ontology-config-generator is a single-module library. The only I/O is reading
the extension TTL + starter JSON and writing the output configs; everything else
is pure value objects and a generic graph extraction. The heavy dependency
(rdflib) is imported lazily inside the two functions that touch a graph, so
the module imports — and its non-parsing paths run — on a bare interpreter.
| Module | Responsibility |
|---|---|
ontology_config_generator/generator.py |
Everything: ConfigSpec (a spec-table row), generate_configs() (the deterministic compile + provenance + degrade-open), extract_named() (the generic OWL extractor), _deep_merge() (starter/static + extracted merge), the spec-table loader, and the main() CLI. rdflib is imported lazily inside generate_configs/extract_named. |
ontology_config_generator/__init__.py |
Re-exports the public API (ConfigSpec, generate_configs, extract_named, DEFAULT_NAMESPACE) and __version__. No heavy import at module top. |
ontology_config_generator/__main__.py |
python -m ontology_config_generator → generator.main. |
extension.ttl ──► rdflib.Graph (lazy parse; degrade-open on missing/bad file)
│
spec_table[i] ──────────┤ for each spec:
{filename, │
extract: {key→cls}, ├─ starter_dir/filename JSON ─┐
static} │ ├─► _deep_merge(base, static) = base
│ for each (key → class): │
├─ extract_named(graph, class) ─┘
│ • named subClassOf <ns+class>
│ • named rdf:type <ns+class>
│ • blank nodes skipped, de-duped
│ • {id, label(or id), description(or "")}
│ │
└─ _deep_merge(base, extracted) ──► + _generated provenance
──► output_dir/filename.json
Two properties make this a compiler rather than a script: the output is a pure function of (graph, spec table, namespace) — deterministic and stamped with provenance — and every failure mode degrades open — a missing/garbage TTL or a per-class extraction error logs a warning and yields empty lists, never an exception that aborts the run.
| Seam | How to use it |
|---|---|
| Which configs / class bindings | The spec_table — a list of ConfigSpec (or plain dicts). Each row's extract maps an output JSON key to a bound class local-name (or a list of them, concatenated). There is no hard-coded class set. |
| Namespace | generate_configs(..., namespace=...) / extract_named(..., namespace=...). Defaults to the neutral http://example.org/ontology/core/; point it at your core ontology's IRI. |
| Shape baseline | ConfigSpec.static (inline fixed scaffolding) and/or starter_dir= (read-only JSON shape templates loaded per filename). Extracted non-empty lists win over the baseline; an empty extraction preserves it. |
| Output JSON shape | Per-spec: the keys in extract + the static dict define the document. The extractor always emits {id, label, description} rows. |
| Storage / parsing | Reads/writes are plain files. Swap generate_configs for a wrapper that streams to a DB or object store — keep the ConfigSpec contract so callers don't change. |
| Runtime dependencies | None at import. rdflib is required only to parse a graph (lazy import); install via the dev or rdf extra. |
- Deterministic — no LLM, no randomness; identical inputs produce identical configs (byte-for-byte, modulo the
_generated.frompath). - Degrade-open — a missing/unparseable extension or a failed extraction yields starter/static-shaped configs with empty lists, never a raised exception.
- Lazy heavy import —
rdflibis imported insidegenerate_configs/extract_named;import ontology_config_generatorworks with rdflib absent. - Domain-neutral — no class name and no namespace is hard-coded; both are caller-supplied (the namespace has a neutral default).
- Blank nodes excluded — only IRI-named subjects are emitted, and each subject appears once even if it is both a subclass and an instance.