Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions polyfactory/factories/pydantic_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -713,11 +713,29 @@ def get_field_value_coverage(
if cls.is_ignored_type(field_meta.annotation):
return

field_meta = cast("PydanticFieldMeta", field_meta)
if cls.__use_examples__:
examples = getattr(field_meta, "examples", None) or []
if len(examples) > 0:
yield CoverageContainer(examples)
return

def examples_coverage(field_meta: PydanticFieldMeta) -> Iterable[Any]:
examples = field_meta.examples or []
if len(examples) > 0:
yield CoverageContainer(examples)
return
if field_meta.children:
# NoneType children aren't included in field_meta.children,
# so to ensure that they are covered we need to check for them explicitly
if NoneType in field_meta.type_args:
yield None
for child in field_meta.children:
child = cast("PydanticFieldMeta", child)
yield from examples_coverage(child)
return
yield from super(ModelFactory, cls).get_field_value_coverage(
field_meta, field_build_parameters, build_context
)

yield from examples_coverage(field_meta)
return

yield from super().get_field_value_coverage(field_meta, field_build_parameters, build_context)

Expand Down
35 changes: 35 additions & 0 deletions tests/test_pydantic_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,41 @@ class FooFactory(ModelFactory[Foo]):
assert {instance.number for instance in instances} == set(example_numbers)


@pytest.mark.skipif(_IS_PYDANTIC_V1, reason="Pydantic 1 doesn't support examples")
def test_factory_use_examples_coverage_when_examples_in_annotations() -> None:
class TopLevel(BaseModel):
f: Annotated[int, Field(examples=[1, 2, 3, 4])]

class WithOptional(BaseModel):
f: Optional[Annotated[int, Field(examples=[1, 2, 3, 4])]]

class OrNone(BaseModel):
f: Union[Annotated[int, Field(examples=[1, 2, 3, 4])], None]

class ExamplesInBothSubtypes(BaseModel):
f: Union[Annotated[int, Field(examples=[1, 2])], Annotated[int, Field(examples=[3, 4])], None]

class OuterMostExampleIsRespected(BaseModel):
f: Annotated[
Union[Annotated[int, Field(examples=[1, 2])], Annotated[int, Field(examples=[3, 4])], None],
Field(examples=[6, 7, 8, 9]),
]

for cls, expected in (
(TopLevel, [1, 2, 3, 4]),
(WithOptional, [1, 2, 3, 4, None]),
(OrNone, [1, 2, 3, 4, None]),
(ExamplesInBothSubtypes, [1, 2, 3, 4, None]),
(OuterMostExampleIsRespected, [6, 7, 8, 9]),
):

class ClsFactory(ModelFactory[cls]): # type: ignore[valid-type]
__use_examples__ = True

instances = list(ClsFactory.coverage())
assert {instance.f for instance in instances} == set(expected) # type: ignore[attr-defined]


def test_factory_use_construct_nested() -> None:
class Child(BaseModel):
a: int = Field(ge=0)
Expand Down
Loading