litestar-org / litestar-org/polyfactory

Bug: Invalid Coverage for Optional Fields with Annotated Constraint

Open
#514 0 comments 3 reactions 0 assignees View on GitHub
bug
Dominant language
Python
Stars
1.5k
Forks
120
PR merge metrics
No merged PRs in 30d

Description

### Description

I was trying to produce coverage for a Pydantic model with Annotated Field constraints.

```py
class PartialA(BaseModel):
a: Annotated[str | None, Field(min_length=1, max_length=10)] = None
```

The coverage function does not yield proper attributes for field `a`.

I tracked it down to the method `get_field_value_coverage` in `BaseFactory` which should extract the proper constraints.

Hope the issue is clear, happy to give further clarifications.

### URL to code causing the issue

_No response_

### MCVE

- This is a test that I wrote which can be used to test my issue

```python
from pydantic import BaseModel, Field
from typing import Annotated
from polyfactory.factories.pydantic_factory import ModelFactory

from polyfactory.pytest_plugin import register_fixture

class A(BaseModel):
a: Annotated[str, Field(min_length=1, max_length=10)]

class PartialA(BaseModel):
a: Annotated[str | None, Field(min_length=1, max_length=10)] = None

class PartialB(BaseModel):
a: str | None = None

class PartialC(BaseModel):
a: Annotated[int | None, Field(ge=0, le=10)] = None

@register_fixture
class ASchemaFactory(ModelFactory[A]):
__model__ = A

@register_fixture
class PartialASchemaFactory(ModelFactory[PartialA]):
__model__ = PartialA

@register_fixture
class PartialBSchemaFactory(ModelFactory[PartialB]):
__model__ = PartialB

@register_fixture
class PartialCSchemaFactory(ModelFactory[PartialC]):
__model__ = PartialC

def test_a_schema_factory(
a_schema_factory: ASchemaFactory):
for spec in a_schema_factory.coverage():
pass

def test_partial_a_schema_factory(
partial_a_schema_factory: PartialASchemaFactory):
for spec in partial_a_schema_factory.coverage():
pass

def test_partial_b_schema_factory(
partial_b_schema_factory: PartialBSchemaFactory):
for spec in partial_b_schema_factory.coverage():
pass

def test_partial_c_schema_factory(
partial_c_schema_factory: PartialCSchemaFactory):
for spec in partial_c_schema_factory.coverage():
pass
```

### Steps to reproduce

_No response_

### Screenshots

_No response_

### Logs

```bash
==================================================================== test session starts =====================================================================
platform linux -- Python 3.12.2, pytest-7.4.3, pluggy-1.3.0
rootdir: /home/rr/work/oss/polyfactory
configfile: pyproject.toml
plugins: cov-4.1.0, hypothesis-6.92.1, Faker-21.0.0, asyncio-0.23.2
asyncio: mode=Mode.AUTO
collected 4 items

tests/test_optional_constraint_coverage_factory.py .F.F

========================================================================== FAILURES ==========================================================================
_______________________________________________________________ test_partial_a_schema_factory ________________________________________________________________

partial_a_schema_factory =

def test_partial_a_schema_factory(
partial_a_schema_factory: PartialASchemaFactory):
> for spec in partial_a_schema_factory.coverage():

tests/test_optional_constraint_coverage_factory.py:44:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

cls = , kwargs = {}, data = {'a': 'GHTBnvXwdvDGBsyHYejs'}

@classmethod
def coverage(cls, **kwargs: Any) -> abc.Iterator[T]:
"""Build a batch of the factory's Meta.model will full coverage of the sub-types of the model.

:param kwargs: Any kwargs. If field_meta names are set in kwargs, their values will be used.

:returns: A iterator of instances of type T.

"""
for data in cls.process_kwargs_coverage(**kwargs):
> instance = cls.__model__(**data)
E pydantic_core._pydantic_core.ValidationError: 1 validation error for PartialA
E a
E String should have at most 10 characters [type=string_too_long, input_value='GHTBnvXwdvDGBsyHYejs', input_type=str]
E For further information visit https://errors.pydantic.dev/2.5/v/string_too_long

polyfactory/factories/base.py:1058: ValidationError
_______________________________________________________________ test_partial_c_schema_factory ________________________________________________________________

partial_c_schema_factory =

def test_partial_c_schema_factory(
partial_c_schema_factory: PartialCSchemaFactory):
> for spec in partial_c_schema_factory.coverage():

tests/test_optional_constraint_coverage_factory.py:54:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

cls = , kwargs = {}, data = {'a': 7693}

@classmethod
def coverage(cls, **kwargs: Any) -> abc.Iterator[T]:
"""Build a batch of the factory's Meta.model will full coverage of the sub-types of the model.

:param kwargs: Any kwargs. If field_meta names are set in kwargs, their values will be used.

:returns: A iterator of instances of type T.

"""
for data in cls.process_kwargs_coverage(**kwargs):
> instance = cls.__model__(**data)
E pydantic_core._pydantic_core.ValidationError: 1 validation error for PartialC
E a
E Input should be less than or equal to 10 [type=less_than_equal, input_value=7693, input_type=int]
E For further information visit https://errors.pydantic.dev/2.5/v/less_than_equal

polyfactory/factories/base.py:1058: ValidationError
====================================================================== warnings summary ======================================================================
.venv/lib/python3.12/site-packages/beanie/odm/fields.py:581
/home/rr/work/oss/polyfactory/.venv/lib/python3.12/site-packages/beanie/odm/fields.py:581: DeprecationWarning: `general_plain_validator_function` is deprecated, use `with_info_plain_validator_function` instead.
return core_schema.general_plain_validator_function(validate)

.venv/lib/python3.12/site-packages/pydantic_core/core_schema.py:3902
.venv/lib/python3.12/site-packages/pydantic_core/core_schema.py:3902
.venv/lib/python3.12/site-packages/pydantic_core/core_schema.py:3902
/home/rr/work/oss/polyfactory/.venv/lib/python3.12/site-packages/pydantic_core/core_schema.py:3902: DeprecationWarning: `general_plain_validator_function` is deprecated, use `with_info_plain_validator_function` instead.
warnings.warn(

.venv/lib/python3.12/site-packages/beanie/odm/fields.py:150
.venv/lib/python3.12/site-packages/beanie/odm/fields.py:150
/home/rr/work/oss/polyfactory/.venv/lib/python3.12/site-packages/beanie/odm/fields.py:150: DeprecationWarning: `general_plain_validator_function` is deprecated, use `with_info_plain_validator_function` instead.
python_schema=core_schema.general_plain_validator_function(

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================================================== short test summary info ===================================================================
FAILED tests/test_optional_constraint_coverage_factory.py::test_partial_a_schema_factory - pydantic_core._pydantic_core.ValidationError: 1 validation error for PartialA
FAILED tests/test_optional_constraint_coverage_factory.py::test_partial_c_schema_factory - pydantic_core._pydantic_core.ValidationError: 1 validation error for PartialC
========================================================== 2 failed, 2 passed, 6 warnings in 0.46s ===========================================================
```

### Release Version

2.15.0

### Platform

- [X] Linux
- [ ] Mac
- [ ] Windows
- [ ] Other (Please specify in the description above)

Contributor guide

Open the contributing guide

Research direction

Start in polyfactory/factories/base.py at BaseFactory.get_field_value_coverage and reproduce the issue with tests/test_optional_constraint_coverage_factory.py. Check how constraints are extracted for optional Annotated fields, then verify that the coverage cases for PartialA and PartialC produce values within their declared bounds and the test file passes.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.