Source code for litestar.dto.field

"""DTO domain types."""

from __future__ import annotations

from dataclasses import dataclass
from enum import Enum
from typing import TYPE_CHECKING

from litestar.exceptions import ImproperlyConfiguredException

if TYPE_CHECKING:
    from typing import Any, Literal, Mapping

    from litestar.typing import FieldDefinition

__all__ = (
    "DTO_FIELD_META_KEY",
    "DTOField",
    "Mark",
    "dto_field",
    "extract_dto_field",
)

DTO_FIELD_META_KEY = "__dto__"


class Mark(str, Enum):
    """For marking field definitions on domain models."""

    READ_ONLY = "read-only"
    """To mark a field that can be read, but not updated by clients."""
    WRITE_ONLY = "write-only"
    """To mark a field that can be written to, but not read by clients."""
    PRIVATE = "private"
    """To mark a field that can neither be read or updated by clients."""


@dataclass
class DTOField:
    """For configuring DTO behavior on model fields."""

    mark: Mark | Literal["read-only", "write-only", "private"] | None = None
    """Mark the field as read-only, or private."""


[docs] def dto_field(mark: Literal["read-only", "write-only", "private"] | Mark) -> dict[str, DTOField]: """Create a field metadata mapping. Args: mark: A DTO mark for the field, e.g., "read-only". Returns: A dict for setting as field metadata, such as the dataclass "metadata" field key, or the SQLAlchemy "info" field. Marking a field automates its inclusion/exclusion from DTO field definitions, depending on the DTO's purpose. """ return {DTO_FIELD_META_KEY: DTOField(mark=Mark(mark))}
def extract_dto_field(field_definition: FieldDefinition, field_info_mapping: Mapping[str, Any]) -> DTOField: """Extract ``DTOField`` instance for a model field. Supports ``DTOField`` to bet set via ``Annotated`` or via a field info/metadata mapping. E.g., ``Annotated[str, DTOField(mark="read-only")]`` or ``info=dto_field(mark="read-only")``. If a value is found in ``field_info_mapping``, it is prioritized over the field definition's metadata. Args: field_definition: A field definition. field_info_mapping: A field metadata/info attribute mapping, e.g., SQLAlchemy's ``info`` attribute, or dataclasses ``metadata`` attribute. Returns: DTO field info, if any. """ if inst := field_info_mapping.get(DTO_FIELD_META_KEY): if not isinstance(inst, DTOField): raise ImproperlyConfiguredException(f"DTO field info must be an instance of DTOField, got '{inst}'") return inst return next((f for f in field_definition.metadata if isinstance(f, DTOField)), DTOField())