litestar-org/polyfactory

Bug: Invalid Coverage for Optional Fields with Annotated Constraint

tharindurr opened this issue · 0 comments

Description

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

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
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

==================================================================== 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 = <class 'tests.test_optional_constraint_coverage_factory.PartialASchemaFactory'>

    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 = <class 'tests.test_optional_constraint_coverage_factory.PartialASchemaFactory'>, 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 = <class 'tests.test_optional_constraint_coverage_factory.PartialCSchemaFactory'>

    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 = <class 'tests.test_optional_constraint_coverage_factory.PartialCSchemaFactory'>, 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

  • Linux
  • Mac
  • Windows
  • Other (Please specify in the description above)

Note

While we are open for sponsoring on GitHub Sponsors and
OpenCollective, we also utilize Polar.sh to engage in pledge-based sponsorship.

Check out all issues funded or available for funding on our Polar.sh dashboard

  • If you would like to see an issue prioritized, make a pledge towards it!
  • We receive the pledge once the issue is completed & verified
  • This, along with engagement in the community, helps us know which features are a priority to our users.
Fund with Polar