# How Python Pydantic Models Work in Apache Ossie: Schema Validation and Serialization

> Discover how Python Pydantic models integrate with Apache Ossie for robust schema validation and seamless serialization. Convert YAML/JSON to type-safe Python objects efficiently.

- Repository: [The Apache Software Foundation/ossie](https://github.com/apache/ossie)
- Tags: how-to-guide
- Published: 2026-07-19

---

**Apache Ossie defines its semantic-model schema using immutable Pydantic BaseModel classes in [`python/src/ossie/models.py`](https://github.com/apache/ossie/blob/main/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`](https://github.com/apache/ossie/blob/main/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`](https://github.com/apache/ossie/blob/main/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 `OSIDialect` enum 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.

```python
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:

```python
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.py`](https://github.com/apache/ossie/blob/main/python/src/ossie/models.py) using 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_yaml` and `to_osi_json` methods leverage `model_dump` with `by_alias=True` for clean serialization.
- The `model_validate` method 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`](https://github.com/apache/ossie/blob/main/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`](https://github.com/apache/ossie/blob/main/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`](https://github.com/apache/ossie/blob/main/models.py) implementation.