Skip to main content

SchemaIR for Python

Types as data: Portable contracts and type calculations in Python.

SchemaIR declarations are ordinary JSON-compatible dictionaries. You can store a contract with a project, exchange it with a TypeScript tool, and inspect or calculate types without executing the application behind the contract.

This is the Python 0.2.0 binding for SchemaIR V1. It implements the shared protocol rather than Python annotations or Pydantic models. The TypeScript implementation remains the behavioral reference.

Install from source

Use Python 3.11 or newer. From the repository root:

python -m pip install -e ./python

The package is published on PyPI as schemair.

Store, calculate, and validate a contract

import json
from schemair import authoring as s
from schemair import (
    check_schema_relation,
    evaluate_expression,
    validate_payload,
    validate_schema,
)

# A SchemaNode describes the concrete output shape as data.
user = s.record([
    s.required_field("id", s.string()),
    s.required_field("name", s.string()),
])

# Reload the declaration without importing its original application.
loaded = json.loads(json.dumps(user))
assert validate_schema(loaded).status == "accepted"

# Build a SchemaTypeExpr, then evaluate it before executing an operation.
selection = s.field_of(loaded, "name")
name_type = evaluate_expression(selection)
assert name_type.status == "evaluated"
assert check_schema_relation(name_type.value, s.string()).status == "assignable"

# Validate actual values independently of type calculation.
payload = validate_payload({"id": "123", "name": "Ada"}, loaded)
assert payload.status == "accepted"

Python exposes snake_case helpers directly from schemair.authoring and also provides schemair.authoring.schema and schemair.authoring.expression namespaces matching the TypeScript authoring boundary. Wire fields retain the protocol's camelCase spelling, such as elementSchema, refPath, and semanticPath.

API and results

Task Entry points Results
Validate declarations validate_schema, validate_operation, validate_operation_container, validate_structured_operation, validate_structured_operation_container, validate_schema_type_expr, validate_schema_type_term accepted, rejected
Validate data validate_payload, validate_payload_async accepted, rejected, unknown
Compare contracts check_schema_relation, check_operation_relation and their _async companions assignable, incompatible, unknown, rejected
Calculate types evaluate_expression, evaluate_schema_type_term and their _async companions evaluated, incomplete, rejected
Compare type terms check_type_term_relation, check_type_term_relation_async Relation statuses
Infer variables solve_type_variables, solve_type_variables_async solved, unknown, incompatible, rejected

These functions return a Result with status, issues, and value. Expression results put the evaluated term in value and expose unresolved variable names through unresolved_type_vars; solver results put the binding dictionary there. An evaluated term may still be an expression, so check its shape before using it as a concrete schema. Diagnostics contain a code, path, message, and optional details.

validate_expression(value, term=True) remains available for validating either a schema or an expression. Definition validation does not execute operations or resolve external references.

Solve a type variable

from schemair import authoring as s, evaluate_expression, solve_type_variables

solution = solve_type_variables(
    ["T"],
    [{"source": s.number(), "target": s.type_var("T")}],
)
assert solution.status == "solved"
output = evaluate_expression(s.array_of(s.type_var("T")), type_vars=solution.value)
assert output.value == {"kind": "array", "elementSchema": s.number()}

The solver infers from supported source-to-target constraints. It is finite, not a complete Python or TypeScript generic type checker. Inspect unknown and diagnostics when candidate relations cannot be proved.

Operations and host callbacks

An operation is a concrete declaration of input, output, errors, and emitted channels. Structured payloads contain SchemaNode values. Functions and unresolved expressions are not operation payload schemas. See the operation model.

Reference resolvers receive a tuple of path segments. For example:

import asyncio
from schemair import authoring as s, validate_payload_async

async def resolve_ref(path):
    return s.string() if path == ("UserName",) else None

async def main():
    result = await validate_payload_async("Ada", s.ref(["UserName"]), resolve_ref=resolve_ref)
    assert result.status == "accepted"

asyncio.run(main())

The payload and schema relation APIs accept resolve_ref, semantic_provider, and constraint_provider. Python payload callbacks receive (semantic_path, value) or (constraints, value); relation callbacks receive the source and target paths or constraint lists. Term relation APIs additionally accept host_type_relation(source_path, target_path) for opaque host types.

