about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/pydantic/v1/generics.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/pydantic/v1/generics.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-4a52a71956a8d46fcb7294ac71734504bb09bcc2.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/pydantic/v1/generics.py')
-rw-r--r--.venv/lib/python3.12/site-packages/pydantic/v1/generics.py400
1 files changed, 400 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/pydantic/v1/generics.py b/.venv/lib/python3.12/site-packages/pydantic/v1/generics.py
new file mode 100644
index 00000000..9a69f2b3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pydantic/v1/generics.py
@@ -0,0 +1,400 @@
+import sys
+import types
+import typing
+from typing import (
+    TYPE_CHECKING,
+    Any,
+    ClassVar,
+    Dict,
+    ForwardRef,
+    Generic,
+    Iterator,
+    List,
+    Mapping,
+    Optional,
+    Tuple,
+    Type,
+    TypeVar,
+    Union,
+    cast,
+)
+from weakref import WeakKeyDictionary, WeakValueDictionary
+
+from typing_extensions import Annotated, Literal as ExtLiteral
+
+from pydantic.v1.class_validators import gather_all_validators
+from pydantic.v1.fields import DeferredType
+from pydantic.v1.main import BaseModel, create_model
+from pydantic.v1.types import JsonWrapper
+from pydantic.v1.typing import display_as_type, get_all_type_hints, get_args, get_origin, typing_base
+from pydantic.v1.utils import all_identical, lenient_issubclass
+
+if sys.version_info >= (3, 10):
+    from typing import _UnionGenericAlias
+if sys.version_info >= (3, 8):
+    from typing import Literal
+
+GenericModelT = TypeVar('GenericModelT', bound='GenericModel')
+TypeVarType = Any  # since mypy doesn't allow the use of TypeVar as a type
+
+CacheKey = Tuple[Type[Any], Any, Tuple[Any, ...]]
+Parametrization = Mapping[TypeVarType, Type[Any]]
+
+# weak dictionaries allow the dynamically created parametrized versions of generic models to get collected
+# once they are no longer referenced by the caller.
+if sys.version_info >= (3, 9):  # Typing for weak dictionaries available at 3.9
+    GenericTypesCache = WeakValueDictionary[CacheKey, Type[BaseModel]]
+    AssignedParameters = WeakKeyDictionary[Type[BaseModel], Parametrization]
+else:
+    GenericTypesCache = WeakValueDictionary
+    AssignedParameters = WeakKeyDictionary
+
+# _generic_types_cache is a Mapping from __class_getitem__ arguments to the parametrized version of generic models.
+# This ensures multiple calls of e.g. A[B] return always the same class.
+_generic_types_cache = GenericTypesCache()
+
+# _assigned_parameters is a Mapping from parametrized version of generic models to assigned types of parametrizations
+# as captured during construction of the class (not instances).
+# E.g., for generic model `Model[A, B]`, when parametrized model `Model[int, str]` is created,
+# `Model[int, str]`: {A: int, B: str}` will be stored in `_assigned_parameters`.
+# (This information is only otherwise available after creation from the class name string).
+_assigned_parameters = AssignedParameters()
+
+
+class GenericModel(BaseModel):
+    __slots__ = ()
+    __concrete__: ClassVar[bool] = False
+
+    if TYPE_CHECKING:
+        # Putting this in a TYPE_CHECKING block allows us to replace `if Generic not in cls.__bases__` with
+        # `not hasattr(cls, "__parameters__")`. This means we don't need to force non-concrete subclasses of
+        # `GenericModel` to also inherit from `Generic`, which would require changes to the use of `create_model` below.
+        __parameters__: ClassVar[Tuple[TypeVarType, ...]]
+
+    # Setting the return type as Type[Any] instead of Type[BaseModel] prevents PyCharm warnings
+    def __class_getitem__(cls: Type[GenericModelT], params: Union[Type[Any], Tuple[Type[Any], ...]]) -> Type[Any]:
+        """Instantiates a new class from a generic class `cls` and type variables `params`.
+
+        :param params: Tuple of types the class . Given a generic class
+            `Model` with 2 type variables and a concrete model `Model[str, int]`,
+            the value `(str, int)` would be passed to `params`.
+        :return: New model class inheriting from `cls` with instantiated
+            types described by `params`. If no parameters are given, `cls` is
+            returned as is.
+
+        """
+
+        def _cache_key(_params: Any) -> CacheKey:
+            args = get_args(_params)
+            # python returns a list for Callables, which is not hashable
+            if len(args) == 2 and isinstance(args[0], list):
+                args = (tuple(args[0]), args[1])
+            return cls, _params, args
+
+        cached = _generic_types_cache.get(_cache_key(params))
+        if cached is not None:
+            return cached
+        if cls.__concrete__ and Generic not in cls.__bases__:
+            raise TypeError('Cannot parameterize a concrete instantiation of a generic model')
+        if not isinstance(params, tuple):
+            params = (params,)
+        if cls is GenericModel and any(isinstance(param, TypeVar) for param in params):
+            raise TypeError('Type parameters should be placed on typing.Generic, not GenericModel')
+        if not hasattr(cls, '__parameters__'):
+            raise TypeError(f'Type {cls.__name__} must inherit from typing.Generic before being parameterized')
+
+        check_parameters_count(cls, params)
+        # Build map from generic typevars to passed params
+        typevars_map: Dict[TypeVarType, Type[Any]] = dict(zip(cls.__parameters__, params))
+        if all_identical(typevars_map.keys(), typevars_map.values()) and typevars_map:
+            return cls  # if arguments are equal to parameters it's the same object
+
+        # Create new model with original model as parent inserting fields with DeferredType.
+        model_name = cls.__concrete_name__(params)
+        validators = gather_all_validators(cls)
+
+        type_hints = get_all_type_hints(cls).items()
+        instance_type_hints = {k: v for k, v in type_hints if get_origin(v) is not ClassVar}
+
+        fields = {k: (DeferredType(), cls.__fields__[k].field_info) for k in instance_type_hints if k in cls.__fields__}
+
+        model_module, called_globally = get_caller_frame_info()
+        created_model = cast(
+            Type[GenericModel],  # casting ensures mypy is aware of the __concrete__ and __parameters__ attributes
+            create_model(
+                model_name,
+                __module__=model_module or cls.__module__,
+                __base__=(cls,) + tuple(cls.__parameterized_bases__(typevars_map)),
+                __config__=None,
+                __validators__=validators,
+                __cls_kwargs__=None,
+                **fields,
+            ),
+        )
+
+        _assigned_parameters[created_model] = typevars_map
+
+        if called_globally:  # create global reference and therefore allow pickling
+            object_by_reference = None
+            reference_name = model_name
+            reference_module_globals = sys.modules[created_model.__module__].__dict__
+            while object_by_reference is not created_model:
+                object_by_reference = reference_module_globals.setdefault(reference_name, created_model)
+                reference_name += '_'
+
+        created_model.Config = cls.Config
+
+        # Find any typevars that are still present in the model.
+        # If none are left, the model is fully "concrete", otherwise the new
+        # class is a generic class as well taking the found typevars as
+        # parameters.
+        new_params = tuple(
+            {param: None for param in iter_contained_typevars(typevars_map.values())}
+        )  # use dict as ordered set
+        created_model.__concrete__ = not new_params
+        if new_params:
+            created_model.__parameters__ = new_params
+
+        # Save created model in cache so we don't end up creating duplicate
+        # models that should be identical.
+        _generic_types_cache[_cache_key(params)] = created_model
+        if len(params) == 1:
+            _generic_types_cache[_cache_key(params[0])] = created_model
+
+        # Recursively walk class type hints and replace generic typevars
+        # with concrete types that were passed.
+        _prepare_model_fields(created_model, fields, instance_type_hints, typevars_map)
+
+        return created_model
+
+    @classmethod
+    def __concrete_name__(cls: Type[Any], params: Tuple[Type[Any], ...]) -> str:
+        """Compute class name for child classes.
+
+        :param params: Tuple of types the class . Given a generic class
+            `Model` with 2 type variables and a concrete model `Model[str, int]`,
+            the value `(str, int)` would be passed to `params`.
+        :return: String representing a the new class where `params` are
+            passed to `cls` as type variables.
+
+        This method can be overridden to achieve a custom naming scheme for GenericModels.
+        """
+        param_names = [display_as_type(param) for param in params]
+        params_component = ', '.join(param_names)
+        return f'{cls.__name__}[{params_component}]'
+
+    @classmethod
+    def __parameterized_bases__(cls, typevars_map: Parametrization) -> Iterator[Type[Any]]:
+        """
+        Returns unbound bases of cls parameterised to given type variables
+
+        :param typevars_map: Dictionary of type applications for binding subclasses.
+            Given a generic class `Model` with 2 type variables [S, T]
+            and a concrete model `Model[str, int]`,
+            the value `{S: str, T: int}` would be passed to `typevars_map`.
+        :return: an iterator of generic sub classes, parameterised by `typevars_map`
+            and other assigned parameters of `cls`
+
+        e.g.:
+        ```
+        class A(GenericModel, Generic[T]):
+            ...
+
+        class B(A[V], Generic[V]):
+            ...
+
+        assert A[int] in B.__parameterized_bases__({V: int})
+        ```
+        """
+
+        def build_base_model(
+            base_model: Type[GenericModel], mapped_types: Parametrization
+        ) -> Iterator[Type[GenericModel]]:
+            base_parameters = tuple(mapped_types[param] for param in base_model.__parameters__)
+            parameterized_base = base_model.__class_getitem__(base_parameters)
+            if parameterized_base is base_model or parameterized_base is cls:
+                # Avoid duplication in MRO
+                return
+            yield parameterized_base
+
+        for base_model in cls.__bases__:
+            if not issubclass(base_model, GenericModel):
+                # not a class that can be meaningfully parameterized
+                continue
+            elif not getattr(base_model, '__parameters__', None):
+                # base_model is "GenericModel"  (and has no __parameters__)
+                # or
+                # base_model is already concrete, and will be included transitively via cls.
+                continue
+            elif cls in _assigned_parameters:
+                if base_model in _assigned_parameters:
+                    # cls is partially parameterised but not from base_model
+                    # e.g. cls = B[S], base_model = A[S]
+                    # B[S][int] should subclass A[int],  (and will be transitively via B[int])
+                    # but it's not viable to consistently subclass types with arbitrary construction
+                    # So don't attempt to include A[S][int]
+                    continue
+                else:  # base_model not in _assigned_parameters:
+                    # cls is partially parameterized, base_model is original generic
+                    # e.g.  cls = B[str, T], base_model = B[S, T]
+                    # Need to determine the mapping for the base_model parameters
+                    mapped_types: Parametrization = {
+                        key: typevars_map.get(value, value) for key, value in _assigned_parameters[cls].items()
+                    }
+                    yield from build_base_model(base_model, mapped_types)
+            else:
+                # cls is base generic, so base_class has a distinct base
+                # can construct the Parameterised base model using typevars_map directly
+                yield from build_base_model(base_model, typevars_map)
+
+
+def replace_types(type_: Any, type_map: Mapping[Any, Any]) -> Any:
+    """Return type with all occurrences of `type_map` keys recursively replaced with their values.
+
+    :param type_: Any type, class or generic alias
+    :param type_map: Mapping from `TypeVar` instance to concrete types.
+    :return: New type representing the basic structure of `type_` with all
+        `typevar_map` keys recursively replaced.
+
+    >>> replace_types(Tuple[str, Union[List[str], float]], {str: int})
+    Tuple[int, Union[List[int], float]]
+
+    """
+    if not type_map:
+        return type_
+
+    type_args = get_args(type_)
+    origin_type = get_origin(type_)
+
+    if origin_type is Annotated:
+        annotated_type, *annotations = type_args
+        return Annotated[replace_types(annotated_type, type_map), tuple(annotations)]
+
+    if (origin_type is ExtLiteral) or (sys.version_info >= (3, 8) and origin_type is Literal):
+        return type_map.get(type_, type_)
+    # Having type args is a good indicator that this is a typing module
+    # class instantiation or a generic alias of some sort.
+    if type_args:
+        resolved_type_args = tuple(replace_types(arg, type_map) for arg in type_args)
+        if all_identical(type_args, resolved_type_args):
+            # If all arguments are the same, there is no need to modify the
+            # type or create a new object at all
+            return type_
+        if (
+            origin_type is not None
+            and isinstance(type_, typing_base)
+            and not isinstance(origin_type, typing_base)
+            and getattr(type_, '_name', None) is not None
+        ):
+            # In python < 3.9 generic aliases don't exist so any of these like `list`,
+            # `type` or `collections.abc.Callable` need to be translated.
+            # See: https://www.python.org/dev/peps/pep-0585
+            origin_type = getattr(typing, type_._name)
+        assert origin_type is not None
+        # PEP-604 syntax (Ex.: list | str) is represented with a types.UnionType object that does not have __getitem__.
+        # We also cannot use isinstance() since we have to compare types.
+        if sys.version_info >= (3, 10) and origin_type is types.UnionType:  # noqa: E721
+            return _UnionGenericAlias(origin_type, resolved_type_args)
+        return origin_type[resolved_type_args]
+
+    # We handle pydantic generic models separately as they don't have the same
+    # semantics as "typing" classes or generic aliases
+    if not origin_type and lenient_issubclass(type_, GenericModel) and not type_.__concrete__:
+        type_args = type_.__parameters__
+        resolved_type_args = tuple(replace_types(t, type_map) for t in type_args)
+        if all_identical(type_args, resolved_type_args):
+            return type_
+        return type_[resolved_type_args]
+
+    # Handle special case for typehints that can have lists as arguments.
+    # `typing.Callable[[int, str], int]` is an example for this.
+    if isinstance(type_, (List, list)):
+        resolved_list = list(replace_types(element, type_map) for element in type_)
+        if all_identical(type_, resolved_list):
+            return type_
+        return resolved_list
+
+    # For JsonWrapperValue, need to handle its inner type to allow correct parsing
+    # of generic Json arguments like Json[T]
+    if not origin_type and lenient_issubclass(type_, JsonWrapper):
+        type_.inner_type = replace_types(type_.inner_type, type_map)
+        return type_
+
+    # If all else fails, we try to resolve the type directly and otherwise just
+    # return the input with no modifications.
+    new_type = type_map.get(type_, type_)
+    # Convert string to ForwardRef
+    if isinstance(new_type, str):
+        return ForwardRef(new_type)
+    else:
+        return new_type
+
+
+def check_parameters_count(cls: Type[GenericModel], parameters: Tuple[Any, ...]) -> None:
+    actual = len(parameters)
+    expected = len(cls.__parameters__)
+    if actual != expected:
+        description = 'many' if actual > expected else 'few'
+        raise TypeError(f'Too {description} parameters for {cls.__name__}; actual {actual}, expected {expected}')
+
+
+DictValues: Type[Any] = {}.values().__class__
+
+
+def iter_contained_typevars(v: Any) -> Iterator[TypeVarType]:
+    """Recursively iterate through all subtypes and type args of `v` and yield any typevars that are found."""
+    if isinstance(v, TypeVar):
+        yield v
+    elif hasattr(v, '__parameters__') and not get_origin(v) and lenient_issubclass(v, GenericModel):
+        yield from v.__parameters__
+    elif isinstance(v, (DictValues, list)):
+        for var in v:
+            yield from iter_contained_typevars(var)
+    else:
+        args = get_args(v)
+        for arg in args:
+            yield from iter_contained_typevars(arg)
+
+
+def get_caller_frame_info() -> Tuple[Optional[str], bool]:
+    """
+    Used inside a function to check whether it was called globally
+
+    Will only work against non-compiled code, therefore used only in pydantic.generics
+
+    :returns Tuple[module_name, called_globally]
+    """
+    try:
+        previous_caller_frame = sys._getframe(2)
+    except ValueError as e:
+        raise RuntimeError('This function must be used inside another function') from e
+    except AttributeError:  # sys module does not have _getframe function, so there's nothing we can do about it
+        return None, False
+    frame_globals = previous_caller_frame.f_globals
+    return frame_globals.get('__name__'), previous_caller_frame.f_locals is frame_globals
+
+
+def _prepare_model_fields(
+    created_model: Type[GenericModel],
+    fields: Mapping[str, Any],
+    instance_type_hints: Mapping[str, type],
+    typevars_map: Mapping[Any, type],
+) -> None:
+    """
+    Replace DeferredType fields with concrete type hints and prepare them.
+    """
+
+    for key, field in created_model.__fields__.items():
+        if key not in fields:
+            assert field.type_.__class__ is not DeferredType
+            # https://github.com/nedbat/coveragepy/issues/198
+            continue  # pragma: no cover
+
+        assert field.type_.__class__ is DeferredType, field.type_.__class__
+
+        field_type_hint = instance_type_hints[key]
+        concrete_type = replace_types(field_type_hint, typevars_map)
+        field.type_ = concrete_type
+        field.outer_type_ = concrete_type
+        field.prepare()
+        created_model.__annotations__[key] = concrete_type