From 56f1dd9cec203910b75d73b0a8dbb4c9e6559f88 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Tue, 6 Feb 2024 18:35:48 +0100 Subject: [PATCH 1/5] Add missing generic on `Factory` subclasses --- factory/alchemy.py | 6 +++++- factory/base.py | 10 +++++----- factory/mogo.py | 5 +++-- factory/mongoengine.py | 5 +++-- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/factory/alchemy.py b/factory/alchemy.py index f934ce5d..42bd2bbf 100644 --- a/factory/alchemy.py +++ b/factory/alchemy.py @@ -1,10 +1,14 @@ # Copyright: See the LICENSE file. +from typing import TypeVar + from sqlalchemy.exc import IntegrityError from sqlalchemy.orm.exc import NoResultFound from . import base, errors +T = TypeVar("T") + SESSION_PERSISTENCE_COMMIT = 'commit' SESSION_PERSISTENCE_FLUSH = 'flush' VALID_SESSION_PERSISTENCE_TYPES = [ @@ -46,7 +50,7 @@ def _build_default_options(self): ] -class SQLAlchemyModelFactory(base.Factory): +class SQLAlchemyModelFactory(base.Factory[T]): """Factory for SQLAlchemy models. """ _options_class = SQLAlchemyOptions diff --git a/factory/base.py b/factory/base.py index 8d499501..f28f587c 100644 --- a/factory/base.py +++ b/factory/base.py @@ -656,7 +656,7 @@ def __init__(self, **kwargs): setattr(self, field, value) -class StubFactory(Factory): +class StubFactory(Factory[T]): class Meta: strategy = enums.STUB_STRATEGY @@ -671,7 +671,7 @@ def create(cls, **kwargs): raise errors.UnsupportedStrategy() -class BaseDictFactory(Factory): +class BaseDictFactory(Factory[T]): """Factory for dictionary-like classes.""" class Meta: abstract = True @@ -688,12 +688,12 @@ def _create(cls, model_class, *args, **kwargs): return cls._build(model_class, *args, **kwargs) -class DictFactory(BaseDictFactory): +class DictFactory(BaseDictFactory[T]): class Meta: model = dict -class BaseListFactory(Factory): +class BaseListFactory(Factory[T]): """Factory for list-like classes.""" class Meta: abstract = True @@ -714,7 +714,7 @@ def _create(cls, model_class, *args, **kwargs): return cls._build(model_class, *args, **kwargs) -class ListFactory(BaseListFactory): +class ListFactory(BaseListFactory[T]): class Meta: model = list diff --git a/factory/mogo.py b/factory/mogo.py index f886ae14..8885d0aa 100644 --- a/factory/mogo.py +++ b/factory/mogo.py @@ -2,12 +2,13 @@ """factory_boy extensions for use with the mogo library (pymongo wrapper).""" - +from typing import TypeVar from . import base +T = TypeVar("T") -class MogoFactory(base.Factory): +class MogoFactory(base.Factory[T]): """Factory for mogo objects.""" class Meta: abstract = True diff --git a/factory/mongoengine.py b/factory/mongoengine.py index eb4a8dc5..e585b70a 100644 --- a/factory/mongoengine.py +++ b/factory/mongoengine.py @@ -2,12 +2,13 @@ """factory_boy extensions for use with the mongoengine library (pymongo wrapper).""" - +from typing import TypeVar from . import base +T = TypeVar("T") -class MongoEngineFactory(base.Factory): +class MongoEngineFactory(base.Factory[T]): """Factory for mongoengine objects.""" class Meta: From 937f4c6a99a7c9465bcff43aee94006e8238a71f Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 7 Feb 2024 10:51:46 +0100 Subject: [PATCH 2/5] Parametrize concrete factories, add tests --- factory/base.py | 6 +++--- tests/test_typing.py | 24 ++++++++++++++++++++---- tox.ini | 1 + 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/factory/base.py b/factory/base.py index f28f587c..46a43b9e 100644 --- a/factory/base.py +++ b/factory/base.py @@ -656,7 +656,7 @@ def __init__(self, **kwargs): setattr(self, field, value) -class StubFactory(Factory[T]): +class StubFactory(Factory[StubObject]): class Meta: strategy = enums.STUB_STRATEGY @@ -688,7 +688,7 @@ def _create(cls, model_class, *args, **kwargs): return cls._build(model_class, *args, **kwargs) -class DictFactory(BaseDictFactory[T]): +class DictFactory(BaseDictFactory[dict]): class Meta: model = dict @@ -714,7 +714,7 @@ def _create(cls, model_class, *args, **kwargs): return cls._build(model_class, *args, **kwargs) -class ListFactory(BaseListFactory[T]): +class ListFactory(BaseListFactory[list]): class Meta: model = list diff --git a/tests/test_typing.py b/tests/test_typing.py index c2f8b564..6ee98878 100644 --- a/tests/test_typing.py +++ b/tests/test_typing.py @@ -3,6 +3,8 @@ import dataclasses import unittest +from typing_extensions import assert_type + import factory @@ -25,7 +27,21 @@ class UserFactory(factory.Factory[User]): class Meta: model = User - result: User - result = UserFactory.build() - result = UserFactory.create() - self.assertEqual(result.name, "John Doe") + assert_type(UserFactory.build(), User) + assert_type(UserFactory.create(), User) + assert_type(UserFactory.build_batch(2), list[User]) + assert_type(UserFactory.create_batch(2), list[User]) + self.assertEqual(UserFactory.create().name, "John Doe") + + def test_dict_factory(self) -> None: + + class Pet(factory.DictFactory): + species = "dog" + name = "rover" + + assert_type(Pet.build(), dict) + assert_type(Pet.create(), dict) + + def test_list_factory(self) -> None: + assert_type(factory.ListFactory().build(), list) + assert_type(factory.ListFactory().create(), list) diff --git a/tox.ini b/tox.ini index d842c759..79e76f26 100644 --- a/tox.ini +++ b/tox.ini @@ -36,6 +36,7 @@ passenv = POSTGRES_DATABASE deps = mypy + typing_extensions alchemy: SQLAlchemy alchemy: sqlalchemy_utils mongo: mongoengine From f21ea3c18e31ec16535ed6375e955b03a3929142 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 7 Feb 2024 12:03:50 +0100 Subject: [PATCH 3/5] Fix tests compat --- tests/test_typing.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/test_typing.py b/tests/test_typing.py index 6ee98878..31b3dd0d 100644 --- a/tests/test_typing.py +++ b/tests/test_typing.py @@ -2,6 +2,7 @@ import dataclasses import unittest +from typing import List from typing_extensions import assert_type @@ -29,8 +30,8 @@ class Meta: assert_type(UserFactory.build(), User) assert_type(UserFactory.create(), User) - assert_type(UserFactory.build_batch(2), list[User]) - assert_type(UserFactory.create_batch(2), list[User]) + assert_type(UserFactory.build_batch(2), List[User]) + assert_type(UserFactory.create_batch(2), List[User]) self.assertEqual(UserFactory.create().name, "John Doe") def test_dict_factory(self) -> None: @@ -43,5 +44,6 @@ class Pet(factory.DictFactory): assert_type(Pet.create(), dict) def test_list_factory(self) -> None: - assert_type(factory.ListFactory().build(), list) - assert_type(factory.ListFactory().create(), list) + assert_type(factory.ListFactory(), list) + assert_type(factory.ListFactory.build(), list) + assert_type(factory.ListFactory.create(), list) From c4b4fa49fa995dd514302dcf4a9696f8d0beb00f Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 7 Feb 2024 12:14:34 +0100 Subject: [PATCH 4/5] Remove unsupported use case --- tests/test_typing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_typing.py b/tests/test_typing.py index 31b3dd0d..103a598d 100644 --- a/tests/test_typing.py +++ b/tests/test_typing.py @@ -44,6 +44,5 @@ class Pet(factory.DictFactory): assert_type(Pet.create(), dict) def test_list_factory(self) -> None: - assert_type(factory.ListFactory(), list) assert_type(factory.ListFactory.build(), list) assert_type(factory.ListFactory.create(), list) From f19bacbc9ec137da7ea74fafce89fd67f0a5fd4a Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 7 Feb 2024 12:18:12 +0100 Subject: [PATCH 5/5] lint --- factory/mogo.py | 1 + factory/mongoengine.py | 1 + 2 files changed, 2 insertions(+) diff --git a/factory/mogo.py b/factory/mogo.py index 8885d0aa..35089953 100644 --- a/factory/mogo.py +++ b/factory/mogo.py @@ -8,6 +8,7 @@ T = TypeVar("T") + class MogoFactory(base.Factory[T]): """Factory for mogo objects.""" class Meta: diff --git a/factory/mongoengine.py b/factory/mongoengine.py index e585b70a..9767d14b 100644 --- a/factory/mongoengine.py +++ b/factory/mongoengine.py @@ -8,6 +8,7 @@ T = TypeVar("T") + class MongoEngineFactory(base.Factory[T]): """Factory for mongoengine objects."""