How Python Pydantic Models Work in Apache Ossie: Schema Validation and Serialization
Apache Ossie defines its semantic-model schema using immutable Pydantic BaseModel classes in python/src/ossie/models.py, leveraging type validation, field aliasing, and serialization helpers to convert between declarative YAML/JSON and type-safe Python objects.
The Apache Ossie project uses Python Pydantic models to transform declarative semantic definitions into validated, programmatic Python objects. In the apache/ossie repository, the python/src/ossie/models.py module contains the complete hierarchy of Pydantic classes representing datasets, fields, and metrics. By delegating validation and serialization logic to Pydantic, Ossie ensures strict schema compliance while maintaining clean, immutable data structures.
Pydantic BaseModel Architecture in models.py
The Ossie Python package declares all semantic entities as subclasses of pydantic.BaseModel within python/src/ossie/models.py. The root object OSIDocument contains version metadata, supported dialects, and a list of OSISemanticModel instances. Nested within these are OSIDataset, OSIField, OSIMetric, and OSIExpression classes, each annotated with Python type hints such as str, Optional[list[OSIField]], and custom enums.
This architecture delegates all runtime validation to Pydantic. When instantiating any model, Pydantic checks the input data against the declared types and raises a ValidationError immediately if the structure does not conform to the schema, preventing invalid semantic definitions from propagating through converters or CLI tools.
Strict Type Validation and ConfigDict
Ossie configures its Pydantic models for immutability and safety using ConfigDict. Every class defines model_config = ConfigDict(frozen=True), which makes instances immutable after creation. This guarantees reproducible semantic definitions across different environments and prevents accidental mutation during complex conversion operations.
For AI context objects that require flexibility, Ossie uses model_config = ConfigDict(frozen=True, extra="allow") on the OSIAIContextObject class. This setting permits arbitrary additional keys beyond the defined schema, ensuring future extensions do not break existing validation logic while keeping the model frozen.
Field Aliases for Specification Compliance
To handle JSON/YAML keys that conflict with Python reserved words, Ossie uses Pydantic's Field aliasing. For example, the relationship model maps the JSON key "from" to the Python-safe attribute from_dataset using Field(..., alias="from"). This allows Ossie to expose Pythonic attribute names internally while maintaining exact compatibility with the OSSIE JSON/YAML specification.
Serialization with model_dump
The OSIDocument class provides custom serialization helpers to_osi_yaml and to_osi_json that wrap Pydantic's native methods. These methods call model_dump and model_dump_json with by_alias=True and exclude_none=True, ensuring that field aliases are preserved in the output and null values are excluded. This produces clean, specification-compliant YAML and JSON without manual dictionary manipulation.
The Semantic Model Hierarchy
The Ossie semantic structure follows a strict containment pattern implemented as nested Pydantic models:
- OSIDocument: The root container holding version, dialects, vendors, and semantic models.
- OSISemanticModel: Groups datasets, relationships, and metrics describing a specific business domain.
- OSIDataset: Represents a logical table with primary keys and a list of OSIField objects.
- OSIField: Contains an OSIExpression supporting multiple dialects, plus optional dimensions or AI context.
- OSIExpression: Wraps a list of OSIDialectExpression pairs, each binding an
OSIDialectenum to a raw expression string.
All classes act as pure data containers, with Pydantic handling the heavy lifting of validation, immutability, and serialization.
Loading and Validating External Documents
Ossie supports loading external YAML or JSON documents directly into Pydantic models using the model_validate class method. This approach performs strict validation against the schema upon loading, raising descriptive errors if the document structure deviates from the specification.
import yaml
from ossie.models import OSIDocument
yaml_str = """
version: "0.2.0"
dialects:
- ANSI_SQL
semantic_model:
- name: sales_analytics
datasets:
- name: orders
source: my_database.orders
primary_key: [order_id]
fields:
- name: sales_amount
expression:
dialects:
- dialect: ANSI_SQL
expression: "SUM(sales_amount)"
"""
data = yaml.safe_load(yaml_str)
doc = OSIDocument.model_validate(data) # Raises ValidationError on schema mismatch
print(doc)
Complete Code Example: Building a Semantic Model
The following example demonstrates constructing a complete semantic model programmatically and serializing it to OSSIE-compliant YAML:
from ossie.models import (
OSIDialect,
OSIDocument,
OSISemanticModel,
OSIDataset,
OSIField,
OSIExpression,
OSIDialectExpression,
OSIMetric
)
# Define a SQL expression for a metric
expr = OSIExpression(
dialects=[
OSIDialectExpression(
dialect=OSIDialect.ANSI_SQL,
expression="SUM(sales_amount)"
)
]
)
# Create a metric using the expression
metric = OSIMetric(
name="total_sales",
expression=expr,
description="Total sales amount"
)
# Build a dataset with fields
field = OSIField(
name="sales_amount",
expression=expr
)
dataset = OSIDataset(
name="orders",
source="my_database.orders",
primary_key=["order_id"],
fields=[field]
)
# Assemble the semantic model
semantic_model = OSISemanticModel(
name="sales_analytics",
datasets=[dataset],
metrics=[metric]
)
# Create the OSSIE document and output YAML
doc = OSIDocument(
version="0.2.0",
dialects=[OSIDialect.ANSI_SQL],
semantic_model=[semantic_model]
)
print(doc.to_osi_yaml())
Summary
- Ossie defines its entire semantic schema in
python/src/ossie/models.pyusing Pydantic BaseModel subclasses. - ConfigDict(frozen=True) ensures all semantic objects are immutable and reproducible across conversions.
- Field aliases resolve conflicts between Python reserved keywords and OSSIE specification keys like
"from". - The
to_osi_yamlandto_osi_jsonmethods leveragemodel_dumpwithby_alias=Truefor clean serialization. - The
model_validatemethod provides strict loading and validation of external YAML/JSON documents.
Frequently Asked Questions
How does Ossie ensure Pydantic models remain immutable?
Ossie configures each Pydantic class with model_config = ConfigDict(frozen=True) in python/src/ossie/models.py. This setting prevents attribute modification after instantiation, guaranteeing that semantic definitions remain constant throughout the conversion lifecycle and ensuring reproducible builds across different environments.
Why does Ossie use field aliases in its Python models?
Field aliases allow Ossie to map JSON/YAML specification keys that conflict with Python reserved words—such as "from"—to valid Python attribute names like from_dataset. Using Field(..., alias="from") preserves exact specification compliance in serialized output while maintaining Pythonic code standards internally.
How do I validate an external YAML file against Ossie Pydantic models?
Parse the YAML content and pass the resulting dictionary to OSIDocument.model_validate(data). This class method performs comprehensive schema validation and raises a Pydantic ValidationError if the structure, types, or relationships do not conform to the OSSIE specification, ensuring only valid definitions are processed.
What Pydantic version does Apache Ossie require?
According to the python/pyproject.toml in the apache/ossie repository, the project declares a dependency on Pydantic 2.x (pydantic>=2.0). This version provides the ConfigDict configuration pattern and model_dump methods used throughout the models.py implementation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →