Skip to main content

cimoxide

Python bindings for cimoxide, a Rust toolkit for ENTSO-E CGMES (Common Grid Model Exchange Standard) power system data. This package wraps the Rust decoder and SHACL/SPARQL validator (via PyO3) to give you fast RDF/XML parsing and CGMES conformance validation from Python, with no Rust toolchain required at install time.

Install

pip install cimoxide

Prebuilt wheels are published for common platforms; if none match your environment, pip will need a Rust toolchain and maturin to build from source.

Quick start

import cimoxide

# Parse one or more CGMES RDF/XML files into a single merged dataset.
ds = cimoxide.decode_files([
    "RealGrid_EQ.xml",
    "RealGrid_SSH.xml",
    "RealGrid_TP.xml",
    "RealGrid_SV.xml",
])

len(ds)                       # total number of elements
ds.by_type()                  # {"ACLineSegment": [mrid, ...], ...} — copies the whole index
ds.count_type("ACLineSegment")  # 7561 — O(1), copies nothing
ds.get_type("ACLineSegment")  # [{"_type": "ACLineSegment", "ACLineSegment.r": "0.12", ...}, ...]

for mrid in ds:
    obj = ds[mrid]             # dict, e.g. {"_type": "BusbarSection", "IdentifiedObject.name": "...", ...}

Each element is a plain Python dict with "_type" (the CIM class name) and "id" (the mRID), plus one key per attribute the XML carried, named "Class.attr" as in the XML. Every value is the string the XML wrote — numbers are not parsed — and a reference is the referenced mRID; an attribute written more than once is a list of strings.

Modify and re-encode

CimDataset supports dict-style assignment and deletion, so you can edit elements in place and write the result back out as CGMES profile XML:

# Edit an existing element (read, mutate the dict, assign it back).
line = ds["ACLineSegment.1"]
line["ACLineSegment.r"] = "0.15"
ds["ACLineSegment.1"] = line

# Add a brand-new element the same way — the "_type" key selects the CIM class, which
# also says which keys are references.
ds["BaseVoltage.NEW"] = {"_type": "BaseVoltage", "id": "BaseVoltage.NEW", "BaseVoltage.nominalVoltage": "110"}

# Remove one.
del ds["ACLineSegment.2"]

# Encode a single profile as an RDF/XML string.
eq_xml = ds.to_xml_for_profile("EQ")

# Or write a full profile set straight to a directory: dir/EQ.xml, dir/SSH.xml, ...
ds.write_xml_files("out/", ["EQ", "SSH", "TP", "SV"])

to_xml_for_profile/write_xml_files only emit elements and fields whose CIM schema origin includes the requested profile. If the dataset still has the decoded FullModel header for that profile (from the original source file), it's reused verbatim (scenarioTime, modelingAuthoritySet, version, DependentOn, ...); otherwise a minimal header is synthesized.

Validation

violations = cimoxide.validate_files(
    ["RealGrid_EQ.xml", "RealGrid_SSH.xml"],
    profiles=["EQ", "SSH"],   # optional; auto-detected if omitted
)

for v in violations:
    print(v.severity, v.rule_id, v.message, v.object_id)

validate_files runs two-phase validation: per-profile SHACL/SPARQL checks against each file individually, then cross-profile checks on the merged dataset. See the validate_files docstring for the full parameter list (solved, common, quality, silence).

API surface

Function / method Description
cimoxide.decode_file(path) Parse a single RDF/XML file.
cimoxide.decode_files(paths) Parse multiple RDF/XML files in parallel (one thread each, GIL released) and merge them.
cimoxide.decode_str(content) Parse RDF/XML from a string.
cimoxide.validate_files(paths, ...) Two-phase SHACL/SPARQL validation, returns list[Violation].
CimDataset.merge(other) Merge another dataset into this one (other becomes empty).
CimDataset[mrid] / .get(mrid) Fetch one element as a dict (KeyError / None if missing).
CimDataset[mrid] = {...} Insert or replace the element at mrid.
del CimDataset[mrid] Remove the element at mrid (KeyError if missing).
CimDataset.mrids() / iter(ds) / len(ds) Enumerate or count MRIDs.
CimDataset.by_type() dict[str, list[mrid]] type index; copies one str per MRID.
CimDataset.count_type(name) Number of elements of one CIM class. O(1), copies nothing.
CimDataset.get_type(name) All element dicts for one CIM class.
CimDataset.entries() All entries as dict[mrid, dict] (deserializes everything).
CimDataset.query(sparql) Run SPARQL 1.1 over the dataset. Builds an RDF graph on first call, then caches it.
CimDataset.drop_sparql_store() Release that cached graph (it roughly doubles resident memory).
CimDataset.to_xml_for_profile(profile) Encode one CGMES profile (e.g. "EQ") as an RDF/XML string.
CimDataset.write_xml_files(dir, profiles) Write one RDF/XML file per profile into dir.

