Metadata-Version: 2.4
Name: battinfo
Version: 0.8.0rc2
Summary: Implementation and interoperability layer for the domain-battery ontology.
Author: Simon Clark, Jesper Friis, Francesca Lønstad Bleken, Casper Welzel Andersen, Eibar Flores, Hendrik Snijder, Simon Stier, Corsin Battaglia
Maintainer-email: Simon Clark <j.simon.clark@gmail.com>
License-Expression: Apache-2.0 AND CC-BY-4.0 AND MIT
Project-URL: Homepage, https://battinfo.org
Project-URL: Repository, https://github.com/BIG-MAP/BattINFO
Project-URL: Documentation, https://big-map.github.io/BattINFO/
Project-URL: Issues, https://github.com/BIG-MAP/BattINFO/issues
Project-URL: Changelog, https://github.com/BIG-MAP/BattINFO/blob/v0.8.0/CHANGELOG.md
Keywords: batteries,ontology,EMMO,linked data,JSON-LD,FAIR data,semantic web
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: pydantic>=2.11
Requires-Dist: typer>=0.27.0
Requires-Dist: rich>=13.8
Requires-Dist: jsonschema>=4.21
Requires-Dist: rdflib>=7.6
Requires-Dist: pyshacl>=0.40.1
Requires-Dist: pyld>=3.1.0
Requires-Dist: pyyaml>=6.0.1
Provides-Extra: tabular
Requires-Dist: pandas>=3.0.5; extra == "tabular"
Requires-Dist: pyarrow>=25.0.0; extra == "tabular"
Requires-Dist: openpyxl>=3.1; extra == "tabular"
Provides-Extra: publish
Requires-Dist: rocrate>=0.15.1; extra == "publish"
Provides-Extra: storage
Requires-Dist: boto3>=1.43.57; extra == "storage"
Provides-Extra: processing
Requires-Dist: batterydf[excel,mat,nda]<0.3,>=0.2.0rc2; extra == "processing"
Requires-Dist: matplotlib>=3.11.1; extra == "processing"
Requires-Dist: plotly>=6.9.0; extra == "processing"
Provides-Extra: dev
Requires-Dist: battinfo[tabular]; extra == "dev"
Requires-Dist: battinfo[publish]; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: setuptools>=83.0.0; extra == "dev"
Requires-Dist: wheel; extra == "dev"
Requires-Dist: twine>=7.0.0; extra == "dev"
Requires-Dist: datamodel-code-generator>=0.71.0; extra == "dev"
Requires-Dist: linkml>=1.8; extra == "dev"
Requires-Dist: nbformat>=5.9; extra == "dev"
Requires-Dist: nbmake>=1.5; extra == "dev"
Requires-Dist: ipykernel>=6.29; extra == "dev"
Requires-Dist: ruff>=0.16.0; extra == "dev"
Requires-Dist: pytest>=9.1.1; extra == "dev"
Requires-Dist: pytest-cov>=5.0; extra == "dev"
Requires-Dist: pytest-timeout>=2.3; extra == "dev"
Requires-Dist: pytest-socket>=0.7; extra == "dev"
Requires-Dist: mypy>=2.3.0; extra == "dev"
Provides-Extra: docs
Requires-Dist: autodoc-pydantic>=2.2; extra == "docs"
Requires-Dist: sphinx-copybutton>=0.5; extra == "docs"
Requires-Dist: sphinx>=7.3; extra == "docs"
Requires-Dist: pydata-sphinx-theme>=0.20.0; extra == "docs"
Requires-Dist: myst-parser>=3.0; extra == "docs"
Requires-Dist: nbsphinx>=0.9; extra == "docs"
Requires-Dist: ipython>=9.15.0; extra == "docs"
Requires-Dist: sphinx-design>=0.6; extra == "docs"
Dynamic: license-file

<div align="center">

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/BIG-MAP/BattINFO/main/brand/assets/logo/logo-horizontal-on-dark.svg">
  <img alt="BattINFO" src="https://raw.githubusercontent.com/BIG-MAP/BattINFO/main/brand/assets/logo/logo-horizontal.svg" width="420">
</picture>

### The semantic data layer for battery technology

