litestar-org / litestar-org/polyfactory
Enhancement: support creation of Hypothesis strategies
- Dominant language
- Python
- Stars
- 1.5k
- Forks
- 120
- PR merge metrics
- No merged PRs in 30d
Description
### Summary
I was playing around with [hypothesis](https://hypothesis.readthedocs.io/) and noticed that it can't create strategies when there are constraints on the fields. So, I'm proposing that `polyfactory` supports creation of strategies for a given model, with the constraints being respected.
Currently, there seems to be plans to support this as seen in this [issue](https://github.com/HypothesisWorks/hypothesis/issues/3356), however that would require the users use the annotated types for the constraints. Furthermore, while pydantic v1 did use to integrate with hypothesis, the latest version does not so as documented [here](https://docs.pydantic.dev/latest/integrations/hypothesis/).
Would this be something that would be helpful and worth implementing? Opinions, @litestar-org/members?
### Basic Example
```python
from typing import Annotated, Any
import msgspec
from hypothesis import given
from hypothesis import strategies as st
from hypothesis.strategies import SearchStrategy
from msgspec import Struct
from msgspec.structs import asdict
from polyfactory.factories.msgspec_factory import MsgspecFactory
from polyfactory.field_meta import FieldMeta
class Foo(Struct):
foo: Annotated[int, msgspec.Meta(ge=100)]
def handle_constrained_int(field_meta: FieldMeta) -> SearchStrategy[int]:
return st.integers(min_value=field_meta.constraints.get("ge"))
class FooFactory(MsgspecFactory[Foo]):
__model__ = Foo
@classmethod
def create_hypothesis_strategy(cls) -> SearchStrategy[Foo]:
st_kwargs: dict[str, SearchStrategy[Any]] = {}
for field in cls.get_model_fields():
if field.annotation is int:
st_kwargs[field.name] = handle_constrained_int(field)
return st.builds(cls.__model__, **st_kwargs)
polyfactory_foo_st = FooFactory.create_hypothesis_strategy()
hypothesis_foo_st = st.builds(Foo)
@given(polyfactory_foo_st)
def test_polyfactory_foo_st(foo: Foo):
foo_dict = asdict(foo)
_ = msgspec.convert(foo_dict, Foo)
@given(hypothesis_foo_st)
def test_hypothesis_foo_st(foo: Foo):
foo_dict = asdict(foo)
_ = msgspec.convert(foo_dict, Foo) # this will fail the msgspec validation
if __name__ == "__main__":
# test_polyfactory_foo_st()
test_hypothesis_foo_st()
```
### Drawbacks and Impact
_No response_
### Unresolved questions
_No response_
Contributor guide
Research direction
Start with polyfactory.factories.msgspec_factory.MsgspecFactory and polyfactory.field_meta.FieldMeta, then review the example's create_hypothesis_strategy entry point. Determine how model fields and their constraints should map to Hypothesis strategies across supported types. Done means a factory can produce a strategy whose generated models satisfy the declared constraints, with coverage for the msgspec example and related cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- testing-qa
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100