Python API#

orphan:

True

How the Python surface is organized — the generated symbol-by-symbol reference follows below; for the layered architecture, see How BattINFO is built.

Where to start#

Goal

Surface to use

Turn lab data into published, linked records

battinfo.workspace(...) — the one object for the whole journey

Describe a battery product (a datasheet as data)

The CellSpec record class + the publish shortcut

Author research-grade composition (materials, electrodes, electrolyte)

battinfo.authoring — see Tutorial 5

Load, query, save, or resolver-publish canonical records

battinfo.api helpers

Turn a folder of photos and CSVs into a linked submission

battinfo.ingest — one-command folder intake

Drive everything from the shell

The battinfo CLI — see the CLI reference

If you are new here, start with the tutorials — six notebooks that walk the whole story end to end.

The curated top-level namespace (import battinfo) exposes the record classes, the workspace, publishing, and validation — everything else lives in its home module (battinfo.api, battinfo.authoring, battinfo.materials, …) and is documented there.

The workspace#

battinfo.workspace(root) is the data-first surface: convert raw cycler files, register cells, link tests and data, save validated records with stable IRIs, and publish — to the registry review queue and, with zenodo=True, to a citable DOI.

import battinfo

ws = battinfo.workspace(".")

ws.convert()                              # raw cycler files → tidy BDF tables
spec = ws.search("samsung inr21700 50e")[0]   # reuse the registry's identity
ws.add("cell", spec=spec, serial_numbers=["S1", "S2"])
ws.add("test", type="cycling", cell="S1", data="bdf/S1.bdf.csv")
ws.save()
ws.publish(note="My cycling campaign, 2026")

ws.quickstart() prints the full recipe, including login and funding attribution (ws.project(...), ws.contributor(...)). Tutorial 3 builds the chain step by step; Tutorial 6 runs it from a raw cycler export.

Drafts and templates: ws.template("cell-spec", ...) / ws.template("test-spec", ...) write skeleton draft files; ws.load(path) authors them into the session. ws.load(ws.search(...)[0]) references an existing registry record instead (reused, never re-published).

Record classes#

CellSpec, Cell, TestSpec, Test, and Dataset are the record types as pydantic classes — the single source of truth for authoring and for what is on disk. For a standalone cell-spec record, publish is the shortcut:

from battinfo import CellSpec, publish

cell_spec = CellSpec(
    manufacturer="Google",
    model="G20M7",
    format="pouch",
    chemistry="Li-ion",
)

local_result = publish(cell_spec, destination="local")
registry_result = publish(
    cell_spec,
    destination="registry",
    registry_base_url="https://registry.example.org",
    api_key="...",
    workspace_id="hello-world",
    publisher_id="demo-lab",
)
  • destination="local" writes the canonical BattINFO record and returns its path in debug_paths.

  • destination="registry" also generates the submission package and submits it to battinfo-registry.

  • destination="battery-genome" additionally returns the expected Battery Genome page URL when platform_base_url is configured.

Publication package (record-classes path)#

When you hold the four core record objects in Python and want the local publication artifacts without a workspace, build the package directly:

from pathlib import Path

from battinfo import Cell, CellSpec, Dataset, Test, build_publication_package, load_publication_package

dataset_dir = Path("data/cr2032-run")
dataset_dir.mkdir(parents=True, exist_ok=True)
(dataset_dir / "capacity.csv").write_text("cycle,capacity_ah\n1,0.225\n")

cell_spec = CellSpec(manufacturer="Energizer", model="CR2032", format="coin", chemistry="Li-primary")
cell = Cell(cell_spec=cell_spec, serial_number="energizer-cr2032-202602-dtjrga")
test = Test(cell=cell, kind="capacity_check", protocol="constant current discharging", status="completed")
dataset = Dataset(path=str(dataset_dir), cell=cell, test=test, name="Energizer CR2032 dataset")

report = build_publication_package(
    cell_spec=cell_spec, cell_instance=cell, test=test, dataset=dataset,
)
bundle = load_publication_package(dataset_dir / "battinfo.publish.jsonld")

