from __future__ import annotations from typing import TYPE_CHECKING, Any from attrs import NOTHING, Attribute, Factory from .._compat import get_args, is_annotated, is_bare_final from ..dispatch import StructureHook from ..errors import StructureHandlerNotFoundError from ..fns import raise_error from ._consts import AttributeOverride if TYPE_CHECKING: from ..converters import BaseConverter def _annotated_override_or_default( type: Any, default: AttributeOverride ) -> AttributeOverride: """ If the type is Annotated containing an AttributeOverride, return it. Otherwise, return the default. """ if is_annotated(type): for arg in get_args(type): if isinstance(arg, AttributeOverride): return arg return default def find_structure_handler( a: Attribute, type: Any, c: BaseConverter, prefer_attrs_converters: bool = False ) -> StructureHook | None: """Find the appropriate structure handler to use. Return `None` if no handler should be used. """ try: if a.converter is not None and prefer_attrs_converters: # If the user as requested to use attrib converters, use nothing # so it falls back to that. handler = None elif ( a.converter is not None and not prefer_attrs_converters and type is not None ): try: handler = c.get_structure_hook(type, cache_result=False) except StructureHandlerNotFoundError: handler = None else: # The legacy way, should still work. if handler == raise_error: handler = None elif type is not None: if ( is_bare_final(type) and a.default is not NOTHING and not isinstance(a.default, Factory) ): # This is a special case where we can use the # type of the default to dispatch on. type = a.default.__class__ handler = c.get_structure_hook(type, cache_result=False) if handler == c._structure_call: # Finals can't really be used with _structure_call, so # we wrap it so the rest of the toolchain doesn't get # confused. def handler(v, _, _h=handler): return _h(v, type) else: handler = c.get_structure_hook(type, cache_result=False) else: handler = c.structure return handler except RecursionError: # This means we're dealing with a reference cycle, so use late binding. return c.structure