From 1f17a71c885b31621f3b476397e4f6ffbd53c4a8 Mon Sep 17 00:00:00 2001 From: Costi Mihai Date: Wed, 1 May 2024 10:59:43 +0200 Subject: [PATCH 1/5] Allow overriding the fixture name to be used when a subfactory is invoked --- pytest_factoryboy/fixture.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pytest_factoryboy/fixture.py b/pytest_factoryboy/fixture.py index 782806e..af01547 100644 --- a/pytest_factoryboy/fixture.py +++ b/pytest_factoryboy/fixture.py @@ -501,6 +501,10 @@ def attr_fixture(request: SubRequest, value: T) -> T: def subfactory_fixture(request: SubRequest, factory_class: FactoryType) -> Any: """SubFactory/RelatedFactory fixture implementation.""" + overriden_fixture_name = getattr(factory_class._meta, "fixture_name", None) + if overriden_fixture_name is not None: + return request.getfixturevalue(overriden_fixture_name) + fixture = inflection.underscore(factory_class._meta.model.__name__) return request.getfixturevalue(fixture) From 918fb909d8804b18ceea2d6b49b09614b7139b9b Mon Sep 17 00:00:00 2001 From: Costi Mihai Date: Wed, 1 May 2024 11:13:27 +0200 Subject: [PATCH 2/5] Use a protected attribute for "fixture_name" Otherwise the metaclass will raise a TypeError because of an unkown attribute --- pytest_factoryboy/fixture.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_factoryboy/fixture.py b/pytest_factoryboy/fixture.py index af01547..523b4de 100644 --- a/pytest_factoryboy/fixture.py +++ b/pytest_factoryboy/fixture.py @@ -501,7 +501,7 @@ def attr_fixture(request: SubRequest, value: T) -> T: def subfactory_fixture(request: SubRequest, factory_class: FactoryType) -> Any: """SubFactory/RelatedFactory fixture implementation.""" - overriden_fixture_name = getattr(factory_class._meta, "fixture_name", None) + overriden_fixture_name = getattr(factory_class._meta, "_fixture_name", None) if overriden_fixture_name is not None: return request.getfixturevalue(overriden_fixture_name) From 979048e46bcb17d78d684a17c74f375973f68d43 Mon Sep 17 00:00:00 2001 From: Costi Mihai Date: Wed, 1 May 2024 12:01:34 +0200 Subject: [PATCH 3/5] Add documentation on how to use the fixture name --- README.rst | 35 +++++++++++++++++++++++++++++++++++ pytest_factoryboy/fixture.py | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 5e26406..2020c39 100644 --- a/README.rst +++ b/README.rst @@ -113,6 +113,41 @@ Sub-factory attribute points to the model fixture of the sub-factory. Attributes of sub-factories are injected as dependencies to the model fixture and can be overridden_ via the parametrization. +Django Model SubFactory with a custom fixture name +-------------------------------------------------- + +By default, the subfactory is retrieved by using the lowercase-underscore form of the Django model class name +and invoking that fixture from the pytest request. +If you want to use a different name, you must define it in the factory class Meta and use a custom DjangoModelFactory + +.. code-block:: python + + from factory.django import DjangoModelFactory, DjangoOptions + + class CustomFixtureFactoryOptions(DjangoOptions): + """Allow overriding the fixture name when referencing the factory via SubFactory/RelatedFactory.""" + def _build_default_options(self): + return super()._build_default_options() + [ + factory.base.OptionDefault("fixture_name", None), + ] + + + class CustomFixtureDjangoModelFactory(DjangoModelFactory): + _options_class = CustomFixtureFactoryOptions + + class Meta: + abstract = True + + + @register + class AuthorFactory(CustomFixtureDjangoModelFactory): + class Meta: + model = Author + fixture_name = "other_author" + + name = "Charles Dickens" + + Related Factory --------------- diff --git a/pytest_factoryboy/fixture.py b/pytest_factoryboy/fixture.py index 523b4de..af01547 100644 --- a/pytest_factoryboy/fixture.py +++ b/pytest_factoryboy/fixture.py @@ -501,7 +501,7 @@ def attr_fixture(request: SubRequest, value: T) -> T: def subfactory_fixture(request: SubRequest, factory_class: FactoryType) -> Any: """SubFactory/RelatedFactory fixture implementation.""" - overriden_fixture_name = getattr(factory_class._meta, "_fixture_name", None) + overriden_fixture_name = getattr(factory_class._meta, "fixture_name", None) if overriden_fixture_name is not None: return request.getfixturevalue(overriden_fixture_name) From 2a5fc8024405292b5d1e5def2e82de8494f17feb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 May 2024 10:07:31 +0000 Subject: [PATCH 4/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pytest_factoryboy/fixture.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_factoryboy/fixture.py b/pytest_factoryboy/fixture.py index af01547..036cdf1 100644 --- a/pytest_factoryboy/fixture.py +++ b/pytest_factoryboy/fixture.py @@ -504,7 +504,7 @@ def subfactory_fixture(request: SubRequest, factory_class: FactoryType) -> Any: overriden_fixture_name = getattr(factory_class._meta, "fixture_name", None) if overriden_fixture_name is not None: return request.getfixturevalue(overriden_fixture_name) - + fixture = inflection.underscore(factory_class._meta.model.__name__) return request.getfixturevalue(fixture) From fad61e71788a53ada51d2e2347c7c28005a15962 Mon Sep 17 00:00:00 2001 From: Costi Mihai Date: Wed, 1 May 2024 17:06:42 +0200 Subject: [PATCH 5/5] Attempt to use overriden fixture name in other parts of the code --- pytest_factoryboy/fixture.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pytest_factoryboy/fixture.py b/pytest_factoryboy/fixture.py index af01547..70764fe 100644 --- a/pytest_factoryboy/fixture.py +++ b/pytest_factoryboy/fixture.py @@ -273,6 +273,10 @@ def inject_into_caller(name: str, function: Callable[..., Any], locals_: Box[dic def get_model_name(factory_class: FactoryType) -> str: """Get model fixture name by factory.""" + overriden_fixture_name = getattr(factory_class._meta, "fixture_name", None) + if overriden_fixture_name is not None: + return overriden_fixture_name + model_cls = factory_class._meta.model if isinstance(model_cls, str): @@ -501,11 +505,7 @@ def attr_fixture(request: SubRequest, value: T) -> T: def subfactory_fixture(request: SubRequest, factory_class: FactoryType) -> Any: """SubFactory/RelatedFactory fixture implementation.""" - overriden_fixture_name = getattr(factory_class._meta, "fixture_name", None) - if overriden_fixture_name is not None: - return request.getfixturevalue(overriden_fixture_name) - - fixture = inflection.underscore(factory_class._meta.model.__name__) + fixture = inflection.underscore(get_model_name(factory_class)) return request.getfixturevalue(fixture)