Create, validate, and publish battery metadata as machine-readable Linked Data —
typed against [EMMO domain-battery](https://github.com/emmo-repo/domain-battery)
and resolvable through persistent `https://w3id.org/battinfo/` identifiers.

<!-- Badges · status -->
[![CI](https://github.com/BIG-MAP/BattINFO/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/BIG-MAP/BattINFO/actions/workflows/ci.yml)
[![Python](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2FBIG-MAP%2FBattINFO%2Fmain%2Fpyproject.toml&logo=python&logoColor=white)](https://github.com/BIG-MAP/BattINFO/blob/main/pyproject.toml)
[![License: Apache 2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/BIG-MAP/BattINFO/blob/main/LICENSE)
<br/>
<!-- Badges · activity & quality -->
[![Contributors](https://img.shields.io/github/contributors/BIG-MAP/BattINFO?color=informational)](https://github.com/BIG-MAP/BattINFO/graphs/contributors)
[![Last commit](https://img.shields.io/github/last-commit/BIG-MAP/BattINFO/main)](https://github.com/BIG-MAP/BattINFO/commits/main)
[![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-261230.svg)](https://github.com/astral-sh/ruff)
[![Typed](https://img.shields.io/badge/typing-mypy-2A6DB2.svg)](http://mypy-lang.org/)
<br/>
<!-- Badges · domain alignment -->
[![Ontology: EMMO domain-battery](https://img.shields.io/badge/ontology-EMMO%20domain--battery-6E4C9F.svg)](https://github.com/emmo-repo/domain-battery)
<br/>
<!-- Badges · learn & cite -->
[![nbviewer](https://img.shields.io/badge/render-nbviewer-F37726?logo=jupyter&logoColor=white)](https://nbviewer.org/github/BIG-MAP/BattINFO/tree/main/docs/guides/)
<!-- DOI: the Zenodo concept DOI; it resolves to the latest archived release -->
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6304782.svg)](https://doi.org/10.5281/zenodo.6304782)

[**Quickstart**](https://github.com/BIG-MAP/BattINFO/blob/main/QUICKSTART.md) ·
[**Documentation**](https://github.com/BIG-MAP/BattINFO/blob/main/docs/index.md) ·
[**How-to guides**](https://github.com/BIG-MAP/BattINFO/blob/main/docs/pages/howto.md) ·
[**Tutorials**](#tutorials) ·
[**Contributing**](#contributing) ·
[**Cite**](#citation)

New words? The [plain-language glossary](https://github.com/BIG-MAP/BattINFO/blob/main/docs/pages/glossary.md) decodes
*Linked Data*, *EMMO*, *IRI*, and friends in two sentences each.

</div>

---

BattINFO provides a Python library, a CLI, and a canonical asset suite — JSON
Schemas, ontology mappings, profiles, and examples — that make it straightforward
to describe batteries as **valid, machine-readable Linked Data**.

Every record gets a persistent `https://w3id.org/battinfo/` IRI. The JSON-LD that BattINFO writes for a record (`battinfo.record_to_jsonld`), for a workspace's saved cell specs, cells, test specs, tests and datasets (`ws.export`) and for a Zenodo deposit is valid RDF, typed against EMMO domain-battery and ready to query with SPARQL. What a record's IRI serves from the registry is not yet that model; the [known limitations](https://github.com/BIG-MAP/BattINFO/blob/main/docs/scope.md#known-limitations-in-080) say what it serves instead.

## Table of contents

- [Why BattINFO](#why-battinfo)
- [Installation](#installation)
- [Quickstart](#quickstart)
- [Tutorials](#tutorials)
- [What BattINFO does](#what-battinfo-does)
- [Semantic foundation](#semantic-foundation)
- [Project status](#project-status)
- [Repository layout](#repository-layout)
- [Core principles](#core-principles)
- [Contributing](#contributing)
- [Citation](#citation)
- [License](#license)

## Why BattINFO

Battery data is fragmented across spreadsheets, vendor datasheets, and ad-hoc
JSON. BattINFO turns that into a single, semantically-grounded record model:

- **Write plain JSON or Python** — get validated, EMMO-aligned JSON-LD.
- **Interoperable by construction** — records share one ontology (EMMO) and one identifier scheme.
- **Provenance built in** — a `CellSpec → Cell → Test → Dataset` chain links every measurement back to the cell that produced it.

## Installation

Supports **Python 3.11–3.14**. 0.8.0 will be the first working release of battinfo on PyPI. Until then, install it from GitHub into a virtual environment:

```bash
python -m venv .venv
source .venv/bin/activate            # Windows: .venv\Scripts\activate
pip install "battinfo @ git+https://github.com/BIG-MAP/BattINFO.git"
```

Optional extras: `battinfo[processing]` (cycler-file conversion via `ws.convert()` + plotting), `battinfo[tabular]` (CSV/Parquet/XLSX readers), `battinfo[publish]` (RO-Crate validation), `battinfo[storage]` (S3), `battinfo[docs]` (Sphinx), and `battinfo[dev]` (full test/lint/build toolchain). To convert raw cycler files, install the converter and the plotting libraries with:

```bash
pip install "battinfo[processing] @ git+https://github.com/BIG-MAP/BattINFO.git"
```

The `processing` extra requires `batterydf[nda,excel,mat]>=0.2.0rc2,<0.3`, so pip installs the batterydf 0.2.0 release candidate until 0.2.0 itself is published.

Working on BattINFO itself? See [Contributing](#contributing).

## Quickstart

```python
from battinfo import CellSpec, publish

result = publish(
    CellSpec(
        manufacturer="Panasonic",
        model="NCR18650B",
        format="cylindrical",
        chemistry="Li-ion",
        nominal_capacity={"value": 3.2, "unit": "Ah"},
    ),
    destination="local",
    root=".battinfo/my-library",
)
print(result.canonical_iri)
# https://w3id.org/battinfo/spec/xxxx-xxxx-xxxx-xxxx
```

That IRI is **permanent, but not yet resolvable on the web** — opening it in a
browser returns 404 for a record published locally. A local publish mints the
identity; it becomes dereferenceable once you publish the record to the
registry (`ws.publish()`, see [Tutorial 6](https://github.com/BIG-MAP/BattINFO/blob/main/docs/guides/06-publish-your-data.ipynb)).

`destination="local"` writes to a `.battinfo/` directory (a dot-directory —
`ls -a` to see it):

```text
.battinfo/my-library/
├── index.json
└── examples/cell-spec/cell-spec-<id>.json   # the canonical record JSON
```

Or from the command line:

```bash
battinfo --help
```

For interactive, multi-record work — cells, tests, datasets, equipment — the
authoring workspace is the blessed surface:

```python
import battinfo
ws = battinfo.workspace(".")
ws.quickstart()   # prints a copy-pasteable end-to-end example
```

**Lab work?** Start at the [how-to guides](https://github.com/BIG-MAP/BattINFO/blob/main/docs/pages/howto.md), where bench tasks such as registering materials, building a cell from components, labelling cells, converting cycler exports and publishing each map to a runnable recipe. The
[capability table](https://github.com/BIG-MAP/BattINFO/blob/main/docs/workspace-authoring.md#what-each-surface-can-author-today)
shows which surface (workspace, `battinfo.api`, CLI) authors which record types today.

**→ Read the [full quickstart](https://github.com/BIG-MAP/BattINFO/blob/main/QUICKSTART.md) and the [documentation index](https://github.com/BIG-MAP/BattINFO/blob/main/docs/index.md).**

## Tutorials

Six tutorial notebooks in [`docs/guides/`](https://github.com/BIG-MAP/BattINFO/tree/main/docs/guides) — one story, from the
record model to a published dataset. Each runs from its own folder and writes
only to a throwaway `_scratch/` directory next to it. The example files they read
ship inside the package, so a pip install is enough to run them (tutorial 6 also
needs the `processing` extra).

| Tutorial | What you'll learn |
|---|---|
| [1 — Concepts](https://github.com/BIG-MAP/BattINFO/blob/main/docs/guides/01-concepts.ipynb) | The record model, IRIs, and the semantic layer |
| [2 — Describing a cell](https://github.com/BIG-MAP/BattINFO/blob/main/docs/guides/02-first-cell-type.ipynb) | Author and publish a cell spec, with a taste of material-level depth |
| [3 — Linked records](https://github.com/BIG-MAP/BattINFO/blob/main/docs/guides/03-linked-records.ipynb) | Cells, test specs, tests, and datasets with the workspace |
| [4 — Semantic layer](https://github.com/BIG-MAP/BattINFO/blob/main/docs/guides/04-semantic-layer.ipynb) | JSON-LD anatomy, EMMO type stacking, RDF and SPARQL |
| [5 — Cell descriptors](https://github.com/BIG-MAP/BattINFO/blob/main/docs/guides/05-descriptors.ipynb) | Research-grade composition: materials, BOMs, electrodes, electrolyte |
| [6 — Publish your first dataset](https://github.com/BIG-MAP/BattINFO/blob/main/docs/guides/06-publish-your-data.ipynb) | End to end: raw cycler CSV → validated records → DOI + registry |

## What BattINFO does

- Validates battery metadata as plain JSON (JSON Schema / Pydantic) **and** as semantic RDF (JSON-LD + URDNA2015 normalisation).
- Maps JSON inputs into domain-battery-aligned JSON-LD using authoritative curated property and unit mappings.
- Provides profiles, examples, and mapping rules for all common battery record types.
- Supports a reusable cell-spec library, curated once as BattINFO descriptors and published as generated RDF/JSON-LD.
- Publishes dataset metadata with a core `CellSpec → Cell → Test → Dataset` provenance chain.

## Semantic foundation

| Layer | What it provides |
|-------|-----------------|
| `battinfo.ttl` | OWL application ontology; imports EMMO domain-battery 0.21.0 and domain-electrochemistry 0.39.0 with pinned versioned IRIs |
| [`assets/mappings/domain-battery/`](https://github.com/BIG-MAP/BattINFO/tree/main/assets/mappings/domain-battery) | 117 curated property→EMMO-IRI mappings and 75 unit→EMMO-IRI mappings; drives JSON→JSON-LD transformation |
| `assets/schemas/` | 25 JSON Schema (draft 2020-12) files: one for each of the 22 record types, plus the shared base, the canonical cell description and the ingest manifest |
| [`src/battinfo/transform/json_to_jsonld.py`](https://github.com/BIG-MAP/BattINFO/blob/main/src/battinfo/transform/json_to_jsonld.py) | Deterministic, mapping-table-driven transformation to EMMO-aligned JSON-LD using the canonical domain-battery context |
| [`src/battinfo/validate/`](https://github.com/BIG-MAP/BattINFO/tree/main/src/battinfo/validate) | Multi-layer validation: JSON Schema, Pydantic, JSON-LD (URDNA2015), semantic rules, referential integrity, publication |

The JSON-LD that `record_to_jsonld`, `ws.export` and the Zenodo deposit graph write uses:

- `hasProperty` → `[ClassName, ConventionalProperty]` → `hasNumericalPart` → `hasNumberValue` (canonical EMMO quantity pattern) for cell specs, cells, tests, datasets, materials and components; some test-protocol and parameter-set values do not follow it yet (see the [known limitations](https://github.com/BIG-MAP/BattINFO/blob/main/docs/scope.md#known-limitations-in-080))
- `hasMeasurementUnit` → full EMMO or QUDT IRI (never a bare string)
- `@type` stacking: the cell that a cylindrical LFP cell spec describes is a `BatteryCell`, a `CylindricalBattery`, a `LithiumIonBattery` and a `LithiumIonIronPhosphateBattery`, taken from its format, chemistry and `positive_electrode_basis`. `LithiumIonGraphiteBattery` is added only when `negative_electrode_basis` is graphite.

## Project status

> **Beta.** The test suite (more than 5,000 tests at the 0.8.0 release) runs in CI on Python 3.11–3.14, on Linux and Windows. Ontology dependency versions are pinned and verified. See [`docs/scope.md`](https://github.com/BIG-MAP/BattINFO/blob/main/docs/scope.md) for the full capability map and the [known limitations](https://github.com/BIG-MAP/BattINFO/blob/main/docs/scope.md#known-limitations-in-080) of this release.

**Supported**
- Cell-descriptor validation and mapping, canonical record query/save/publish/index flows, JSON-LD-first publication, and validation policies.
- CLI and Python API covering `cell-spec`, `cell-instance`, `test`, `dataset`, and `test-protocol` records.

**Preview (may still change)**
- Reusable cell-spec library flows beyond the walkthrough fixtures.

**In development (no stability promise)**
- The folder-based batch path: `battinfo push` processes a folder of raw cycler files, packages it and uploads it to the Zenodo sandbox, and `battinfo batch` runs the same steps one at a time. To publish on zenodo.org, use `ws.zenodo()`.
- `battinfo dataset` is experimental: its init, process and publish flow cannot complete in 0.8.0, so publish a dataset with `ws.zenodo()` instead.
- Registry administration (`battinfo registry bootstrap`).
- Large-scale reference validation.

## Repository layout

| Path | Contents |
|------|----------|
| `battinfo.ttl` | OWL application ontology |
| [`assets/`](https://github.com/BIG-MAP/BattINFO/tree/main/assets) | Canonical schemas and mapping assets |
| [`examples/`](https://github.com/BIG-MAP/BattINFO/tree/main/examples) | Canonical example records and guide notebooks |
| [`src/battinfo/`](https://github.com/BIG-MAP/BattINFO/tree/main/src/battinfo) | Python package and CLI |
| [`docs/`](https://github.com/BIG-MAP/BattINFO/tree/main/docs) | Adoption and usage documentation |
| `.tools/` | Maintainer tooling: `build/`, `datasheets/`, `library/`, `quality/`, `semantic/` |
| [`tests/`](https://github.com/BIG-MAP/BattINFO/tree/main/tests) | Regression and contract tests |

## Core principles

- **Domain-battery is the normative ontology** (semantics and terms). BattINFO is non-normative and operational (schemas, mappings, tooling).
- **The JSON Schema is the save-time contract**, and the pydantic models in `bundle.py` are the hand-written authoring surface. `tests/test_schema_model_parity.py` checks that every schema property can be reached from the models, apart from a listed set of known gaps, and [AGENTS.md](https://github.com/BIG-MAP/BattINFO/blob/main/AGENTS.md#sources-of-truth-and-generated-files) lists which files are generated and how.
- **JSON-LD-first publication**: `record_to_jsonld`, `ws.export` and the Zenodo deposit graph write valid RDF aligned to domain-battery.
- **Stable, opaque identifiers**: all published entities carry a `https://w3id.org/battinfo/{type}/{uid}` IRI, governed by [`IDENTIFIER_POLICY.md`](https://github.com/BIG-MAP/BattINFO/blob/main/IDENTIFIER_POLICY.md).
- BattINFO does not host or modify the domain-battery ontology.

## Contributing

Contributions are welcome. Please open an issue to discuss substantial changes
before submitting a pull request, and make sure the full quality gate passes:

```bash
uv sync --all-extras
uv run ruff check src tests
uv run mypy
uv run pytest -q tests
```

A shorter acceptance gate runs the acceptance tests, a smoke test of the installed package and a wheel build. It is part of the repository, not of the installed package, so run it from a checkout:

```bash
uv run python .tools/quality/run_verification.py
```

CI runs the same checks across Python 3.11–3.14 on Linux and Windows via the [CI](https://github.com/BIG-MAP/BattINFO/blob/main/.github/workflows/ci.yml) workflow, alongside [Security](https://github.com/BIG-MAP/BattINFO/blob/main/.github/workflows/security.yml) (pip-audit + CodeQL) and [Docs](https://github.com/BIG-MAP/BattINFO/blob/main/.github/workflows/docs.yml) builds.

## Citation

If you use BattINFO in your research, please cite it. The concept DOI
[10.5281/zenodo.6304782](https://doi.org/10.5281/zenodo.6304782) always resolves to the latest archived release;
each release also gets its own version DOI on Zenodo.

```bibtex
@software{battinfo,
  title        = {BattINFO: The semantic data layer for battery technology},
  author       = {Clark, Simon and Friis, Jesper and L{\o}nstad Bleken, Francesca and Andersen, Casper Welzel and Flores, Eibar and Snijder, Hendrik and Stier, Simon and Battaglia, Corsin},
  year         = {2026},
  publisher    = {Zenodo},
  doi          = {10.5281/zenodo.6304782},
  url          = {https://github.com/BIG-MAP/BattINFO}
}
```

> **Maintainers:** publishing a GitHub Release archives it on Zenodo as a new
> version under this concept DOI. Zenodo takes the metadata, including the
> author list, from `CITATION.cff`.

## License

Distributed under the **Apache License 2.0**. See [`LICENSE`](https://github.com/BIG-MAP/BattINFO/blob/main/LICENSE). The package also includes EMMO-derived context files and labels under CC BY 4.0 and five BPX example parameter sets under MIT; [`NOTICE`](https://github.com/BIG-MAP/BattINFO/blob/main/NOTICE) says which files they are.

## Acknowledgements

Built on the [EMMO](https://github.com/emmo-repo) ontology suite — in particular
[domain-battery](https://github.com/emmo-repo/domain-battery) and
domain-electrochemistry — and informed by the
[Battery Pass](https://thebatterypass.eu/) data content guidance.