Notes:

  • battinfo.publish.jsonld is the foundational Schema.org JSON-LD artifact.

  • ro-crate-metadata.json and datacite-metadata.json are emitted alongside it.

  • battinfo.dcat.jsonld is available as an optional export.

Query and save (battinfo.api)#

Canonical-record helpers for scripted workflows:

from battinfo import query_cell_specs, save_cell_instance
from battinfo.api import template_cell_instance

rows = query_cell_specs(manufacturer="A123", chemistry="LFP", limit=5)

draft = template_cell_instance(cell_spec_id="https://w3id.org/battinfo/spec/3m6k-9t2p-7x4h-9nq8")
draft["cell_instance"]["serial_number"] = "LAB-001"

result = save_cell_instance(draft, source_root="examples", resolve_references=False)

Draft inputs omit canonical fields like id, short_id, and identifier — saving canonizes them and fills default provenance.

Index and resolver publishing (battinfo.api)#

from battinfo.api import build_index, index_stats, publish_record

publish_record(
    "examples/cell-instance/cell-3m6k-9t2p-7x4h-9nq8.json",
    target_root=".battinfo/resolver-site",
)

index = build_index(source_root="examples", out_path=".battinfo/index.json")
stats = index_stats(".battinfo/index.json")

Ingest-first intake (battinfo.ingest)#

One-command registration for a typed resource instance plus its evidence files (photos become photo datasets; CSVs become a Test plus a Dataset):

from battinfo.ingest import build_ingest_workspace, publish_ingest_workspace, write_ingest_manifest

The folder-local battinfo.ingest.json manifest carries stable ingest metadata; its shape is defined by the ingest manifest contract and validated against assets/schemas/ingest-manifest.schema.json. resource_type="cell-instance" is the currently implemented subject.

Advanced: the internal engine#

battinfo.workspace(...) and the record classes are facades over an internal authoring engine (battinfo._workspace.Workspace) that also powers submission-package export and release workflows. New code should not build on the engine directly — its surface is large, uncurated, and free to change; everything the tutorials and this page show goes through the stable facades. If you maintain older code that imports Workspace from battinfo, you will see a deprecation message pointing at the replacement for each call.

Guidance#

  • Prefer battinfo.workspace(...) for anything that ends in publishing.

  • Prefer opaque BattINFO IRIs under https://w3id.org/battinfo/.

  • For validation policy and machine-readable issue output, see the validation contract.

  • For submission-envelope internals, see the contract explanation page.

Generated reference#

Everything below is generated from the source docstrings and field descriptions — it cannot drift from the code. The authoring workspace has its own page at Workspace authoring.

The record classes#

The five record classes are both the canonical source of truth and the authoring input: construct them with the flat field names you know from the datasheet and hand them to publish or the matching save_* function. Every field is documented below; quantity keys and unit symbols are enumerated in Property & unit reference.

pydantic model battinfo.CellSpec#
Fields:
  • bibliography (dict[str, Any])

  • cell_specification_id (str | None)

  • chemistry (str)

  • comment (list[str])

  • construction (dict[str, Any])

  • country_of_origin (str | None)

  • datasheet_revision (str | None)

  • electrolyte (battinfo.bundle.Electrolyte | None)

  • electrolyte_spec_id (str | None)

  • format (str)

  • housing (battinfo.bundle.Housing | None)

  • housing_spec_id (str | None)

  • id (str | None)

  • iec_code (str | None)

  • kind (str)

  • manufacturer (str)

  • manufacturer_id (str | None)

  • model (str)

  • name (str | None)

  • negative_electrode (battinfo.bundle.Electrode | None)

  • negative_electrode_basis (str | None)

  • negative_electrode_spec_id (str | None)

  • positive_electrode (battinfo.bundle.Electrode | None)

  • positive_electrode_basis (str | None)

  • positive_electrode_spec_id (str | None)

  • product_type (battinfo.bundle.CellProductType | None)

  • properties (dict[str, Any])

  • rechargeable (bool | None)

  • separator (battinfo.bundle.Separator | None)

  • separator_spec_id (str | None)

  • size_code (str | None)

  • source (battinfo.bundle.ProvenanceInfo)

  • specification_comment (list[str])

  • uid (str | None)

  • year (int | None)

