File: fields.py

package info (click to toggle)
python-polyfactory 2.22.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,892 kB
  • sloc: python: 11,338; makefile: 103; sh: 37
file content (120 lines) | stat: -rw-r--r-- 3,535 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
from __future__ import annotations

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

from typing_extensions import ParamSpec

from polyfactory.exceptions import ParameterException
from polyfactory.utils import deprecation
from polyfactory.utils.predicates import is_safe_subclass

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


class WrappedCallable(TypedDict):
    """A ref storing a callable. This class is a utility meant to prevent binding of methods."""

    value: Callable


class Require:
    """A factory field that marks an attribute as a required build-time kwarg."""


class Ignore:
    """A factory field that marks an attribute as ignored."""


class Use(Generic[P, T]):
    """Factory field used to wrap a callable.

    The callable will be invoked whenever building the given factory attribute.


    """

    __slots__ = ("args", "fn", "kwargs")

    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

    def to_value(self) -> T:
        """Invoke the callable.

        :returns: The output of the callable.


        """
        return cast("T", self.fn["value"](*self.args, **self.kwargs))


class PostGenerated:
    """Factory field that allows generating values after other fields are generated by the factory."""

    __slots__ = ("args", "fn", "kwargs")

    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

    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)


class Fixture:
    """Factory field to create a pytest fixture from a factory."""

    __slots__ = ("kwargs", "ref", "size")

    @deprecation.deprecated(version="2.20.0", alternative="Use factory directly")
    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

    def to_value(self) -> Any:
        """Call the factory's build or batch method.

        :raises: ParameterException

        :returns: The build result.
        """
        from polyfactory.factories.base import BaseFactory

        factory = self.ref["value"]
        if not is_safe_subclass(factory, BaseFactory):
            msg = "fixture has not been registered using the register_factory decorator"
            raise ParameterException(msg)

        if self.size is not None:
            return factory.batch(self.size, **self.kwargs)
        return factory.build(**self.kwargs)