Model

didactic.api.Model

Model(**kwargs: FieldValue | JsonValue)

Base class for didactic models.

Subclasses declare fields as ordinary type-annotated class attributes::

import didactic as dx


class User(dx.Model):
    id: str
    email: str
    display_name: str = ""

Construction validates the fields against the class's __field_specs__; attribute access decodes from the underlying storage on each call (no parallel Python-side mirror).

Notes

Instances are frozen. Use with_ to produce a new instance with one or more fields changed.

See Also

didactic.field : the field descriptor constructor. didactic.ValidationError : raised on construction failure.

Construct a Model from keyword arguments.

PARAMETER DESCRIPTION
**kwargs

One value per declared field. Required fields must be supplied.

TYPE: FieldValue | JsonValue DEFAULT: {}

RAISES DESCRIPTION
ValidationError

If required fields are missing, unknown fields are supplied, or a value fails the field's converter / type translation.

with_

with_(**changes: FieldValue) -> Self

Return a new instance with the specified fields replaced.

PARAMETER DESCRIPTION
**changes

Field-name -> new-value pairs.

TYPE: FieldValue DEFAULT: {}

RETURNS DESCRIPTION
Model

A new instance of the same class with the changes applied.

RAISES DESCRIPTION
ValidationError

If any change fails type translation or refers to an unknown field.

model_dump

model_dump(
    *,
    include: set[str] | None = None,
    exclude: set[str] | None = None,
    by_alias: bool = False,
    exclude_none: bool = False,
    exclude_defaults: bool = False,
) -> dict[str, FieldValue]

Render this Model as a plain dict of decoded values.

PARAMETER DESCRIPTION
include

If set, only emit fields whose name is in this set.

TYPE: set[str] | None DEFAULT: None

exclude

If set, omit fields whose name is in this set. Applied after include.

TYPE: set[str] | None DEFAULT: None

by_alias

If True, use each field's alias (where set) as the key in the output dict instead of the field name.

TYPE: bool DEFAULT: False

exclude_none

If True, omit fields whose value is None.

TYPE: bool DEFAULT: False

exclude_defaults

If True, omit fields whose current value equals their declared default.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
dict

{field_name: decoded_value} for every selected field plus every computed field. Embedded sub-models recurse into nested dicts so the result is fully JSON-shaped.

See Also

Model.model_dump_json : JSON-stringified variant.

model_dump_json

model_dump_json(*, indent: int | None = None) -> str

Render this Model as a JSON string.

PARAMETER DESCRIPTION
indent

JSON indentation level. None produces compact JSON; an integer produces pretty-printed output.

TYPE: int | None DEFAULT: None

RETURNS DESCRIPTION
str

JSON encoding of model_dump.

Notes

Field values that are not natively JSON-encodable (datetime, Decimal, UUID, bytes, frozenset) are converted to JSON-friendly forms; datetime to ISO 8601 strings, Decimal to numeric strings, UUID to its canonical string form, bytes to hex, and frozenset to a sorted list. The same conversions are unwound by model_validate_json.

See Also

Model.model_dump : dict-shaped equivalent. Model.model_validate_json : the inverse direction.

model_json_schema classmethod

model_json_schema() -> JsonSchemaDoc

Build a JSON Schema (Draft 2020-12) document for this Model.

RETURNS DESCRIPTION
dict

A JSON Schema object describing the Model's fields, required keys, and any annotated-types constraints (Ge/Le/MinLen/etc.). Pydantic-shaped consumers (FastAPI, OpenAPI generators) can use this directly.

See Also

didactic.codegen.json_schema_of : the underlying implementation.

emit_as classmethod

emit_as(target: str, **opts: object) -> bytes

Emit this Model class under the named target format.

PARAMETER DESCRIPTION
target

Either a custom-emitter target name (registered via @dx.codegen.emitter or dx.codegen.register_emitter), a panproto IoRegistry protocol ("avro", "openapi", ...), or a panproto grammar name ("rust", "typescript", ...).

TYPE: str

**opts

Optional emitter-specific options.