Use async APIs when callbacks perform I/O. Async wrappers resolve references and adapt providers before invoking the synchronous core. Nested arrays, records, tagged unions, and typed additional fields are traversed for provider calls, including structured operation errors and emitted channels. Async expression evaluation enforces the same step/depth budgets and resolver decision states as the synchronous surface.

Standard vocabulary

schemair.standard exposes STANDARD_SEMANTIC_PATHS, STANDARD_CONSTRAINT_PATHS, definition maps, standard_vocabulary_registry, and classify_semantic_path. Standard validation is opt-in:

from schemair import authoring as s, standard, validate_payload

email = s.string(semantic_path=standard.STANDARD_SEMANTIC_PATHS["string"]["email"])
result = validate_payload("ada@example.com", email, **standard.standard_payload_context)
assert result.status == "accepted"

standard_schema_satisfiability, refine_standard_schema, and intersect_standard_schemas expose the same conservative standard constraint profile used by the TypeScript reference, including binary64 interval boundaries, exact float-derived multipleOf checks, pattern handling, and standard argument domains. The relation context implements the shared semantic narrowing and constraint implication rules; host regex/date behavior still follows Python's libraries.

Host policies matter: Python uses its date/time, IP, and regex libraries, while TypeScript uses JavaScript predicates. Python integers are unbounded, but standard multipleOf converts numbers to binary64 and compares exact rational representations. Do not assume arbitrary-precision decimal behavior or identical regex/date acceptance across hosts. See standard vocabulary host policies.

Integrations

from schemair import authoring as s, project_json_schema

schema = s.record([s.required_field("name", s.string())])
projection = project_json_schema(schema, target="draft-2020-12")
assert projection.fidelity == "exact"
print(projection.schema, projection.diagnostics)

Targets are draft-2020-12, draft-07, and openapi-3.0. schema_node_to_json_schema and schema_node_to_openapi_schema return a diagnostic-bearing projection. to_json_schema returns only the dictionary; prefer the projection API when fidelity matters. Supported options include both Python snake_case names and TypeScript-compatible camelCase aliases for ref and mapper strategies. Fidelity results are exact, lossy, or unsupported.

to_standard_schema(schema, **context) returns a ~standard adapter whose validate callable is async and preserves accepted input values. schemaIR_to_standard_json_schema(schema) exposes jsonSchema.input and jsonSchema.output callables; each takes a target string and raises ValueError for unsupported projections. These are Python callable surfaces, not JavaScript package interface types.

Development and verification scope

From python/, run:

python -m unittest discover -s tests -v
python -m compileall -q schemair

Tests read shared schema, operation, expression, solver, and vocabulary vectors from ../conformance/, alongside local integration tests. Shared expression vectors assert evaluated term contents and unresolved variables; solver vectors assert bindings; rejected cases assert diagnostics; local tests cover provider decision shapes, async traversal, resolver cycles, and interpreter budgets.

The binding does not execute operations, supply a scheduler or reference catalog, or provide TypeScript's compile-time Infer utilities. See the roadmap for remaining parity and ecosystem work.

Metadata

Release files for schemair 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for schemair 0.2.0
File Size Uploaded
schemair-0.2.0.tar.gz 47.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for schemair 0.2.0
File Interpreter ABI Platform
schemair-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 93.8 kB

Release files / schemair-0.2.0.tar.gz

Download URL schemair-0.2.0.tar.gz
Size 47.6 kB
Tags Source
SHA-256 checksum
How to use checksums
8f117cbf7abe44f0688ff40debd2299af6f30c65cf8c659284c7e619cfea6b5a
BLAKE2b-256 checksum
How to use checksums
4d32dcdd974667cd52e79ad389a01e94705f3528f50480a6529f40fb5a6ad0cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.11

Release files / schemair-0.2.0-py3-none-any.whl

Download URL schemair-0.2.0-py3-none-any.whl
Size 46.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dc179b573c16f1b80a633af07dae69e0593c490ff5f4126855f329156fb3bb33
BLAKE2b-256 checksum
How to use checksums
4daacfac9c2b29b7f7efcf75c54413d98280e560f02811efe062f6e85eedd049
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.11

Release history Release notifications | RSS feed

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page