Models

The _tag attribute

The _tag attribute is used to define the ASDF tag for the model given it a language-agnostic version and a name. It is a string that follows the ASDF URI format or an ASDF TagDefinition object.

class MyModel(AsdfPydanticModel):
    _tag = "asdf://asdf-pydantic/examples/tags/mymodel-1.0.0"

print(MyModel.get_tag_definition())
# TagDefinition(
#     tag="asdf://asdf-pydantic/examples/tags/mymodel-1.0.0",
#     schema_uri="asdf://asdf-pydantic/examples/schemas/mymodel-1.0.0",
# )

Notice the schema URI is also defined alongside the tag. If you wish to overwrite this, define your tag with a TagDefinition instead.

from asdf.extension import TagDefinition

class MyModel(AsdfPydanticModel):
    _tag = TagDefinition(
        tag=f"asdf://asdf-pydantic/examples/tags/mymodel-1.0.0",
        schema_uri=f"asdf://asdf-pydantic/examples/schemas/foobar-1.0.0",
    )

print(MyModel.get_tag_definition())
# TagDefinition(
#     tag="asdf://asdf-pydantic/examples/tags/mymodel-1.0.0",
#     schema_uri="asdf://asdf-pydantic/examples/schemas/foobar-1.0.0",
# )

ASDF Schema

All AsdfPydanticModel models have an ASDF schema. Its schema definition (a YAML string) can be obtained by calling model_asdf_schema() and its URI get_tag_definition().

Validation

The ASDF schema is used for validation when loading an ASDF file.

JSON Schema

All AsdfPydanticModel models have a JSON schema. Its schema definition (a JSON string) can be obtained by calling model_json_schema().

JSON Validation

The JSON schema is not used for validation neither in ASDF nor in Pydantic.

Model Validation

asdf-pydantic provides validation on both directions of serialization and deserialization.

Validation during deserialization

Deserialization happens when loading an ASDF file into a Python object (e.g., af.open()). If the ASDF file contains a tagged object associated with an AsdfPydanticModel the validation performed are:

  1. ASDF field validation

    All tagged fields in ASDF are validated against its associated ASDF schema.

    To disable this, see disabling ASDF validation.

  2. Pydantic model validation

    All fields with tag associated with an AsdfPydanticModel subtype are validated using Pydantic.

    To disable this, see disabling Pydantic model validation.

ASDF whole file validation

Although not common, some ASDF file may have a schema to validate its whole file and not just the tagged fields contained. File-level validation is performed if a schema is explicitly provided while opening the ASDF file. See ASDF docs for more information.

Validation during serialization

Serialization happens when writing a Python object to an ASDF file (e.g., af.write_to()).

Typically, ASDF will not validate the data being written to the ASDF file, but with AsdfPydanticModel models, Pydantic validation will be performed when upon creating the model instance.

af = AsdfFile({
    "data": MyModel(width=1.0, height=2.0)  # Pydantic validation here
})
af.write_to("data.asdf")  # No ASDF validation here

To disable Pydantic validation, see disabling Pydantic model validation.

ASDF does provide a way to validate all tagged fields in the ASDF tree with AsdfFile.validate()

af = AsdfFile({
    "data": MyModel(width=1.0, height=2.0)  # Pydantic validation here
})
af.validate() # ASDF validation here
af.write_to("data.asdf")  # No ASDF validation here

ASDF whole file validation

Like with deserialization, the whole tree isn’t validated by ASDF, just the tagged fields. You may pass in a schema to AsdfFile.validate() to validate the whole file.

See ASDF docs for more information.

A note on modeling ASDF files

asdf-pydantic focuses on modeling fields you’d populate an ASDF file with, but it does not model the entire file itself. This can be illustrated by when attempting to create an ASDF file, the AsdfPydanticModel describes a key in the tree and not the tree itself.

tree: dict = {
    "data": MyModel(width=1.0, height=2.0),
    "meta": MyMetaModel(author="John Doe", sw_version="1.0.0")
}
af = AsdfFile(tree)

What if you want to model the entire tree with Pydantic?

It’s a very reasonable request to want to mandate your ASDF file must have the fields data and meta in the root of the ASDF file and those fields. However due to ASDF lacking a method to associate an ASDF file to a specific schema (i.e., all ASDF files are validated against the core/asdf schema), the call to validation and association must be done manually.

import asdf.schema

class MyAsdfFileModel(AsdfPydanticModel):
    # NOTE: This tag will not replace the core/asdf schema tag
    # It is only used if the model is used as a tagged field.
    _tag = "asdf://asdf-pydantic/examples/tags/my-asdf-file-1.0.0"

    data: MyModel
    meta: MyMetaModel

tree: dict = MyAsdfFileModel(                                # Pydantic validates the entire tree here
    data=MyModel(width=1.0, height=2.0),                     # Pydantic validates the field here
    meta=MyMetaModel(author="John Doe", sw_version="1.0.0")  # Pydantic validates the field here
).model_dump()                                               # For type checking, we keep the tree a dict.

af = AsdfFile(tree)
# At this point, ASDF has not done any validation.
# We must explicitly ask it to...

asdf.schema.validate(af.tree)                                # ASDF validates the tree here

# Notice we didn't pass any schema to `validate()`, that's because
# AsdfPydanticModel has a schema associated with its tag..
# You may explicitly pass in the model schema.
asdf.schema.validate(af.tree, schema=MyAsdfFileModel.model_asdf_schema()) # ASDF validates the tree here