TYPE: object DEFAULT: {}

RETURNS DESCRIPTION
bytes

The emitted artefact.

RAISES DESCRIPTION
LookupError

If no emitter, codec, or grammar matches target.

Notes

Lookup order: custom emitters first, then IoRegistry protocols, then AstParserRegistry grammars. The "json_schema" target is handled specially: it uses didactic's own JSON Schema generator rather than panproto's codec, so the output matches Pydantic's dialect.

model_validate classmethod

model_validate(
    payload: Mapping[str, FieldValue | JsonValue],
) -> Self

Construct a Model from a dict payload.

PARAMETER DESCRIPTION
payload

{field_name: value} mapping. Equivalent to cls(**payload).

TYPE: Mapping[str, FieldValue | JsonValue]

RETURNS DESCRIPTION
Model

The validated instance.

RAISES DESCRIPTION
ValidationError

If validation fails.

See Also

Model.model_validate_json : variant that takes a JSON string.

model_validate_json classmethod

model_validate_json(raw: str | bytes | bytearray) -> Self

Construct a Model from a JSON string.

PARAMETER DESCRIPTION
raw

JSON-encoded payload; string, bytes, or bytearray.

TYPE: str | bytes | bytearray

RETURNS DESCRIPTION
Model

The validated instance.

RAISES DESCRIPTION
ValidationError

If validation fails.

JSONDecodeError

If raw is not valid JSON.

Notes

After JSON decode, values are converted back through each field's decoder pipeline; any JSON-vs-Python representation gap (e.g. datetime from ISO string, Decimal from numeric string) is bridged before the call into the type translation layer.

from_storage_dict classmethod

from_storage_dict(items: dict[str, str]) -> Self

Build an instance directly from an encoded-storage dict.

PARAMETER DESCRIPTION
items

{field_name: encoded_value} mapping. Values must already be in panproto-shape encoded form (the same shape produced by to_storage_dict).

TYPE: dict[str, str]

RETURNS DESCRIPTION
Model

A new instance whose storage is built from items directly, without re-running validation.

Notes

Private API. Used by Embed field handling and by pickle's __setstate__ hook. Bypassing validation is safe because the values originated from a previously validated instance; do not feed user-supplied data through this hook.

to_storage_dict

to_storage_dict() -> dict[str, str]

Return the encoded-storage dict for this instance.

RETURNS DESCRIPTION
dict

{field_name: encoded_value}; the panproto-shape encoded form of every declared field. Round-trips through from_storage_dict.

didactic.api.BaseModel module-attribute

BaseModel = Model

didactic.api.ModelConfig dataclass

ModelConfig(
    extra: ExtraPolicy = "forbid",
    strict: bool = True,
    populate_by_name: bool = False,
    title: str | None = None,
    description: str | None = None,
)

Class-level configuration for a Model subclass.

PARAMETER DESCRIPTION
extra

How to handle keyword arguments that don't match a declared field. "forbid" (default) raises ValidationError on any unknown key; "ignore" silently drops unknown keys at construction (the dropped values never enter the model and never appear in model_dump()). "allow" raises NotImplementedError (it needs a storage decision for unknown fields that the immutable Model contract doesn't cleanly support yet).

TYPE: ExtraPolicy DEFAULT: 'forbid'

strict

If True, type coercion is disabled; every field's value must already be the declared type. Default True. False raises NotImplementedError until coercion lands.

TYPE: bool DEFAULT: True

populate_by_name

If True, fields with an alias accept both the alias and the Python attribute name as input keys. Default False.

TYPE: bool DEFAULT: False

title

Optional human-readable name for documentation / codegen.

TYPE: str | None DEFAULT: None

description

Optional description rendered into Theory metadata.

TYPE: str | None DEFAULT: None

didactic.api.DEFAULT_CONFIG module-attribute

DEFAULT_CONFIG = ModelConfig()

The configuration applied to a Model that does not specify one.

didactic.api.ExtraPolicy module-attribute

ExtraPolicy = Literal['forbid', 'ignore', 'allow']