The Python port of the MetaObjects cross-language metadata standard: declare your typed entity model once, then generate idiomatic, drift-checked code across TypeScript, Java, C#, Python, and Kotlin. The metamodel is the durable spine; generated code is the disposable artifact.
Behavior is verified byte-for-byte against the same shared conformance corpora as every other language port.
Requires Python 3.11+.
pip install metaobjectsThe only runtime dependency is PyYAML.
Load a directory of metadata (*.json canonical or sigil-free *.yaml):
from metaobjects import load_directory
result = load_directory("metaobjects/") # your *.json / *.yaml metadata files
if result.errors:
for err in result.errors:
print(err) # structured MetaError with a stable ErrorCode
else:
root = result.root # the merged metadata tree (a MetaData node)
print(root)load_directory, load_uris, and load_string are module-level shortcuts over
MetaDataLoader; all return a LoadResult with the same field shape as the other ports.
The primary public API is the loader (load_directory / load_uris /
load_string, MetaDataLoader, LoadResult, ErrorCode, MetaError). The
distribution also ships the Python implementations of the other pillars used by the CLI
and tooling: codegen (Pydantic + FastAPI emit — reference generators you own:
metaobjects eject <name> copies one into your repo), render (Mustache, or Jinja with
pip install metaobjects[jinja] — ADR-0061 — + payload-VO + verify), and runtime (a DB-API 2 ObjectManager — pg8000 / psycopg on Postgres, the standard library's sqlite3 on SQLite, PyMySQL on MySQL 8 (pip install metaobjects[mysql]) — no SQLAlchemy).
Schema migrations are owned by the TypeScript meta CLI (ADR-0015); there is
no migrate module in this distribution.
Table and column names are one project setting, naming in .metaobjects/config.json
(columns and tables, each snake_case by default or literal). metaobjects gen and
verify read it, and so do load_directory, load_uris and load_string(..., project_dir=...):
they search upward from the metadata directory for that file, so the ObjectManager queries the
names the code was generated for. If you keep a database whose columns are named exactly like the
fields, add "naming": { "columns": "literal" }. With no config file found the loader warns once
and uses snake_case; metaobjects.naming.attach_naming(root, project_dir) sets it explicitly and
wins. See the upgrade guide and
physical naming.
- Canonical JSON (
*.json) — the cross-language interchange shape. - Sigil-free YAML (
*.yaml/*.yml) — the AI-first authoring front-end (ADR-0006). Desugared to canonical JSON at load time. A directory may mix both freely.
To scaffold MetaObjects context files (.metaobjects/AGENTS.md, .metaobjects/CLAUDE.md, and
.claude/skills/metaobjects-*/) into your project so your AI assistant understands how to
author metadata and run codegen, use the Node meta CLI:
npx meta agent-docs --server python(Running metaobjects agent-docs in the Python CLI prints this redirect and exits.)
- Standard, docs, and the other four ports: https://metaobjects.dev
- Source & issues: https://github.com/metaobjectsdev/metaobjects
- Full docs: https://github.com/metaobjectsdev/metaobjects/tree/main/docs
Apache-2.0. See LICENSE.