litestar-org / polyfactory

Simple and powerful factories for mock data generation
https://polyfactory.litestar.dev/
MIT License
1k stars 78 forks source link

Bug: Setting `ge` and `multiple_of` but not `le` constraints causes invalid values to be generated #503

Open richardxia opened 6 months ago

richardxia commented 6 months ago

Description

I am using Polyfactory with Pydantic, and it appears that if you create a field with both ge and multiple_of set, but not le or lt, then Polyfactory will generate values that don't satisfy all the constraints. For example, if you set ge to 10 and multiple_of to 3, then Polyfactory appears to always generate a value of 3, which fails to satisfy the >= 10 constraint.

It looks like the bug is in polyfactory.value_generators.constrained_numbers's generate_constrained_number() function. In that function, if both minimum and multiple_of are set to non-None values, but maximum is None, then it'll take the earliest exit by immediately returning multiple_of, even if multiple_of may not satisfy the minimum constraint.

URL to code causing the issue

No response

MCVE

from pydantic import BaseModel, Field
from polyfactory.factories.pydantic_factory import ModelFactory

class Foo(BaseModel):
    bar: int = Field(ge=10, multiple_of=3)

class FooFactory(ModelFactory[Foo]):
    ...

FooFactory.build()

Steps to reproduce

1. Install both pydantic and polyfactory
2. Save the code snippet above to a file (e.g. main.py)
3. Execute the file (e.g. `python3 main.py`)

Screenshots

No response

Logs

Traceback (most recent call last):
  File "/Users/richardx/tmp/polyfactory-multiple-test/main.py", line 13, in <module>
    FooFactory.build()
  File "/Users/richardx/tmp/polyfactory-multiple-test/venv/lib/python3.11/site-packages/polyfactory/factories/pydantic_factory.py", line 401, in build
    return cls.__model__(**processed_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/richardx/tmp/polyfactory-multiple-test/venv/lib/python3.11/site-packages/pydantic/main.py", line 171, in __init__
    self.__pydantic_validator__.validate_python(data, self_instance=self)
pydantic_core._pydantic_core.ValidationError: 1 validation error for Foo
bar
  Input should be greater than or equal to 10 [type=greater_than_equal, input_value=3, input_type=int]
    For further information visit https://errors.pydantic.dev/2.6/v/greater_than_equal

Release Version

4.14.1

Platform


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

guacs commented 6 months ago

@richardxia thanks for reporting this! I think you're right in your analysis of generate_constrained_number being the issue as well. Would you be willing to raise a PR fixing this?

richardxia commented 6 months ago

No problem, I'd be happy to take a stab at fixing this.