From 824915d732ef4d94d2580c4e7a30969553d8c131 Mon Sep 17 00:00:00 2001 From: Peter Law Date: Mon, 8 Jan 2024 22:25:01 +0000 Subject: [PATCH] Minimally annotate the tests This gets the tests passing type checking without requiring that they're fully annotated. --- .github/workflows/ci.yml | 2 +- src/devdata/py.typed | 0 tests/conftest.py | 2 +- tests/test_circular_fk.py | 6 +++++- tests/test_fk_restriction.py | 6 +++++- tests/test_infrastructure/base.py | 21 +++++++++++++++------ tests/test_infrastructure/factories.py | 9 ++++++--- tests/test_infrastructure/utils.py | 8 +++++--- tests/testsite/testsite/settings/devdata.py | 11 ++++++++--- tests/testsite/testsite/settings/django.py | 4 +++- 10 files changed, 49 insertions(+), 20 deletions(-) create mode 100644 src/devdata/py.typed diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 865eac6..7f499a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -127,7 +127,7 @@ jobs: - name: Type-check run: | - poetry run mypy src + poetry run mypy src tests validate-dependencies: name: Check dependency locks diff --git a/src/devdata/py.typed b/src/devdata/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py index cbe7949..fa72b38 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -28,7 +28,7 @@ @pytest.fixture() -def test_data_dir(): +def test_data_dir() -> Path: return Path(__file__).parent / "test-data-tmp" diff --git a/tests/test_circular_fk.py b/tests/test_circular_fk.py index 1bf7c0a..d029868 100644 --- a/tests/test_circular_fk.py +++ b/tests/test_circular_fk.py @@ -1,9 +1,13 @@ +from __future__ import annotations + +from typing import Any + from test_infrastructure import DevdataTestBase from turtles.models import Turtle, World class TestCircularFK(DevdataTestBase): - def get_original_data(self): + def get_original_data(self) -> list[dict[str, Any]]: return [ { "model": "turtles.Turtle", diff --git a/tests/test_fk_restriction.py b/tests/test_fk_restriction.py index 662bff8..306938b 100644 --- a/tests/test_fk_restriction.py +++ b/tests/test_fk_restriction.py @@ -1,9 +1,13 @@ +from __future__ import annotations + +from typing import Any + from django.contrib.auth.models import User from test_infrastructure import DevdataTestBase, make_photo_data, make_user_data class TestFKRestriction(DevdataTestBase): - def get_original_data(self): + def get_original_data(self) -> list[dict[str, Any]]: return [ # Internal user (included) make_user_data(101, "internal", is_superuser=True), diff --git a/tests/test_infrastructure/base.py b/tests/test_infrastructure/base.py index 0824d4c..e8c01f4 100644 --- a/tests/test_infrastructure/base.py +++ b/tests/test_infrastructure/base.py @@ -3,7 +3,8 @@ import collections import itertools import json -from typing import Any, Dict, Iterable, Set +from pathlib import Path +from typing import Any, Dict, Iterable import pytest from django.core import serializers @@ -21,7 +22,7 @@ class DevdataTestBase: # Public API for tests - def get_original_data(self): + def get_original_data(self) -> list[TestObject]: raise NotImplementedError def assert_on_exported_data(self, exported_data): @@ -48,12 +49,16 @@ def exported_pks(self, exported_data, model, strategy=None): return set(x["pk"] for x in exported) def _filter_exported( - self, lookup: Dict[str, Set], objects: Iterable[TestObject] + self, + lookup: dict[str, set[Any]], + objects: list[TestObject], ) -> Iterable[TestObject]: obj = objects[0] # Same model so we just use the first for structure model_name = obj["model"] model = to_model(model_name) + assert model, model_name + fk_fields = [ (x.attname, to_app_model_label(x.related_model)) for x in model._meta.fields @@ -71,13 +76,17 @@ def _filter_exported( ): yield obj - def dump_data_for_import(self, original_data, test_data_dir): + def dump_data_for_import( + self, + original_data: list[TestObject], + test_data_dir: Path, + ) -> None: # Write out data to the filesystem as if it had been exported - data: dict[str, dict[str, TestObject]] + data: dict[str, dict[str, list[TestObject]]] data = collections.defaultdict( lambda: collections.defaultdict(list), ) - exported_pks: dict[str, set] = collections.defaultdict(set) + exported_pks: dict[str, set[Any]] = collections.defaultdict(set) for obj in original_data: if obj["strategy"] is None: continue diff --git a/tests/test_infrastructure/factories.py b/tests/test_infrastructure/factories.py index 132c0f4..afb527f 100644 --- a/tests/test_infrastructure/factories.py +++ b/tests/test_infrastructure/factories.py @@ -6,7 +6,7 @@ def make_photo_data( - pk: int, strategy: Optional[str], **fields + pk: int, strategy: Optional[str], **fields: Any ) -> Dict[str, Any]: return { "model": "photofeed.Photo", @@ -24,11 +24,14 @@ def make_photo_data( def make_user_data( - pk: int, strategy: Optional[str], **fields + pk: int, strategy: Optional[str], **fields: Any ) -> Dict[str, Any]: return { "model": "auth.User", "strategy": strategy, "pk": pk, - "fields": {"username": fake.user_name(), **fields}, + "fields": { + "username": fake.user_name(), # type: ignore[attr-defined] + **fields, + }, } diff --git a/tests/test_infrastructure/utils.py b/tests/test_infrastructure/utils.py index f6ec7c0..7688bfb 100644 --- a/tests/test_infrastructure/utils.py +++ b/tests/test_infrastructure/utils.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import subprocess @@ -17,9 +19,9 @@ def run_command(*command, **kwargs): # the pytest environment. "TEST_DATABASE_NAME": settings.DATABASES["default"]["NAME"], }, - **kwargs + **kwargs, ) -def assert_ran_successfully(process: subprocess.Popen): - assert process.returncode == 0, process.stderr.decode("utf-8") +def assert_ran_successfully(process: subprocess.Popen[bytes]) -> None: + assert process.returncode == 0, process.stderr.decode("utf-8") # type: ignore[union-attr] diff --git a/tests/testsite/testsite/settings/devdata.py b/tests/testsite/testsite/settings/devdata.py index 61fd6c7..011794f 100644 --- a/tests/testsite/testsite/settings/devdata.py +++ b/tests/testsite/testsite/settings/devdata.py @@ -2,17 +2,22 @@ devdata settings for tests. """ +from __future__ import annotations + +from typing import Any + from devdata.strategies import ( ExactQuerySetStrategy, LatestSampleQuerySetStrategy, QuerySetStrategy, RandomSampleQuerySetStrategy, ) +from devdata.types import Anonymiser from ..custom_strategies import InternalUsersStrategy -DEVDATA_FIELD_ANONYMISERS = {} -DEVDATA_MODEL_ANONYMISERS = {} +DEVDATA_FIELD_ANONYMISERS: dict[str, Anonymiser] = {} +DEVDATA_MODEL_ANONYMISERS: dict[str, dict[str, Anonymiser]] = {} DEVDATA_DEFAULT_STRATEGY = QuerySetStrategy(name="default") @@ -77,6 +82,6 @@ ], } -DEVDATA_EXTRA_STRATEGIES = [ +DEVDATA_EXTRA_STRATEGIES: list[tuple[str, dict[str, Any]]] = [ ("devdata.extras.PostgresSequences", {}), ] diff --git a/tests/testsite/testsite/settings/django.py b/tests/testsite/testsite/settings/django.py index 8c255c5..6f520e0 100644 --- a/tests/testsite/testsite/settings/django.py +++ b/tests/testsite/testsite/settings/django.py @@ -2,6 +2,8 @@ Django default settings, customised as necessary for testing. """ +from __future__ import annotations + import os from pathlib import Path @@ -11,7 +13,7 @@ DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS: list[str] = [] INSTALLED_APPS = [ "django.contrib.admin",