Skip to content

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.

Parameters:

Name Type Description Default
**kwargs FieldValue | JsonValue

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

{}

Raises:

Type 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.

Parameters:

Name Type Description Default
**changes FieldValue

Field-name -> new-value pairs.

{}

Returns:

Type Description
Model

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

Raises:

Type 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.

Parameters:

Name Type Description Default
include set[str] | None

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

None
exclude set[str] | None

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

None
by_alias bool

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

False
exclude_none bool

If True, omit fields whose value is None.

False
exclude_defaults bool

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

False

Returns:

Type 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.

Parameters:

Name Type Description Default
indent int | None

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

None

Returns:

Type 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:

Type 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.

Parameters:

Name Type Description Default
target str

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", ...).

required
**opts object

Optional emitter-specific options.

{}

Returns:

Type Description
bytes

The emitted artefact.

Raises:

Type 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.

Parameters:

Name Type Description Default
payload Mapping[str, FieldValue | JsonValue]

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

required

Returns:

Type Description
Model

The validated instance.

Raises:

Type 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.

Parameters:

Name Type Description Default
raw str | bytes | bytearray

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

required

Returns:

Type Description
Model

The validated instance.

Raises:

Type 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.

Parameters:

Name Type Description Default
items dict[str, str]

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

required

Returns:

Type 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:

Type 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.

Parameters:

Name Type Description Default
extra ExtraPolicy

How to handle keyword arguments that don't match a declared field. Only "forbid" is honoured currently; "ignore" and "allow" raise NotImplementedError.

'forbid'
strict bool

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

True
populate_by_name bool

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

False
title str | None

Optional human-readable name for documentation / codegen.

None
description str | None

Optional description rendered into Theory metadata.

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']