pydantic model battinfo.Cell#
Fields:
  • batch_id (str | None)

  • cell_spec (battinfo.bundle.CellSpec | None)

  • cell_spec_id (str | None)

  • comment (list[str])

  • conformance (battinfo.bundle.Conformance | None)

  • dataset_ids (list[str])

  • expires_at (int | str | None)

  • grade (str | None)

  • id (str | None)

  • kind (str)

  • manufactured_at (int | str | None)

  • measured (dict[str, Any])

  • name (str | None)

  • serial_number (str | None)

  • source (battinfo.bundle.ProvenanceInfo)

  • uid (str | None)

pydantic model battinfo.TestSpec#
Fields:
  • artifacts (list[battinfo.bundle.Artifact])

  • comment (list[str])

  • conditions (dict[str, battinfo.testmethod.Quantity])

  • description (str | None)

  • id (str | None)

  • kind (str)

  • method (list[battinfo.testmethod.Step])

  • name (str | None)

  • protocol (battinfo.bundle.ProtocolInfo)

  • record (dict[str, Any])

  • safety (dict[str, Any])

  • source (battinfo.bundle.ProvenanceInfo)

  • test_type (battinfo.bundle.BatteryTestType)

  • uid (str | None)

  • version (str | None)

pydantic model battinfo.Test#
Fields:
  • artifacts (list[battinfo.bundle.Artifact])

  • cell (battinfo.bundle.Cell | None)

  • cell_instance_id (str | None)

  • channel_id (str | None)

  • comment (list[str])

  • conformance (battinfo.bundle.Conformance | None)

  • dataset_ids (list[str])

  • description (str | None)

  • ended_at (int | str | None)

  • equipment_id (str | None)

  • id (str | None)

  • instrument (str | None)

  • kind (str)

  • name (str | None)

  • protocol (battinfo.bundle.ProtocolInfo)

  • protocol_entity (battinfo.bundle.TestSpec | None)

  • protocol_id (str | None)

  • source (battinfo.bundle.ProvenanceInfo)

  • started_at (int | str | None)

  • status (str | None)

  • test_type (battinfo.bundle.BatteryTestType)

  • uid (str | None)

pydantic model battinfo.Dataset#
Fields:
  • access_url (str | None)

  • additional_type (list[str])

  • cell (battinfo.bundle.Cell | None)

  • cell_instance_id (str | None)

  • checksum (battinfo.bundle.ChecksumInfo)

  • citations (list[dict[str, Any]])

  • comment (list[str])

  • conditions_of_access (str | None)

  • created_at (int | str | None)

  • creators (list[dict[str, Any]])

  • data_format (str | None)

  • dataset_path (str | None)

  • description (str | None)

  • distributions (list[dict[str, Any]])

  • download_url (str | None)

  • funders (list[dict[str, Any]])

  • id (str | None)

  • identifier (Any)

  • in_language (str | None)

  • included_in_data_catalog (str | dict[str, Any] | None)

  • is_accessible_for_free (bool | None)

  • is_based_on (list[str])

  • keywords (list[str])

  • kind (str)

  • license (str | None)

  • main_entity (list[dict[str, Any]])

  • measurement_methods (list[str])

  • measurement_techniques (list[str])

  • modified_at (int | str | None)

  • name (str | None)

  • published_at (int | str | None)

  • publisher (dict[str, Any] | None)

  • related_cell_ids (list[str])

  • related_test_ids (list[str])

  • same_as (list[str])

  • source (battinfo.bundle.ProvenanceInfo)

  • spatial_coverage (str | None)

  • temporal_coverage (str | None)

  • test (battinfo.bundle.Test | None)

  • test_id (str | None)

  • uid (str | None)

  • variable_measured (list[dict[str, Any]])

  • version (str | None)

pydantic model battinfo.ProvenanceInfo#
Fields:
  • battinfo_version (str | None)

  • citation (str | None)

  • comment (str | None)

  • curated_by (str | None)

  • file (str | None)

  • file_hash (str | None)

  • name (str | None)

  • retrieved_at (int | str | None)

  • type (str | None)

  • url (str | None)

  • workflow_version (str | None)

