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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
|
from dataclasses import dataclass
from enum import Enum
from typing import (
Any,
Callable,
DefaultDict,
Deque,
Dict,
FrozenSet,
Generic,
Iterable,
List,
Literal,
Optional,
Sequence,
Set,
Tuple,
TypeVar,
Union,
)
import pytest
from pydantic import BaseModel
from polyfactory.exceptions import ParameterException
from polyfactory.factories import DataclassFactory
from polyfactory.factories.pydantic_factory import ModelFactory
from tests.models import Person
def test_handles_complex_typing() -> None:
class MyModel(BaseModel):
nested_dict: Dict[str, Dict[Union[int, str], Dict[Any, List[Dict[str, str]]]]]
dict_str_any: Dict[str, Any]
nested_list: List[List[List[Dict[str, List[Any]]]]]
sequence_literal: Sequence[Literal[1, 2, 3]]
sequence_dict: Sequence[Dict[str, Any]]
iterable_float: Iterable[float]
tuple_ellipsis: Tuple[int, ...]
tuple_str_str: Tuple[str, str]
default_dict: DefaultDict[str, List[Dict[str, int]]]
deque: Deque[List[Dict[str, int]]]
set_union: Set[Union[str, int]]
frozen_set: FrozenSet[str]
plain_list: List[Any]
plain_set: Set[Any]
plain_dict: Dict[str, Any]
class MyFactory(ModelFactory):
__model__ = MyModel
result = MyFactory.build()
assert result.nested_dict
assert result.dict_str_any
assert result.nested_list
assert result.sequence_dict
assert result.iterable_float
assert result.tuple_ellipsis
assert result.tuple_str_str
assert result.default_dict
assert result.deque
assert result.set_union
assert result.frozen_set
assert result.plain_list
assert result.plain_set
assert result.plain_dict
def test_handles_complex_typing_with_embedded_models() -> None:
class MyModel(BaseModel):
person_dict: Dict[str, Person]
person_list: List[Person]
class MyFactory(ModelFactory):
__model__ = MyModel
result = MyFactory.build()
assert result.person_dict
assert result.person_list[0].pets
def test_raises_for_user_defined_types() -> None:
class MyClass:
def __init__(self, value: int) -> None:
self.value = value
class MyModel(BaseModel):
my_class_field: Dict[str, MyClass]
class Config:
arbitrary_types_allowed = True
class MyFactory(ModelFactory):
__model__ = MyModel
with pytest.raises(ParameterException):
MyFactory.build()
def test_randomizes_optional_returns() -> None:
"""this is a flaky test - because it depends on randomness, hence it's been re-ran multiple times."""
class MyModel(BaseModel):
optional_1: Optional[List[str]]
optional_2: Optional[Dict[str, str]]
optional_3: Optional[Set[str]]
optional_4: Optional[Dict[int, str]]
class MyFactory(ModelFactory):
__model__ = MyModel
__random_seed__ = 1
failed = False
for _ in range(5):
try:
result = MyFactory.build()
assert any(
[
not result.optional_1,
not result.optional_2,
not result.optional_3,
not result.optional_4,
],
)
assert any(
[
bool(result.optional_1),
bool(result.optional_2),
bool(result.optional_3),
bool(result.optional_4),
],
)
failed = False
break
except AssertionError:
failed = True
assert not failed
def test_complex_typing_with_enum() -> None:
class Animal(str, Enum):
DOG = "Dog"
CAT = "Cat"
MONKEY = "Monkey"
class MyModel(BaseModel):
animal_list: List[Animal]
class MyFactory(ModelFactory):
__model__ = MyModel
result = MyFactory.build()
assert result.animal_list
def test_union_literal() -> None:
class MyModel(BaseModel):
x: Union[int, Literal["a", "b", "c"]]
class MyFactory(ModelFactory):
__model__ = MyModel
MyFactory.build()
def test_non_collection_generic() -> None:
T = TypeVar("T")
class LoggedVar(Generic[T]):
def __init__(self, name: str = "", log: Callable[[str], None] = print) -> None:
self.__name = name
self.__log = log
def set(self, value: T) -> None:
self.__log(f"Set {self.__name} to {value}")
self.__value = value
def get(self) -> T:
self.__log(f"Get {self.__name} = {self.__value}")
return self.__value
@dataclass
class MyModel:
x: LoggedVar[int]
class MyFactory(DataclassFactory):
__model__ = MyModel
result = MyFactory.build()
assert isinstance(result.x, LoggedVar)
def test_sequence_dict() -> None:
@dataclass
class MyModel:
sequence_dict: Sequence[Dict]
class MyFactory(DataclassFactory):
__model__ = MyModel
result = MyFactory.build()
assert result.sequence_dict
def test_build_with_callable() -> None:
@dataclass
class A:
foo: Callable[[str], int]
factory = DataclassFactory.create_factory(A)
with pytest.raises(ParameterException, match="Unsupported type:"):
factory.build()
|