Source code for litestar.plugins.attrs

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from typing_extensions import TypeGuard

from litestar.exceptions import MissingDependencyException
from litestar.plugins import OpenAPISchemaPlugin
from litestar.types import Empty
from litestar.typing import FieldDefinition
from litestar.utils import is_optional_union

try:
    import attr
    import attrs
except ImportError as e:
    raise MissingDependencyException("attrs") from e

if TYPE_CHECKING:
    from litestar._openapi.schema_generation import SchemaCreator
    from litestar.openapi.spec import Schema

__all__ = ("AttrsSchemaPlugin", "is_attrs_class")


[docs] class AttrsSchemaPlugin(OpenAPISchemaPlugin):
[docs] @staticmethod def is_plugin_supported_type(value: Any) -> bool: return is_attrs_class(value) or is_attrs_class(type(value))
[docs] def to_openapi_schema(self, field_definition: FieldDefinition, schema_creator: SchemaCreator) -> Schema: """Given a type annotation, transform it into an OpenAPI schema class. Args: field_definition: FieldDefinition instance. schema_creator: An instance of the schema creator class Returns: An :class:`OpenAPI <litestar.openapi.spec.schema.Schema>` instance. """ type_hints = field_definition.get_type_hints(include_extras=True, resolve_generics=True) attr_fields = attr.fields_dict(field_definition.type_) return schema_creator.create_component_schema( field_definition, required=sorted( field_name for field_name, attribute in attr_fields.items() if attribute.default is attrs.NOTHING and not is_optional_union(type_hints[field_name]) ), property_fields={ field_name: FieldDefinition.from_kwarg(type_hints[field_name], field_name) for field_name in attr_fields }, )
[docs] def is_attrs_class(annotation: Any) -> TypeGuard[type[attrs.AttrsInstance]]: # pyright: ignore """Given a type annotation determine if the annotation is a class that includes an attrs attribute. Args: annotation: A type. Returns: A typeguard determining whether the type is an attrs class. """ return attrs.has(annotation) if attrs is not Empty else False # type: ignore[comparison-overlap]