Source code for polyfactory.fields

from __future__ import annotations

from typing import Any, Callable, Generic, TypedDict, TypeVar, cast

from typing_extensions import ParamSpec

from polyfactory.exceptions import ParameterException

T = TypeVar("T")
P = ParamSpec("P")


[docs]class WrappedCallable(TypedDict): """A ref storing a callable. This class is a utility meant to prevent binding of methods.""" value: Callable
[docs]class Require: """A factory field that marks an attribute as a required build-time kwarg."""
[docs]class Ignore: """A factory field that marks an attribute as ignored."""
[docs]class Use(Generic[P, T]): """Factory field used to wrap a callable. The callable will be invoked whenever building the given factory attribute. """ __slots__ = ("fn", "kwargs", "args")
[docs] def __init__(self, fn: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> None: """Wrap a callable. :param fn: A callable to wrap. :param args: Any args to pass to the callable. :param kwargs: Any kwargs to pass to the callable. """ self.fn: WrappedCallable = {"value": fn} self.kwargs = kwargs self.args = args
[docs] def to_value(self) -> T: """Invoke the callable. :returns: The output of the callable. """ return cast("T", self.fn["value"](*self.args, **self.kwargs))
[docs]class PostGenerated: """Factory field that allows generating values after other fields are generated by the factory.""" __slots__ = ("fn", "kwargs", "args")
[docs] def __init__(self, fn: Callable, *args: Any, **kwargs: Any) -> None: """Designate field as post-generated. :param fn: A callable. :param args: Args for the callable. :param kwargs: Kwargs for the callable. """ self.fn: WrappedCallable = {"value": fn} self.kwargs = kwargs self.args = args
[docs] def to_value(self, name: str, values: dict[str, Any]) -> Any: """Invoke the post-generation callback passing to it the build results. :param name: Field name. :param values: Generated values. :returns: An arbitrary value. """ return self.fn["value"](name, values, *self.args, **self.kwargs)
[docs]class Fixture: """Factory field to create a pytest fixture from a factory.""" __slots__ = ("ref", "size", "kwargs")
[docs] def __init__(self, fixture: Callable, size: int | None = None, **kwargs: Any) -> None: """Create a fixture from a factory. :param fixture: A factory that was registered as a fixture. :param size: Optional batch size. :param kwargs: Any build kwargs. """ self.ref: WrappedCallable = {"value": fixture} self.size = size self.kwargs = kwargs
[docs] def to_value(self) -> Any: """Call the factory's build or batch method. :raises: ParameterException :returns: The build result. """ from polyfactory.pytest_plugin import FactoryFixture if factory := FactoryFixture.factory_class_map.get(self.ref["value"]): if self.size is not None: return factory.batch(self.size, **self.kwargs) return factory.build(**self.kwargs) msg = "fixture has not been registered using the register_factory decorator" raise ParameterException(msg)