Metadata-Version: 2.4
Name: LazyCIM
Version: 0.1.4
Summary: LazyCIM is a Python library for querying, navigating, and editing CIM/CGMES models using a dynamic, ontology-driven API. Think SQLAlchemy for power system knowledge graphs.
Author: Louis Pauchet, Hallvar Haugdal
Author-email: Louis Pauchet <louis.pauchet@sintef.no>, Hallvar Haugdal <hallvar.haugdal@sintef.no>
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering
Requires-Dist: loguru>=0.7.3
Requires-Dist: pandas>=2.0
Requires-Dist: pydantic>=2.0
Requires-Dist: rdflib>=7.0
Requires-Dist: ipykernel>=7.3.0 ; extra == 'dev'
Requires-Dist: jupyter>=1.1.1 ; extra == 'dev'
Requires-Dist: dotenv>=0.9.9 ; extra == 'dev'
Requires-Dist: lazycim[tests] ; extra == 'dev'
Requires-Dist: lazycim[kgraphpy] ; extra == 'dev'
Requires-Dist: lazycim[validation] ; extra == 'dev'
Requires-Dist: lazycim[lint] ; extra == 'dev'
Requires-Dist: lazycim[docs] ; extra == 'dev'
Requires-Dist: mkdocs-material>=9.5 ; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.27 ; extra == 'docs'
Requires-Dist: requests>=2.31.0 ; extra == 'graphdb'
Requires-Dist: kgraphpy ; extra == 'kgraphpy'
Requires-Dist: ruff==0.16.9 ; extra == 'lint'
Requires-Dist: mutmut==3.8.0 ; extra == 'mutation'
Requires-Dist: pytest>=8.3.0 ; extra == 'tests'
Requires-Dist: pytest-cov>=6.0.0 ; extra == 'tests'
Requires-Dist: requests-mock>=1.12.0 ; extra == 'tests'
Requires-Dist: lazycim[graphdb] ; extra == 'tests'
Requires-Dist: kgverifypy ; extra == 'validation'
Requires-Python: >=3.12
Project-URL: Homepage, https://github.com/p-swamp/LazyCIM
Project-URL: Repository, https://github.com/p-swamp/LazyCIM
Project-URL: Issues, https://github.com/p-swamp/LazyCIM/issues
Project-URL: Documentation, https://p-swamp.github.io/LazyCIM/
Provides-Extra: dev
Provides-Extra: docs
Provides-Extra: graphdb
Provides-Extra: kgraphpy
Provides-Extra: lint
Provides-Extra: mutation
Provides-Extra: tests
Provides-Extra: validation
Description-Content-Type: text/markdown

# LazyCIM

[![Docs](https://github.com/p-swamp/LazyCIM/actions/workflows/docs.yml/badge.svg)](https://p-swamp.github.io/LazyCIM) [![CI](https://github.com/p-swamp/LazyCIM/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/p-swamp/LazyCIM/actions/workflows/ci.yml)

**LazyCIM is a Python library for querying, navigating, and editing CIM/CGMES models as native Python objects. Think SQLAlchemy for CIM knowledge graphs.**

Built on top of RDF knowledge graphs, LazyCIM provides a modern, ontology-driven API that lets users work with power system models without writing SPARQL or generating Python classes from CIM schemas.

## Features

- 🔍 Expressive query API
- 🧠 Dynamic CIM classes discovered from the ontology in Pydantic Models
- ⚡ Lazy loading of objects and relationships
- 📊 Direct export to pandas DataFrames
- ✏️ Creation and modification of CIM objects
- 🔄 Change tracking and commits
- 📤 Write back to the original CGMES profile files, changing only the edited lines
- 🌐 Multiple backends with SPARQL support (RDFLib, GraphDB, ...)

## Install

```bash
pip install LazyCIM
```

## Try it

`lazycim.demo` ships four ready-made models, so there is nothing to set up.
The Nordic44 grid model, ENTSO-E's MicroGrid test model and ReliCapGrid's
Svedala — a grid with its Network Code datasets — are downloaded on first use;
`load_toy()` needs no network at all. For a guided tour of a grid and its
Network Codes, open [`examples/Svedala Grid.ipynb`](examples/Svedala%20Grid.ipynb).

```python
from lazycim import F, L
from lazycim.demo import load_nordic44

repo = load_nordic44()

assert repo.query(L.ACLineSegments).count() == 68
assert repo.query(L.Substations).count() == 44
```

Query CIM objects using Python expressions:

```python
lines = (
    repo.query(L.ACLineSegments)
    .where(F.name.contains("ARENDAL") & (F.normallyInService == True))
    .all()
)

assert len(lines) == 3
```

Nordic44 has four ARENDAL lines, but one carries no `normallyInService` value
at all. CGMES models are routinely partial like this, and a filter matches only
what is actually stated.

Navigate the model naturally. Relationships resolve only when you touch them:

```python
line = repo.query(L.ACLineSegments).where(F.name.contains("ARENDAL")).first()

for terminal in line.Terminals:
    print(terminal.ConnectivityNode.name)

assert len(line.Terminals) == 2
```

Export results directly to pandas:

```python
df = repo.query(L.ACLineSegments).to_dataframe(
    line_name=F.name,
    line_terminal1=F.Terminals[0].mRID,
    line_terminal2=F.Terminals[1].mRID,
    line_terminals=F.Terminals,
)
df["line_terminals"] = df["line_terminals"].apply(len)

assert len(df) == 68
assert set(df["line_terminals"]) == {2}
```

Create and edit CIM objects, then commit:

```python
analog = repo.L.Analog(name="PMU_ARENDAL_CurrentMagnitude")

substation = repo.query(L.Substations).where(F.name == "ARENDAL").first()
substation.name = "ARENDAL (renamed)"

assert repo.status().has_changes
repo.commit()

assert repo.query(L.Analogs).count() == 1
```

## Documentation

The full documentation covers a guided tour of the API, a technical account of
how the laziness, schema discovery and query compilation work, and a generated
API reference. It is available at [p-swamp.github.io/LazyCIM](https://p-swamp.github.io/LazyCIM)

## Philosophy

LazyCIM is designed around a simple idea:

> Work with CIM models as objects, not RDF triples.

The library uses the CIM ontology to discover classes and relationships dynamically, allowing it to adapt to different CIM and CGMES profiles without code generation.

## Development

This library was developed for the **p-SWAMP** project under the **Linux Foundation Energy** umbrella and is funded by **Statnett** and supported by the community.

Contributions are welcome. To contribute, please:

- Open a Pull Request (PR)
- Include appropriate tests for any new feature or bug fix
- Ensure that existing tests pass

Every example above is executed by the test suite (`uv run pytest -m docs`), so
they cannot drift from the code.

All contributors are expected to follow the Linux Foundation Code of Conduct:

- https://lfprojects.org/policies/code-of-conduct/

<p align="center">
<img
src="https://lfenergy.org/wp-content/uploads/sites/5/2025/12/pswamp-horizontal-color.png"
alt="p-SWAMP"
width="500"
/>
</p>