Publish and save#

battinfo.publish(obj: Any = None, destination: str | None = None, **kwargs: Any) PublishResult | dict[str, Any]#

Publish a BattINFO object to a named destination.

The new product surface is publish(obj, destination=…). The legacy publication-package call shape is still accepted for backwards compatibility and delegated to battinfo.publication.publish(…).

battinfo.save_record(record: dict[str, Any] | str | Path, *, source_root: str | Path = PosixPath('examples'), mode: str = 'create_only', duplicate_policy: str = 'error', resolve_references: bool = True, publish: bool = False, publish_root: str | Path = '.battinfo/resolver-site', build_jsonld: bool = True, build_html: bool = True, validate: bool = True, validation_policy: ValidationPolicy | str = ValidationPolicy(name='default', schema='error', references='error', semantic='warn', publication='error'), dry_run: bool = False) dict[str, Any]#

Save one canonical BattINFO resource into local source storage and optional resolver artifacts.

Minting policy: records that arrive without an id/uid are minted deterministically from their natural identity key (see _identity_minted_uid), so re-running an identical ingest lands on the existing records — use mode="upsert" (no-op re-save reports content_changed: False) or duplicate_policy="return_existing" for idempotent pipelines. Records with no distinguishing identity fall back to a random uid and never silently dedup.

battinfo.bulk_save_session(source_root: Path | str) Iterator[RecordLocationCache]#

Speed up a batch of save_* calls against one source root.

Loads the id→path map once (per entity type, lazily) instead of rescanning the source root on every save:

with battinfo.bulk_save_session("examples"):
    for draft in drafts:
        battinfo.save_cell_instance(draft, source_root="examples")

Nested sessions for the same root reuse the outer cache. The session assumes single-writer access to source_root for its duration.

Query and validate#

battinfo.query_cell_specs(*, id: str | None = None, manufacturer: str | None = None, chemistry: str | None = None, format: str | None = None, model_name_contains: str | None = None, nominal_capacity_min: float | None = None, nominal_capacity_max: float | None = None, nominal_voltage_min: float | None = None, nominal_voltage_max: float | None = None, spec_filters: Mapping[str, tuple[float | None, float | None]] | None = None, cell_specs_dir: str | Path = PosixPath('/home/runner/work/BattINFO/BattINFO/src/battinfo/data/examples/cell-spec'), limit: int = 50, offset: int = 0) list[dict[str, Any]]#

Query cell types using practical metadata/property filters.

battinfo.validate_record_report(doc: dict[str, Any], *, source_root: str | Path | None = None, policy: ValidationPolicy | str = ValidationPolicy(name='default', schema='error', references='error', semantic='warn', publication='error')) ValidationReport#
battinfo.record_to_jsonld(record: dict, record_type: str) dict#

Transform a BattINFO plain-JSON record to a JSON-LD document.

Parameters:
  • record – The plain-JSON record dict (as loaded from .battinfo/records/).

  • record_type – One of "cell-spec", "cell-instance", "test", "dataset".

Returns:

  • dict – A JSON-LD document with @context, @id, @type, and semantically typed properties using EMMO/schema.org IRIs.

  • Example:: – import json from battinfo.jsonld import record_to_jsonld

    raw = json.loads(Path(“cell-spec-xyz.json”).read_text()) ld = record_to_jsonld(raw, “cell-spec”) print(json.dumps(ld, indent=2))

The workspace object#

class battinfo.AuthoringWorkspace(root: str | Path = '.', records_repo: str | Path | None = None, registry_url: str | None = None)#

The blessed authoring surface: a simplified workspace for BattINFO records.

Create one with battinfo.workspace() and call quickstart() for a copy-pasteable end-to-end example. Wraps the lower-level object-graph engine battinfo.Workspace (defined in battinfo._workspace) with a concise API designed for interactive / notebook use.

Every method is documented in Workspace authoring; run ws.commands() for the live cheat sheet. (The internal object-graph engine in battinfo._workspace is an implementation detail — the deprecated top-level Workspace name points you back here.)