Metadata-Version: 2.5
Name: cimprofiles
Version: 0.1.0a2
Summary: CIM data profiles (Python dataclasses) and the Identity/units object model used by CIMantic Graphs
Project-URL: Homepage, https://github.com/PNNL-CIM-Tools/CIM-Profiles
Project-URL: Repository, https://github.com/PNNL-CIM-Tools/CIM-Profiles
Project-URL: Issues, https://github.com/PNNL-CIM-Tools/CIM-Profiles/issues
Author-email: "A. Anderson" <19935503+AAndersn@users.noreply.github.com>, "C. Allwardt" <3979063+craig8@users.noreply.github.com>
License-Expression: BSD-3-Clause
License-File: LICENSE
Keywords: cgmes,cim,iec-61968,iec-61970,power-systems
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: <4.0,>=3.10
Requires-Dist: pint>=0.24.4
Description-Content-Type: text/markdown

# CIM-Profiles

CIMTool workspaces for the CIM 16–18 profiles, and the `cimprofiles` Python package built from
them. These files originally shipped as part of cim-graph 0.1.x through 0.5.x.

`cimprofiles` ships the CIM profiles as Python dataclasses, together with the object model they
are built on (`Identity`, `CIMUnit`, profile merging). It depends only on `pint`, and it is
released separately from [cim-graph](https://github.com/PNNL-CIM-Tools/CIM-Graph). Profile updates
(new classes from EA tickets, new profiles) therefore don't wait for a cim-graph release.

```bash
pip install cimprofiles
```

```python
import cimprofiles.cim18.cimhub_2026 as cim

line = cim.ACLineSegment(name='line_1')
```

cim-graph 0.6 and later depend on `cimprofiles`. The old `cimgraph.data_profile.*` import paths
still work there, with a `DeprecationWarning`.

## Repository layout

| Path | Contents |
|---|---|
| `cim17v40/`, `cim18v15/` | CIMTool workspaces. The Sparx EA `.eap` models are stored with Git LFS. |
| `CIMTool_plugin/` | The cimantic-graphs XSLT builders and their documentation |
| `src/cimprofiles/` | The Python package, with profiles grouped by CIM version (`cim16/`, `cim17/`, `cim18/`). See [`src/cimprofiles/README.md`](src/cimprofiles/README.md) for the available profiles and how merging works. |
| `scripts/import_cimtool_output.sh` | Copies a profile generated by CIMTool into `src/cimprofiles/` and rewrites its imports |
| `tests/` | Tests for `Identity`, UUIDs, merging and the generated profiles |

## Seeded UUIDs

Deterministic identifiers are what downstream converters (ArcGIS, OpenDSS, ...) rely on to give
the same equipment the same RDF ID on every run. `Identity.identifier` is a UUID (CIM 18):
either the one given, or a deterministic construct. There are two cases.

**Read from a file:** the `rdf:ID`/`rdf:about` *is* the UUID, in any serialization
(`urn:uuid:…`, `#_…`, `_…`, any case). The name is not used. An identifier that is not a UUID is
replaced, with a warning, by the UUID seeded from it (below), so reading the same file again
gives the same UUIDs. The original string is kept as the mRID, unless the file has an mRID.
Readers key their graphs with `cimprofiles.identity.read_identifier`, which gives the same UUID.

**Built** (converters, notebooks): a new object, deterministic only for the same model
authority, model, class, mRID and name. A renamed object (bus 300 to bus 301) is a different
object and gets a different UUID. A UUID given as the mRID is used directly.

The seeded UUID is version 5 (RFC 9562 §5.5):

```python
namespace = uuid5(NAMESPACE_URL, model_authority)
uuid = uuid5(namespace, f'{model_name}+{ClassName}+{mRID}+{name}+{seed}')
```

- `model_authority` is a URI (`CIMG_MODEL_AUTHORITY`, default
  `https://github.com/PNNL-CIM-Tools/CIM-Graph`), as in `md:Model.modelingAuthoritySet`. The
  namespace is also the identifier of the `cim:ModelAuthority` object cim-graph writes in file
  headers, so each authority's UUIDs live in its own namespace.
- `model_name` comes from `CIMG_MODEL_NAME` (default empty).
- `mRID` is the object's mRID, or the non-UUID `rdf:ID`/`rdf:about` of an object read from a
  file. It is normalized so every serialization of one object agrees: surrounding whitespace, a
  `urn:uuid:` prefix, everything up to the last `#` and one leading `_` are removed.
  `rdf:ID="_LINE1"`, `rdf:about="#_LINE1"` and `mRID="LINE1"` give the same UUID. Case is kept.
- `name` (whitespace-trimmed) and `seed` (passed to `obj.uuid(seed=...)`) are optional.
- Every component keeps its position even when empty, and `%` and `+` inside a component are
  escaped as `%25` and `%2B`, so two different inputs never produce the same string.
- No identifying input at all (or only empty/blank values) gives a random version 4 UUID.

`obj.uri()` returns the bare UUID: lowercase, or uppercase if it was read uppercase (CIMHub and
GridAPPS-D data), so writing a file back reproduces its identifiers. Underscores and
`urn:uuid:` prefixes belong to the serialization style and are added by cim-graph's writers
and queries (`CIMG_IEC61970_552`: `552-NEW`, `552-LEGACY` or `CGMES`).

`cimprofiles.identity.seeded_uuid` and `model_authority_namespace` implement the seeded UUID, and any
language with a UUID library can reproduce it from this description.

## Updating a profile

1. Regenerate it in CIMTool with the cimantic-graphs builders (`CIMTool_plugin/builder.md`).
2. Import it. This rewrites the `cimgraph.data_profile` imports emitted by CIMTool before 2.3.1:
   ```bash
   scripts/import_cimtool_output.sh cim17 <Profiles/name.py> <Profiles/name.__init__.py>
   ```
   The first argument is the CIM version directory. A fourth argument names the package
   directory when it differs from the envelope name (`gridappsd_rc4_2021` for `rc4_2021`).
3. Check for duplicate field definitions, and rebuild the pre-baked merged profiles if it is one
   of their parts:
   ```bash
   uv run python -m cimprofiles.dedupe_profile_fields --check
   uv run python -m cimprofiles.build_merged_profiles
   ```
4. Run the tests: `uv run pytest`.

## Development

```bash
uv sync
uv run pytest
```

## License

BSD 3-Clause. See [LICENSE](LICENSE).