query() materialises the dataset into an in-memory RDF graph the first time it is called and reuses it afterwards, so the first query costs far more than the rest — on a ~150k-element dataset, roughly 1.1 s then ~4 ms. The cache is dropped automatically whenever the dataset is mutated, and drop_sparql_store() releases it explicitly.

Full type stubs with per-method docstrings are in python/cimoxide/__init__.pyi and python/cimoxide/types.pyi (generated TypedDict per CIM class, for editor autocomplete on the returned dicts).

Examples

examples/example_counts.py decodes the RealGrid test configuration and prints an element count per CIM type:

python examples/example_counts.py

examples/example_encode.py decodes RealGrid, encodes it back to EQ/SSH/TP/SV profile files (in a temp directory by default, or the directory given as an argument), then re-decodes the output to confirm the round-trip is lossless:

python examples/example_encode.py [output-dir]

Both require the CGMES-Test-Configurations submodule checked out at the repo root — see "Development" below.

Benchmark

examples/benchmark_realgrid.py times decode_files, write_xml_files, and validate_files against the full RealGrid dataset and reports best/mean wall time plus MB/s throughput for each:

python examples/benchmark_realgrid.py [iterations]   # default: 3

Also requires the CGMES-Test-Configurations submodule.

Tests

The test suite decodes and validates the CGMES fixture files checked into the parent repository's testdata/ directory:

pip install pytest
pytest tests/
  • tests/test_decode.py — round-trip decode tests (decode_file/decode_str/decode_files, indexing, iteration).
  • tests/test_api.py — dataset API contract tests (merge, mutation via __setitem__/__delitem__, error handling).
  • tests/test_encode.py — to_xml_for_profile/write_xml_files behavior, including FullModel header reuse against a real CGMES fixture.
  • tests/test_validate.py — validate_files behavior (profile filtering, silence, quality/common flags, Violation fields).

Development

This package is built from the cimoxide monorepo, where cimoxide-py lives alongside the Rust crates it binds (cimmodel, cimvalidation, cimsparql). To build it from source:

# for ubuntu
git clone --recurse-submodules https://github.com/m-mirz/cimoxide.git
cd cimoxide
python3 -m venv .venv
source .venv/bin/activate
pip3 install maturin
cd cimoxide-py
maturin develop --release   # editable install into the active virtualenv
pip3 install pytest
pytest tests/

See the repository README for the full project layout, the code generator, and the Rust CLI.

License

Apache-2.0

Metadata

Release files for cimoxide 0.5.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cimoxide 0.5.1
File Size Uploaded
cimoxide-0.5.1.tar.gz 1.1 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for cimoxide 0.5.1
File Interpreter ABI Platform
cimoxide-0.5.1-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
cimoxide-0.5.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
cimoxide-0.5.1-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details

Total release size: 14.9 MB

Release files / cimoxide-0.5.1.tar.gz

Download URL cimoxide-0.5.1.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
5a4a3c97a60b8a8ab4731ca5e857969723d9aa8db12a8af28c2bcd175df99454
BLAKE2b-256 checksum
How to use checksums
7b668969e28cbb847d0e06eb96ff8efe3da5c721af302aa23c20f6616c3f1c2e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / cimoxide-0.5.1-cp39-abi3-win_amd64.whl

Download URL cimoxide-0.5.1-cp39-abi3-win_amd64.whl
Size 3.9 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
72fd45c7e0c504aa61db7da929d82e78c76512355b1dc7a256fc3f80e8d32b20
BLAKE2b-256 checksum
How to use checksums
ca62c90dd82fde0ed5a6794aa90e41766b247b713b70e6c56b905fcfd5463c3d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / cimoxide-0.5.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL cimoxide-0.5.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 5.4 MB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
8f6c51a6ff0ed7693b6bb8a79ab40d1e0b2517a5c344e21c1efba33022785a7b
BLAKE2b-256 checksum
How to use checksums
380b2d094f69b0812b8aae47874da34540bdd8aa884b33f818de06f87c2a435a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / cimoxide-0.5.1-cp39-abi3-macosx_11_0_arm64.whl

Download URL cimoxide-0.5.1-cp39-abi3-macosx_11_0_arm64.whl
Size 4.5 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
5aeb875cd34575c42735b47e3dbe5321217d5cccd2b4d11ea8478199dc34b0e4
BLAKE2b-256 checksum
How to use checksums
82729041c5f4880baafc316893676ea753cb735632733d69d70c05d40bd1d18f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.1 This release

4 release files

0.5.0

4 release files

0.4.0

4 release files

0.3.3

4 release files

0.3.2

4 release files

0.3.1

4 release files

0.3.0

4 release files

0.2.0

4 release files

0.1.1

4 release files

0.0.5

4 release files

0.0.4

4 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page