Skip to content

Enhancement: support creation of Hypothesis strategies #387

@vkcku

Description

@vkcku

Summary

I was playing around with hypothesis 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, 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.

Would this be something that would be helpful and worth implementing? Opinions, @litestar-org/members?

Basic Example

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions