Schema generator¶
The Schema.org models are generated by tools/schema-generator, a development tool that is not
published to PyPI. Its source of truth is the official machine-readable ontology.
Usage¶
From the repository root:
| Option | Effect |
|---|---|
| (none) | Use the newest release vendored in tools/schema-generator/data |
--version latest |
Download the latest release announced by Schema.org, then generate |
--version 30.1 |
Download (or reuse) a specific release |
--source FILE |
Use a local schemaorg-*-https.nt file |
--schema-version X |
Version label when the --source file name has none |
--output DIR |
Write elsewhere than packages/goatseo-schema/src/goatseo/schema |
--include-pending |
Also generate terms from pending.schema.org |
--check |
Write nothing; exit with status 1 if the generated files are out of date |
uv run goatseo-schema generate --version latest
uv run goatseo-schema generate --source schemaorg-all-https.nt --output generated/
uv run goatseo-schema generate --check # used by CI
Downloaded releases are saved as tools/schema-generator/data/schemaorg-<version>-current-https.nt.
Commit them: the vendored file makes every regeneration reproducible offline.
Pipeline¶
schemaorg-current-https.nt
│ ntriples.py strict N-Triples reader
▼
triples
│ parser.py classes, properties, enumerations, layers
▼
Internal representation (ir.py)
│ mapper.py Schema.org types to Python types and names
▼
Python declarations
│ pyrender.py source code
▼
Ruff (import sorting, format)
▼
_types.py, _enumerations.py, _version.py
The RDF never reaches Python code directly: everything goes through the intermediate representation.
Internal representation¶
goatseo_schema_generator.ir holds frozen dataclasses:
SchemaType: name, parent types (multiple inheritance), properties, description, kind (CLASS,ENUMERATION,DATATYPE), layer,superseded_by, enumeration members.SchemaProperty: name,domainIncludes,rangeIncludes, description, layer,superseded_by,inverseOf.EnumerationMember: name, the enumerations it belongs to,superseded_by.Ontology: the closed vocabulary, withancestors,descendantsandchildrenqueries.
The parser keeps the core layer and the health-lifesci, bib and auto extensions by
default. When a parent or range belongs to an excluded layer, it is replaced by its nearest
included ancestor or dropped, so the IR never refers to a missing type.
Type mapper¶
- Data types map to Python types (
Texttostr,Datetodatetime.date, ...). - Classes map to model classes; the unions of ranges become union annotations, always accepting a list of values too.
- Enumerations with members become
StrEnumclasses; enumerations without members become models. Large enumeration unions collapse toSchemaEnumeration. - Redundant bases are removed and the method resolution order of every class is checked, so a broken hierarchy fails the generation instead of the import.
- Name collisions (keywords, Pydantic reserved names, two properties mapping to the same snake_case name) are fixed or reported as errors.
Determinism¶
Every collection is sorted before rendering and the output is formatted by Ruff with the
configuration that applies to the target file. Running the generator twice on the same input
produces byte-identical files, which is what --check verifies in CI.