From 913c04a7b1c9546d728a5978ea27ef8feb9aa7fc Mon Sep 17 00:00:00 2001 From: Alessio Bogon <778703+youtux@users.noreply.github.com> Date: Sun, 12 Jan 2025 14:05:55 +0100 Subject: [PATCH 1/3] Fix types --- src/pytest_factoryboy/fixture.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pytest_factoryboy/fixture.py b/src/pytest_factoryboy/fixture.py index d924c76..bcc538f 100644 --- a/src/pytest_factoryboy/fixture.py +++ b/src/pytest_factoryboy/fixture.py @@ -27,7 +27,7 @@ ) from typing_extensions import ParamSpec -from .compat import PostGenerationContext +from .compat import PostGenerationContext, PytestFixtureT from .fixturegen import create_fixture if TYPE_CHECKING: @@ -195,10 +195,10 @@ def generate_fixtures( def create_fixture_with_related( name: str, - function: Callable[P, T], + function: Callable[..., object], fixtures: Collection[str] | None = None, related: Collection[str] | None = None, -) -> Callable[P, T]: +) -> PytestFixtureT: if related is None: related = [] fixture, fn = create_fixture(name=name, function=function, fixtures=fixtures) From 00038aa3ef738b71d734794c8066f8288bd541db Mon Sep 17 00:00:00 2001 From: Alessio Bogon <778703+youtux@users.noreply.github.com> Date: Sun, 12 Jan 2025 14:06:19 +0100 Subject: [PATCH 2/3] Add (failing) test for feature --- tests/test_factory_fixtures.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_factory_fixtures.py b/tests/test_factory_fixtures.py index 3a35b9c..c7ddc59 100644 --- a/tests/test_factory_fixtures.py +++ b/tests/test_factory_fixtures.py @@ -211,3 +211,12 @@ def test_override_subfactory_with_lazy_fixture(self, another_book: Book): """ assert another_book.author.name == "Another Author" + + +class TestDeferredEvaluation: + @pytest.mark.parametrize("book__name", ["bar"]) + def test_book_initialise_later(self, book_factory, book): + assert book.name == "bar" + + book_f = book_factory() + assert book_f.name == "bar" From d04dd97a4762ecb9a29a8d2ffd9deadfbb9c7822 Mon Sep 17 00:00:00 2001 From: Alessio Bogon <778703+youtux@users.noreply.github.com> Date: Sun, 12 Jan 2025 15:15:10 +0100 Subject: [PATCH 3/3] Factory fixture should apply parametrizations --- src/pytest_factoryboy/fixture.py | 20 ++++++++++++++++++-- tests/test_factory_fixtures.py | 11 +---------- tests/test_foo.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 tests/test_foo.py diff --git a/src/pytest_factoryboy/fixture.py b/src/pytest_factoryboy/fixture.py index bcc538f..33d7a1f 100644 --- a/src/pytest_factoryboy/fixture.py +++ b/src/pytest_factoryboy/fixture.py @@ -172,16 +172,18 @@ def generate_fixtures( ), ) + deps = get_deps(factory_class, model_name=model_name) if factory_name not in caller_locals.value: yield ( factory_name, create_fixture_with_related( name=factory_name, function=functools.partial(factory_fixture, factory_class=factory_class), + fixtures=deps, + # TODO: related too? ), ) - deps = get_deps(factory_class, model_name=model_name) yield ( model_name, create_fixture_with_related( @@ -366,6 +368,7 @@ def model_fixture(request: SubRequest, factory_name: str) -> object: fixture_name = request.fixturename prefix = "".join((fixture_name, SEPARATOR)) + # TODO: This should be a dependency of the current fixture (i.e. use `usefixtures`) factory_class: type[Factory[object]] = request.getfixturevalue(factory_name) # create Factory override for the model fixture @@ -500,7 +503,20 @@ def deferred_impl(request: SubRequest) -> object: def factory_fixture(request: SubRequest, factory_class: type[Factory[T]]) -> type[Factory[T]]: """Factory fixture implementation.""" - return factory_class + fixture_name = request.fixturename + # TODO: Not good to check the fixture name, we should know what to expect (via args?) + assert fixture_name.endswith("_factory") + fixture_name = fixture_name[: -len("_factory")] + prefix = "".join((fixture_name, SEPARATOR)) + + # TODO: copy-paste from model_fixture; refactor + kwargs = {} + for key in factory_class._meta.pre_declarations: + argname = "".join((prefix, key)) + if argname in request._fixturedef.argnames: + kwargs[key] = evaluate(request, request.getfixturevalue(argname)) + + return type(f"{factory_class.__name__}Fixture", (factory_class,), kwargs) def attr_fixture(request: SubRequest, value: T) -> T: diff --git a/tests/test_factory_fixtures.py b/tests/test_factory_fixtures.py index c7ddc59..eddc990 100644 --- a/tests/test_factory_fixtures.py +++ b/tests/test_factory_fixtures.py @@ -109,7 +109,7 @@ class Meta: def test_factory(book_factory) -> None: """Test model factory fixture.""" - assert book_factory == BookFactory + assert issubclass(book_factory, BookFactory) def test_model(book: Book): @@ -211,12 +211,3 @@ def test_override_subfactory_with_lazy_fixture(self, another_book: Book): """ assert another_book.author.name == "Another Author" - - -class TestDeferredEvaluation: - @pytest.mark.parametrize("book__name", ["bar"]) - def test_book_initialise_later(self, book_factory, book): - assert book.name == "bar" - - book_f = book_factory() - assert book_f.name == "bar" diff --git a/tests/test_foo.py b/tests/test_foo.py new file mode 100644 index 0000000..657f9d2 --- /dev/null +++ b/tests/test_foo.py @@ -0,0 +1,30 @@ +# TODO: Improve tests +# TODO: Change test module + +from dataclasses import dataclass + +import factory +import pytest + +from pytest_factoryboy import register + + +@dataclass +class Book: + name: str + + +@register +class BookFactory(factory.Factory): + class Meta: + model = Book + + name = "foo" + + +@pytest.mark.parametrize("book__name", ["bar"]) +def test_book_initialise_later(book_factory, book__name, book): + assert book.name == "bar" + + book_f = book_factory() + assert book_f.name == "bar"