litestar-org / litestar-org/polyfactory

Enhancement: support creation of Hypothesis strategies

Open
#387 4 comments 1 reaction 0 assignees View on GitHub
enhancement
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.