summaryrefslogtreecommitdiff
path: root/venv/lib/python3.11/site-packages/polyfactory/utils
diff options
context:
space:
mode:
authorcyfraeviolae <cyfraeviolae>2024-04-03 03:10:44 -0400
committercyfraeviolae <cyfraeviolae>2024-04-03 03:10:44 -0400
commit6d7ba58f880be618ade07f8ea080fe8c4bf8a896 (patch)
treeb1c931051ffcebd2bd9d61d98d6233ffa289bbce /venv/lib/python3.11/site-packages/polyfactory/utils
parent4f884c9abc32990b4061a1bb6997b4b37e58ea0b (diff)
venv
Diffstat (limited to 'venv/lib/python3.11/site-packages/polyfactory/utils')
-rw-r--r--venv/lib/python3.11/site-packages/polyfactory/utils/__init__.py0
-rw-r--r--venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/__init__.cpython-311.pycbin0 -> 201 bytes
-rw-r--r--venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/deprecation.cpython-311.pycbin0 -> 6309 bytes
-rw-r--r--venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/helpers.cpython-311.pycbin0 -> 9079 bytes
-rw-r--r--venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/model_coverage.cpython-311.pycbin0 -> 8226 bytes
-rw-r--r--venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/predicates.cpython-311.pycbin0 -> 6304 bytes
-rw-r--r--venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/types.cpython-311.pycbin0 -> 532 bytes
-rw-r--r--venv/lib/python3.11/site-packages/polyfactory/utils/deprecation.py149
-rw-r--r--venv/lib/python3.11/site-packages/polyfactory/utils/helpers.py196
-rw-r--r--venv/lib/python3.11/site-packages/polyfactory/utils/model_coverage.py146
-rw-r--r--venv/lib/python3.11/site-packages/polyfactory/utils/predicates.py134
-rw-r--r--venv/lib/python3.11/site-packages/polyfactory/utils/types.py12
12 files changed, 637 insertions, 0 deletions
diff --git a/venv/lib/python3.11/site-packages/polyfactory/utils/__init__.py b/venv/lib/python3.11/site-packages/polyfactory/utils/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/polyfactory/utils/__init__.py
diff --git a/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..6297806
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/__init__.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/deprecation.cpython-311.pyc b/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/deprecation.cpython-311.pyc
new file mode 100644
index 0000000..8f43f83
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/deprecation.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/helpers.cpython-311.pyc b/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/helpers.cpython-311.pyc
new file mode 100644
index 0000000..982e068
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/helpers.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/model_coverage.cpython-311.pyc b/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/model_coverage.cpython-311.pyc
new file mode 100644
index 0000000..22c475b
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/model_coverage.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/predicates.cpython-311.pyc b/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/predicates.cpython-311.pyc
new file mode 100644
index 0000000..c1908b6
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/predicates.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/types.cpython-311.pyc b/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/types.cpython-311.pyc
new file mode 100644
index 0000000..59b2b6a
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/polyfactory/utils/__pycache__/types.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/polyfactory/utils/deprecation.py b/venv/lib/python3.11/site-packages/polyfactory/utils/deprecation.py
new file mode 100644
index 0000000..576c4ac
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/polyfactory/utils/deprecation.py
@@ -0,0 +1,149 @@
+from __future__ import annotations
+
+import inspect
+from functools import wraps
+from typing import Any, Callable, Literal, TypeVar
+from warnings import warn
+
+from typing_extensions import ParamSpec
+
+__all__ = ("deprecated", "warn_deprecation", "check_for_deprecated_parameters")
+
+
+T = TypeVar("T")
+P = ParamSpec("P")
+DeprecatedKind = Literal["function", "method", "classmethod", "attribute", "property", "class", "parameter", "import"]
+
+
+def warn_deprecation(
+ version: str,
+ deprecated_name: str,
+ kind: DeprecatedKind,
+ *,
+ removal_in: str | None = None,
+ alternative: str | None = None,
+ info: str | None = None,
+ pending: bool = False,
+) -> None:
+ """Warn about a call to a (soon to be) deprecated function.
+
+ Args:
+ version: Polyfactory version where the deprecation will occur.
+ deprecated_name: Name of the deprecated function.
+ removal_in: Polyfactory version where the deprecated function will be removed.
+ alternative: Name of a function that should be used instead.
+ info: Additional information.
+ pending: Use ``PendingDeprecationWarning`` instead of ``DeprecationWarning``.
+ kind: Type of the deprecated thing.
+ """
+ parts = []
+
+ if kind == "import":
+ access_type = "Import of"
+ elif kind in {"function", "method"}:
+ access_type = "Call to"
+ else:
+ access_type = "Use of"
+
+ if pending:
+ parts.append(f"{access_type} {kind} awaiting deprecation {deprecated_name!r}")
+ else:
+ parts.append(f"{access_type} deprecated {kind} {deprecated_name!r}")
+
+ parts.extend(
+ (
+ f"Deprecated in polyfactory {version}",
+ f"This {kind} will be removed in {removal_in or 'the next major version'}",
+ ) # noqa: COM812
+ )
+ if alternative:
+ parts.append(f"Use {alternative!r} instead")
+
+ if info:
+ parts.append(info)
+
+ text = ". ".join(parts)
+ warning_class = PendingDeprecationWarning if pending else DeprecationWarning
+
+ warn(text, warning_class, stacklevel=2)
+
+
+def deprecated(
+ version: str,
+ *,
+ removal_in: str | None = None,
+ alternative: str | None = None,
+ info: str | None = None,
+ pending: bool = False,
+ kind: Literal["function", "method", "classmethod", "property"] | None = None,
+) -> Callable[[Callable[P, T]], Callable[P, T]]:
+ """Create a decorator wrapping a function, method or property with a warning call about a (pending) deprecation.
+
+ Args:
+ version: Polyfactory version where the deprecation will occur.
+ removal_in: Polyfactory version where the deprecated function will be removed.
+ alternative: Name of a function that should be used instead.
+ info: Additional information.
+ pending: Use ``PendingDeprecationWarning`` instead of ``DeprecationWarning``.
+ kind: Type of the deprecated callable. If ``None``, will use ``inspect`` to figure
+ out if it's a function or method.
+
+ Returns:
+ A decorator wrapping the function call with a warning
+ """
+
+ def decorator(func: Callable[P, T]) -> Callable[P, T]:
+ @wraps(func)
+ def wrapped(*args: P.args, **kwargs: P.kwargs) -> T:
+ warn_deprecation(
+ version=version,
+ deprecated_name=func.__name__,
+ info=info,
+ alternative=alternative,
+ pending=pending,
+ removal_in=removal_in,
+ kind=kind or ("method" if inspect.ismethod(func) else "function"),
+ )
+ return func(*args, **kwargs)
+
+ return wrapped
+
+ return decorator
+
+
+def check_for_deprecated_parameters(
+ version: str,
+ *,
+ parameters: tuple[tuple[str, Any], ...],
+ default_value: Any = None,
+ removal_in: str | None = None,
+ alternative: str | None = None,
+ info: str | None = None,
+ pending: bool = False,
+) -> None:
+ """Warn about a call to a (soon to be) deprecated argument to a function.
+
+ Args:
+ version: Polyfactory version where the deprecation will occur.
+ parameters: Parameters to trigger warning if used.
+ default_value: Default value for parameter to detect if supplied or not.
+ removal_in: Polyfactory version where the deprecated function will be removed.
+ alternative: Name of a function that should be used instead.
+ info: Additional information.
+ pending: Use ``PendingDeprecationWarning`` instead of ``DeprecationWarning``.
+ kind: Type of the deprecated callable. If ``None``, will use ``inspect`` to figure
+ out if it's a function or method.
+ """
+ for parameter_name, value in parameters:
+ if value == default_value:
+ continue
+
+ warn_deprecation(
+ version=version,
+ deprecated_name=parameter_name,
+ info=info,
+ alternative=alternative,
+ pending=pending,
+ removal_in=removal_in,
+ kind="parameter",
+ )
diff --git a/venv/lib/python3.11/site-packages/polyfactory/utils/helpers.py b/venv/lib/python3.11/site-packages/polyfactory/utils/helpers.py
new file mode 100644
index 0000000..f9924bb
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/polyfactory/utils/helpers.py
@@ -0,0 +1,196 @@
+from __future__ import annotations
+
+import sys
+from typing import TYPE_CHECKING, Any, Mapping
+
+from typing_extensions import TypeAliasType, get_args, get_origin
+
+from polyfactory.constants import TYPE_MAPPING
+from polyfactory.utils.predicates import is_annotated, is_new_type, is_optional, is_safe_subclass, is_union
+from polyfactory.utils.types import NoneType
+
+if TYPE_CHECKING:
+ from random import Random
+ from typing import Sequence
+
+
+def unwrap_new_type(annotation: Any) -> Any:
+ """Return base type if given annotation is a type derived with NewType, otherwise annotation.
+
+ :param annotation: A type annotation, possibly one created using 'types.NewType'
+
+ :returns: The unwrapped annotation.
+ """
+ while is_new_type(annotation):
+ annotation = annotation.__supertype__
+
+ return annotation
+
+
+def unwrap_union(annotation: Any, random: Random) -> Any:
+ """Unwraps union types - recursively.
+
+ :param annotation: A type annotation, possibly a type union.
+ :param random: An instance of random.Random.
+ :returns: A type annotation
+ """
+ while is_union(annotation):
+ args = list(get_args(annotation))
+ annotation = random.choice(args)
+ return annotation
+
+
+def unwrap_optional(annotation: Any) -> Any:
+ """Unwraps optional union types - recursively.
+
+ :param annotation: A type annotation, possibly an optional union.
+
+ :returns: A type annotation
+ """
+ while is_optional(annotation):
+ annotation = next(arg for arg in get_args(annotation) if arg not in (NoneType, None))
+ return annotation
+
+
+def unwrap_annotation(annotation: Any, random: Random) -> Any:
+ """Unwraps an annotation.
+
+ :param annotation: A type annotation.
+ :param random: An instance of random.Random.
+
+ :returns: The unwrapped annotation.
+
+ """
+ while (
+ is_optional(annotation)
+ or is_union(annotation)
+ or is_new_type(annotation)
+ or is_annotated(annotation)
+ or isinstance(annotation, TypeAliasType)
+ ):
+ if is_new_type(annotation):
+ annotation = unwrap_new_type(annotation)
+ elif is_optional(annotation):
+ annotation = unwrap_optional(annotation)
+ elif is_annotated(annotation):
+ annotation = unwrap_annotated(annotation, random=random)[0]
+ elif isinstance(annotation, TypeAliasType):
+ annotation = annotation.__value__
+ else:
+ annotation = unwrap_union(annotation, random=random)
+
+ return annotation
+
+
+def flatten_annotation(annotation: Any) -> list[Any]:
+ """Flattens an annotation.
+
+ :param annotation: A type annotation.
+
+ :returns: The flattened annotations.
+ """
+ flat = []
+ if is_new_type(annotation):
+ flat.extend(flatten_annotation(unwrap_new_type(annotation)))
+ elif is_optional(annotation):
+ for a in get_args(annotation):
+ flat.extend(flatten_annotation(a))
+ elif is_annotated(annotation):
+ flat.extend(flatten_annotation(get_args(annotation)[0]))
+ elif is_union(annotation):
+ for a in get_args(annotation):
+ flat.extend(flatten_annotation(a))
+ else:
+ flat.append(annotation)
+
+ return flat
+
+
+def unwrap_args(annotation: Any, random: Random) -> tuple[Any, ...]:
+ """Unwrap the annotation and return any type args.
+
+ :param annotation: A type annotation
+ :param random: An instance of random.Random.
+
+ :returns: A tuple of type args.
+
+ """
+
+ return get_args(unwrap_annotation(annotation=annotation, random=random))
+
+
+def unwrap_annotated(annotation: Any, random: Random) -> tuple[Any, list[Any]]:
+ """Unwrap an annotated type and return a tuple of type args and optional metadata.
+
+ :param annotation: An annotated type annotation
+ :param random: An instance of random.Random.
+
+ :returns: A tuple of type args.
+
+ """
+ args = [arg for arg in get_args(annotation) if arg is not None]
+ return unwrap_annotation(args[0], random=random), args[1:]
+
+
+def normalize_annotation(annotation: Any, random: Random) -> Any:
+ """Normalize an annotation.
+
+ :param annotation: A type annotation.
+
+ :returns: A normalized type annotation.
+
+ """
+ if is_new_type(annotation):
+ annotation = unwrap_new_type(annotation)
+
+ if is_annotated(annotation):
+ annotation = unwrap_annotated(annotation, random=random)[0]
+
+ # we have to maintain compatibility with the older non-subscriptable typings.
+ if sys.version_info <= (3, 9): # pragma: no cover
+ return annotation
+
+ origin = get_origin(annotation) or annotation
+
+ if origin in TYPE_MAPPING:
+ origin = TYPE_MAPPING[origin]
+
+ if args := get_args(annotation):
+ args = tuple(normalize_annotation(arg, random=random) for arg in args)
+ return origin[args] if origin is not type else annotation
+
+ return origin
+
+
+def get_annotation_metadata(annotation: Any) -> Sequence[Any]:
+ """Get the metadata in the annotation.
+
+ :param annotation: A type annotation.
+
+ :returns: The metadata.
+ """
+
+ return get_args(annotation)[1:]
+
+
+def get_collection_type(annotation: Any) -> type[list | tuple | set | frozenset | dict]:
+ """Get the collection type from the annotation.
+
+ :param annotation: A type annotation.
+
+ :returns: The collection type.
+ """
+
+ if is_safe_subclass(annotation, list):
+ return list
+ if is_safe_subclass(annotation, Mapping):
+ return dict
+ if is_safe_subclass(annotation, tuple):
+ return tuple
+ if is_safe_subclass(annotation, set):
+ return set
+ if is_safe_subclass(annotation, frozenset):
+ return frozenset
+
+ msg = f"Unknown collection type - {annotation}"
+ raise ValueError(msg)
diff --git a/venv/lib/python3.11/site-packages/polyfactory/utils/model_coverage.py b/venv/lib/python3.11/site-packages/polyfactory/utils/model_coverage.py
new file mode 100644
index 0000000..6fc3971
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/polyfactory/utils/model_coverage.py
@@ -0,0 +1,146 @@
+from __future__ import annotations
+
+from abc import ABC, abstractmethod
+from collections.abc import Callable, Iterable, Iterator, Mapping, MutableSequence
+from typing import AbstractSet, Any, Generic, Set, TypeVar, cast
+
+from typing_extensions import ParamSpec
+
+from polyfactory.exceptions import ParameterException
+
+
+class CoverageContainerBase(ABC):
+ """Base class for coverage container implementations.
+
+ A coverage container is a wrapper providing values for a particular field. Coverage containers return field values and
+ track a "done" state to indicate that all coverage examples have been generated.
+ """
+
+ @abstractmethod
+ def next_value(self) -> Any:
+ """Provide the next value"""
+ ...
+
+ @abstractmethod
+ def is_done(self) -> bool:
+ """Indicate if this container has provided every coverage example it has"""
+ ...
+
+
+T = TypeVar("T")
+
+
+class CoverageContainer(CoverageContainerBase, Generic[T]):
+ """A coverage container that wraps a collection of values.
+
+ When calling ``next_value()`` a greater number of times than the length of the given collection will cause duplicate
+ examples to be returned (wraps around).
+
+ If there are any coverage containers within the given collection, the values from those containers are essentially merged
+ into the parent container.
+ """
+
+ def __init__(self, instances: Iterable[T]) -> None:
+ self._pos = 0
+ self._instances = list(instances)
+ if not self._instances:
+ msg = "CoverageContainer must have at least one instance"
+ raise ValueError(msg)
+
+ def next_value(self) -> T:
+ value = self._instances[self._pos % len(self._instances)]
+ if isinstance(value, CoverageContainerBase):
+ result = value.next_value()
+ if value.is_done():
+ # Only move onto the next instance if the sub-container is done
+ self._pos += 1
+ return cast(T, result)
+
+ self._pos += 1
+ return value
+
+ def is_done(self) -> bool:
+ return self._pos >= len(self._instances)
+
+ def __repr__(self) -> str:
+ return f"CoverageContainer(instances={self._instances}, is_done={self.is_done()})"
+
+
+P = ParamSpec("P")
+
+
+class CoverageContainerCallable(CoverageContainerBase, Generic[T]):
+ """A coverage container that wraps a callable.
+
+ When calling ``next_value()`` the wrapped callable is called to provide a value.
+ """
+
+ def __init__(self, func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> None:
+ self._func = func
+ self._args = args
+ self._kwargs = kwargs
+
+ def next_value(self) -> T:
+ try:
+ return self._func(*self._args, **self._kwargs)
+ except Exception as e: # noqa: BLE001
+ msg = f"Unsupported type: {self._func!r}\n\nEither extend the providers map or add a factory function for this type."
+ raise ParameterException(msg) from e
+
+ def is_done(self) -> bool:
+ return True
+
+
+def _resolve_next(unresolved: Any) -> tuple[Any, bool]: # noqa: C901
+ if isinstance(unresolved, CoverageContainerBase):
+ result, done = _resolve_next(unresolved.next_value())
+ return result, unresolved.is_done() and done
+
+ if isinstance(unresolved, Mapping):
+ result = {}
+ done_status = True
+ for key, value in unresolved.items():
+ val_resolved, val_done = _resolve_next(value)
+ key_resolved, key_done = _resolve_next(key)
+ result[key_resolved] = val_resolved
+ done_status = done_status and val_done and key_done
+ return result, done_status
+
+ if isinstance(unresolved, (tuple, MutableSequence)):
+ result = []
+ done_status = True
+ for value in unresolved:
+ resolved, done = _resolve_next(value)
+ result.append(resolved)
+ done_status = done_status and done
+ if isinstance(unresolved, tuple):
+ result = tuple(result)
+ return result, done_status
+
+ if isinstance(unresolved, Set):
+ result = type(unresolved)()
+ done_status = True
+ for value in unresolved:
+ resolved, done = _resolve_next(value)
+ result.add(resolved)
+ done_status = done_status and done
+ return result, done_status
+
+ if issubclass(type(unresolved), AbstractSet):
+ result = type(unresolved)()
+ done_status = True
+ resolved_values = []
+ for value in unresolved:
+ resolved, done = _resolve_next(value)
+ resolved_values.append(resolved)
+ done_status = done_status and done
+ return result.union(resolved_values), done_status
+
+ return unresolved, True
+
+
+def resolve_kwargs_coverage(kwargs: dict[str, Any]) -> Iterator[dict[str, Any]]:
+ done = False
+ while not done:
+ resolved, done = _resolve_next(kwargs)
+ yield resolved
diff --git a/venv/lib/python3.11/site-packages/polyfactory/utils/predicates.py b/venv/lib/python3.11/site-packages/polyfactory/utils/predicates.py
new file mode 100644
index 0000000..895e380
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/polyfactory/utils/predicates.py
@@ -0,0 +1,134 @@
+from __future__ import annotations
+
+from inspect import isclass
+from typing import Any, Literal, NewType, Optional, TypeVar, get_args
+
+from typing_extensions import Annotated, NotRequired, ParamSpec, Required, TypeGuard, _AnnotatedAlias, get_origin
+
+from polyfactory.constants import TYPE_MAPPING
+from polyfactory.utils.types import UNION_TYPES, NoneType
+
+P = ParamSpec("P")
+T = TypeVar("T")
+
+
+def is_safe_subclass(annotation: Any, class_or_tuple: type[T] | tuple[type[T], ...]) -> "TypeGuard[type[T]]":
+ """Determine whether a given annotation is a subclass of a give type
+
+ :param annotation: A type annotation.
+ :param class_or_tuple: A potential super class or classes.
+
+ :returns: A typeguard
+ """
+ origin = get_type_origin(annotation)
+ if not origin and not isclass(annotation):
+ return False
+ try:
+ return issubclass(origin or annotation, class_or_tuple)
+ except TypeError: # pragma: no cover
+ return False
+
+
+def is_any(annotation: Any) -> "TypeGuard[Any]":
+ """Determine whether a given annotation is 'typing.Any'.
+
+ :param annotation: A type annotation.
+
+ :returns: A typeguard.
+ """
+ return (
+ annotation is Any
+ or getattr(annotation, "_name", "") == "typing.Any"
+ or (get_origin(annotation) in UNION_TYPES and Any in get_args(annotation))
+ )
+
+
+def is_dict_key_or_value_type(annotation: Any) -> "TypeGuard[Any]":
+ """Determine whether a given annotation is a valid dict key or value type:
+ ``typing.KT`` or ``typing.VT``.
+
+ :returns: A typeguard.
+ """
+ return str(annotation) in {"~KT", "~VT"}
+
+
+def is_union(annotation: Any) -> "TypeGuard[Any]":
+ """Determine whether a given annotation is 'typing.Union'.
+
+ :param annotation: A type annotation.
+
+ :returns: A typeguard.
+ """
+ return get_type_origin(annotation) in UNION_TYPES
+
+
+def is_optional(annotation: Any) -> "TypeGuard[Any | None]":
+ """Determine whether a given annotation is 'typing.Optional'.
+
+ :param annotation: A type annotation.
+
+ :returns: A typeguard.
+ """
+ origin = get_type_origin(annotation)
+ return origin is Optional or (get_origin(annotation) in UNION_TYPES and NoneType in get_args(annotation))
+
+
+def is_literal(annotation: Any) -> bool:
+ """Determine whether a given annotation is 'typing.Literal'.
+
+ :param annotation: A type annotation.
+
+ :returns: A boolean.
+ """
+ return (
+ get_type_origin(annotation) is Literal
+ or repr(annotation).startswith("typing.Literal")
+ or repr(annotation).startswith("typing_extensions.Literal")
+ )
+
+
+def is_new_type(annotation: Any) -> "TypeGuard[type[NewType]]":
+ """Determine whether a given annotation is 'typing.NewType'.
+
+ :param annotation: A type annotation.
+
+ :returns: A typeguard.
+ """
+ return hasattr(annotation, "__supertype__")
+
+
+def is_annotated(annotation: Any) -> bool:
+ """Determine whether a given annotation is 'typing.Annotated'.
+
+ :param annotation: A type annotation.
+
+ :returns: A boolean.
+ """
+ return get_origin(annotation) is Annotated or (
+ isinstance(annotation, _AnnotatedAlias) and getattr(annotation, "__args__", None) is not None
+ )
+
+
+def is_any_annotated(annotation: Any) -> bool:
+ """Determine whether any of the types in the given annotation is
+ `typing.Annotated`.
+
+ :param annotation: A type annotation.
+
+ :returns: A boolean
+ """
+
+ return any(is_annotated(arg) or hasattr(arg, "__args__") and is_any_annotated(arg) for arg in get_args(annotation))
+
+
+def get_type_origin(annotation: Any) -> Any:
+ """Get the type origin of an annotation - safely.
+
+ :param annotation: A type annotation.
+
+ :returns: A type annotation.
+ """
+ origin = get_origin(annotation)
+ if origin in (Annotated, Required, NotRequired):
+ origin = get_args(annotation)[0]
+ return mapped_type if (mapped_type := TYPE_MAPPING.get(origin)) else origin
diff --git a/venv/lib/python3.11/site-packages/polyfactory/utils/types.py b/venv/lib/python3.11/site-packages/polyfactory/utils/types.py
new file mode 100644
index 0000000..413f5dd
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/polyfactory/utils/types.py
@@ -0,0 +1,12 @@
+from typing import Union
+
+try:
+ from types import NoneType, UnionType
+
+ UNION_TYPES = {UnionType, Union}
+except ImportError:
+ UNION_TYPES = {Union}
+
+ NoneType = type(None) # type: ignore[misc,assignment]
+
+__all__ = ("NoneType", "UNION_TYPES")