From 083cf33e867e6097bc90386c23fd36f3857d9374 Mon Sep 17 00:00:00 2001 From: Serg Tereshchenko Date: Wed, 12 Jan 2022 18:41:00 +0200 Subject: [PATCH 01/12] feat: Add basic typing support --- factory/base.py | 15 +++++++++------ factory/django.py | 5 +++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/factory/base.py b/factory/base.py index 36b2359a..796f3d65 100644 --- a/factory/base.py +++ b/factory/base.py @@ -4,11 +4,14 @@ import collections import logging import warnings +from typing import Generic, List, TypeVar from . import builder, declarations, enums, errors, utils logger = logging.getLogger('factory.generate') +T = TypeVar('T') + # Factory metaclasses @@ -405,7 +408,7 @@ def reset(self, next_value=0): self.seq = next_value -class BaseFactory: +class BaseFactory(Generic[T]): """Factory base support for sequences, attributes and stubs.""" # Backwards compatibility @@ -506,12 +509,12 @@ def _create(cls, model_class, *args, **kwargs): return model_class(*args, **kwargs) @classmethod - def build(cls, **kwargs): + def build(cls, **kwargs) -> T: """Build an instance of the associated class, with overridden attrs.""" return cls._generate(enums.BUILD_STRATEGY, kwargs) @classmethod - def build_batch(cls, size, **kwargs): + def build_batch(cls, size, **kwargs) -> List[T]: """Build a batch of instances of the given class, with overridden attrs. Args: @@ -523,12 +526,12 @@ def build_batch(cls, size, **kwargs): return [cls.build(**kwargs) for _ in range(size)] @classmethod - def create(cls, **kwargs): + def create(cls, **kwargs) -> T: """Create an instance of the associated class, with overridden attrs.""" return cls._generate(enums.CREATE_STRATEGY, kwargs) @classmethod - def create_batch(cls, size, **kwargs): + def create_batch(cls, size, **kwargs) -> List[T]: """Create a batch of instances of the given class, with overridden attrs. Args: @@ -627,7 +630,7 @@ def simple_generate_batch(cls, create, size, **kwargs): return cls.generate_batch(strategy, size, **kwargs) -class Factory(BaseFactory, metaclass=FactoryMetaClass): +class Factory(BaseFactory[T], metaclass=FactoryMetaClass): """Factory base with build and create support. This class has the ability to support multiple ORMs by using custom creation diff --git a/factory/django.py b/factory/django.py index 9526b775..d5ca6d95 100644 --- a/factory/django.py +++ b/factory/django.py @@ -9,6 +9,7 @@ import logging import os import warnings +from typing import TypeVar from django.contrib.auth.hashers import make_password from django.core import files as django_files @@ -20,7 +21,7 @@ DEFAULT_DB_ALIAS = 'default' # Same as django.db.DEFAULT_DB_ALIAS - +T = TypeVar("T") _LAZY_LOADS = {} @@ -72,7 +73,7 @@ def get_model_class(self): return self.model -class DjangoModelFactory(base.Factory): +class DjangoModelFactory(base.Factory[T]): """Factory for Django models. This makes sure that the 'sequence' field of created objects is a new id. From 366e4b02f934f3cf400e505a1e9c27b7d65691a1 Mon Sep 17 00:00:00 2001 From: Serg Tereshchenko Date: Fri, 14 Apr 2023 20:40:15 +0300 Subject: [PATCH 02/12] feat: Add tests for typing --- Makefile | 2 ++ factory/py.typed | 0 setup.cfg | 4 ++++ tests/typecheck/test_basics.yml | 13 +++++++++++++ tox.ini | 3 +++ 5 files changed, 22 insertions(+) create mode 100644 factory/py.typed create mode 100644 tests/typecheck/test_basics.yml diff --git a/Makefile b/Makefile index a31a9fb8..8f283891 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,8 @@ test: -Wdefault:"'cgi' is deprecated and slated for removal in Python 3.13":DeprecationWarning:: \ -Wdefault:"datetime.datetime.utcfromtimestamp() is deprecated and scheduled for removal in a future version.":DeprecationWarning:: \ -m unittest + # Consider using pytest for entire test run (it just works) + pytest tests/typecheck --mypy-only-local-stub # DOC: Test the examples example-test: diff --git a/factory/py.typed b/factory/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/setup.cfg b/setup.cfg index 3ba2b7aa..917424f5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -59,6 +59,10 @@ doc = sphinx_rtd_theme sphinxcontrib-spelling +[options.package_data] +factory = + py.typed + [bdist_wheel] universal = 1 diff --git a/tests/typecheck/test_basics.yml b/tests/typecheck/test_basics.yml new file mode 100644 index 00000000..47598b72 --- /dev/null +++ b/tests/typecheck/test_basics.yml @@ -0,0 +1,13 @@ +- case: created_instance_is_of_correct_type + main: | + from django.db import models + import factory.django + + class Book(models.Model): + ... + + class BookFactory(factory.django.DjangoModelFactory[Book]): + ... + + instance = BookFactory.create() + reveal_type(instance) # N: Revealed type is "main.Book" diff --git a/tox.ini b/tox.ini index 9010d318..c1d63d2f 100644 --- a/tox.ini +++ b/tox.ini @@ -35,6 +35,9 @@ passenv = POSTGRES_HOST POSTGRES_DATABASE deps = + pytest + pytest-mypy-plugins + django-types alchemy: SQLAlchemy alchemy: sqlalchemy_utils mongo: mongoengine From acf5cc32536550d7351568c44410f06a6b8c14b5 Mon Sep 17 00:00:00 2001 From: Serhii Tereshchenko Date: Thu, 18 Jan 2024 11:53:28 +0200 Subject: [PATCH 03/12] fix: Run type-check also on pypy --- Makefile | 4 +++- tox.ini | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8f283891..8c43f070 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,9 @@ test: -Wdefault:"'cgi' is deprecated and slated for removal in Python 3.13":DeprecationWarning:: \ -Wdefault:"datetime.datetime.utcfromtimestamp() is deprecated and scheduled for removal in a future version.":DeprecationWarning:: \ -m unittest - # Consider using pytest for entire test run (it just works) + +# Consider using pytest for entire test run (it just works) +test-types: pytest tests/typecheck --mypy-only-local-stub # DOC: Test the examples diff --git a/tox.ini b/tox.ini index c1d63d2f..cf3acc08 100644 --- a/tox.ini +++ b/tox.ini @@ -5,6 +5,7 @@ envlist = docs examples linkcheck + py{38,39,310,311,py39,py310}-typecheck py{38,39,310,311,312,py39,py310}-sqlite py{38,39,310,311,py39,py310}-django32-mongo-alchemy-{sqlite,postgres} py{38,39,310,311,py39,py310}-django41-mongo-alchemy-{sqlite,postgres} From 28112c304a7a133a9c3b3c920c4298eb85dcde84 Mon Sep 17 00:00:00 2001 From: Serhii Tereshchenko Date: Sat, 14 Oct 2023 11:25:16 +0300 Subject: [PATCH 04/12] feat: Support correct return type for Factory() call (pyright-only) --- factory/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/factory/base.py b/factory/base.py index 796f3d65..84c151fe 100644 --- a/factory/base.py +++ b/factory/base.py @@ -415,7 +415,7 @@ class BaseFactory(Generic[T]): UnknownStrategy = errors.UnknownStrategy UnsupportedStrategy = errors.UnsupportedStrategy - def __new__(cls, *args, **kwargs): + def __new__(cls, *args, **kwargs) -> T: """Would be called if trying to instantiate the class.""" raise errors.FactoryError('You cannot instantiate BaseFactory') From 1658cb27a58f8ce089c10f1ba6c4fbfa46c6e571 Mon Sep 17 00:00:00 2001 From: Serhii Tereshchenko Date: Wed, 17 Jan 2024 13:12:20 +0200 Subject: [PATCH 05/12] Split typecheck into its own environment --- .github/workflows/test.yml | 7 ++++--- tox.ini | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dc279ad4..e1f40ace 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ concurrency: jobs: tests: - name: Python ${{ matrix.python-version }}, Database ${{ matrix.database-type }} + name: Python ${{ matrix.python-version }}, Database ${{ matrix.environment }} runs-on: ubuntu-latest strategy: @@ -24,9 +24,10 @@ jobs: - "3.12" - "pypy-3.9" - "pypy-3.10" - database-type: + environment: - "sqlite" - "postgres" + - "typecheck" services: mongodb: @@ -56,4 +57,4 @@ jobs: - name: Run tests run: tox env: - DATABASE_TYPE: ${{ matrix.database-type }} + DATABASE_TYPE: ${{ matrix.environment }} diff --git a/tox.ini b/tox.ini index cf3acc08..a1438476 100644 --- a/tox.ini +++ b/tox.ini @@ -26,7 +26,8 @@ python = pypy-3.10: pypy310 [gh-actions:env] -DATABASE_TYPE = +ENVIRONMENT = + typecheck: typecheck sqlite: sqlite postgres: postgres From fb42aa861cbbbadec49955c9f973015a5a9e16e3 Mon Sep 17 00:00:00 2001 From: Serhii Tereshchenko Date: Wed, 17 Jan 2024 13:05:22 +0200 Subject: [PATCH 06/12] Apply suggestions from code review Co-authored-by: Viicos --- factory/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/factory/base.py b/factory/base.py index 84c151fe..7009efa1 100644 --- a/factory/base.py +++ b/factory/base.py @@ -514,7 +514,7 @@ def build(cls, **kwargs) -> T: return cls._generate(enums.BUILD_STRATEGY, kwargs) @classmethod - def build_batch(cls, size, **kwargs) -> List[T]: + def build_batch(cls, size: int, **kwargs) -> List[T]: """Build a batch of instances of the given class, with overridden attrs. Args: @@ -531,7 +531,7 @@ def create(cls, **kwargs) -> T: return cls._generate(enums.CREATE_STRATEGY, kwargs) @classmethod - def create_batch(cls, size, **kwargs) -> List[T]: + def create_batch(cls, size: int, **kwargs) -> List[T]: """Create a batch of instances of the given class, with overridden attrs. Args: From f5000598862845b9a69d254a82dc6ae1dfea2250 Mon Sep 17 00:00:00 2001 From: Serhii Tereshchenko Date: Thu, 18 Jan 2024 11:55:21 +0200 Subject: [PATCH 07/12] chore: Rename env --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e1f40ace..c373f5e4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ concurrency: jobs: tests: - name: Python ${{ matrix.python-version }}, Database ${{ matrix.environment }} + name: Python ${{ matrix.python-version }}, Env ${{ matrix.environment }} runs-on: ubuntu-latest strategy: From 2ef6f9454ab5ad35ff4f0e9ba72c7a7c72fb58e0 Mon Sep 17 00:00:00 2001 From: Serhii Tereshchenko Date: Thu, 18 Jan 2024 11:59:49 +0200 Subject: [PATCH 08/12] fix: Fix workflow variable --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c373f5e4..1fd738d6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -57,4 +57,4 @@ jobs: - name: Run tests run: tox env: - DATABASE_TYPE: ${{ matrix.environment }} + ENVIRONMENT: ${{ matrix.environment }} From a4ce9fa2702b81cf538d9bcbb12a97bf3bbf81e2 Mon Sep 17 00:00:00 2001 From: Serhii Tereshchenko Date: Thu, 18 Jan 2024 12:05:05 +0200 Subject: [PATCH 09/12] fix: Make sure typing tests is run during CI --- tox.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tox.ini b/tox.ini index a1438476..3fee469f 100644 --- a/tox.ini +++ b/tox.ini @@ -86,3 +86,7 @@ extras = dev whitelist_externals = make commands = make lint + +[testenv:typecheck] +whitelist_externals = make +commands = make test-types From a263022fb6362d93098318e0f8a469fe947a304e Mon Sep 17 00:00:00 2001 From: Serhii Tereshchenko Date: Thu, 18 Jan 2024 12:12:56 +0200 Subject: [PATCH 10/12] fix: Fix tox env names --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 3fee469f..4e5e63e1 100644 --- a/tox.ini +++ b/tox.ini @@ -87,6 +87,6 @@ extras = dev whitelist_externals = make commands = make lint -[testenv:typecheck] +[testenv:py{38,39,310,311,py39,py310}-typecheck] whitelist_externals = make commands = make test-types From 03ccbd4b1828034ebcbb46c8963f4b9cd20c7f3e Mon Sep 17 00:00:00 2001 From: Serhii Tereshchenko Date: Thu, 18 Jan 2024 12:36:17 +0200 Subject: [PATCH 11/12] Update tox.ini MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François Freitag --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 4e5e63e1..a99625e4 100644 --- a/tox.ini +++ b/tox.ini @@ -87,6 +87,6 @@ extras = dev whitelist_externals = make commands = make lint -[testenv:py{38,39,310,311,py39,py310}-typecheck] +[testenv:py{38,39,310,311,312,py39,py310}-typecheck] whitelist_externals = make commands = make test-types From f8d9807e73edb12eabfb9e6a9de045cbc6df5ed4 Mon Sep 17 00:00:00 2001 From: Serhii Tereshchenko Date: Thu, 18 Jan 2024 12:36:28 +0200 Subject: [PATCH 12/12] Update tox.ini MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François Freitag --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index a99625e4..2c253b62 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ envlist = docs examples linkcheck - py{38,39,310,311,py39,py310}-typecheck + py{38,39,310,311,312,py39,py310}-typecheck py{38,39,310,311,312,py39,py310}-sqlite py{38,39,310,311,py39,py310}-django32-mongo-alchemy-{sqlite,postgres} py{38,39,310,311,py39,py310}-django41-mongo-alchemy-{sqlite,postgres}