Skip to content

Commit 0fcfc11

Browse files
authored
Merge pull request jazzband#601 from ProtixIT/mypy-in-ci
Enable static type checks using mypy in CI
2 parents 4c9d6ee + c75e54a commit 0fcfc11

File tree

7 files changed

+54
-18
lines changed

7 files changed

+54
-18
lines changed

model_utils/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
__version__ = importlib.metadata.version('django-model-utils')
88
except importlib.metadata.PackageNotFoundError: # pragma: no cover
99
# package is not installed
10-
__version__ = None
10+
__version__ = None # type: ignore[assignment]
1111

1212
__all__ = ("Choices", "FieldTracker", "ModelTracker")

mypy.ini

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[mypy]
2+
implicit_reexport=False
3+
pretty=True
4+
show_error_codes=True
5+
strict_equality=True
6+
warn_redundant_casts=True
7+
warn_unreachable=True
8+
warn_unused_ignores=True
9+
10+
mypy_path = $MYPY_CONFIG_FILE_DIR
11+
12+
plugins =
13+
mypy_django_plugin.main
14+
15+
[mypy.plugins.django-stubs]
16+
django_settings_module = "tests.settings"

requirements-mypy.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
mypy==1.9.0
2+
django-stubs==4.2.7

tests/models.py

+13-9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
from __future__ import annotations
2+
3+
from typing import ClassVar
4+
15
from django.db import models
26
from django.db.models import Manager
37
from django.db.models.query_utils import DeferredAttribute
@@ -32,7 +36,7 @@ class InheritanceManagerTestParent(models.Model):
3236
related_self = models.OneToOneField(
3337
"self", related_name="imtests_self", null=True,
3438
on_delete=models.CASCADE)
35-
objects = InheritanceManager()
39+
objects: ClassVar[InheritanceManager[InheritanceManagerTestParent]] = InheritanceManager()
3640

3741
def __str__(self):
3842
return "{}({})".format(
@@ -44,7 +48,7 @@ def __str__(self):
4448
class InheritanceManagerTestChild1(InheritanceManagerTestParent):
4549
non_related_field_using_descriptor_2 = models.FileField(upload_to="test")
4650
normal_field_2 = models.TextField()
47-
objects = InheritanceManager()
51+
objects: ClassVar[InheritanceManager[InheritanceManagerTestParent]] = InheritanceManager()
4852

4953

5054
class InheritanceManagerTestGrandChild1(InheritanceManagerTestChild1):
@@ -172,8 +176,8 @@ class Post(models.Model):
172176
order = models.IntegerField()
173177

174178
objects = models.Manager()
175-
public = QueryManager(published=True)
176-
public_confirmed = QueryManager(
179+
public: ClassVar[QueryManager[Post]] = QueryManager(published=True)
180+
public_confirmed: ClassVar[QueryManager[Post]] = QueryManager(
177181
models.Q(published=True) & models.Q(confirmed=True))
178182
public_reversed = QueryManager(published=True).order_by("-order")
179183

@@ -194,7 +198,7 @@ class Meta:
194198

195199

196200
class AbstractTracked(models.Model):
197-
number = 1
201+
number: models.IntegerField
198202

199203
class Meta:
200204
abstract = True
@@ -340,13 +344,13 @@ class SoftDeletable(SoftDeletableModel):
340344
"""
341345
name = models.CharField(max_length=20)
342346

343-
all_objects = models.Manager()
347+
all_objects: ClassVar[Manager[SoftDeletable]] = models.Manager()
344348

345349

346350
class CustomSoftDelete(SoftDeletableModel):
347351
is_read = models.BooleanField(default=False)
348352

349-
objects = CustomSoftDeleteManager()
353+
objects: ClassVar[CustomSoftDeleteManager[SoftDeletableModel]] = CustomSoftDeleteManager()
350354

351355

352356
class StringyDescriptor:
@@ -390,7 +394,7 @@ class ModelWithCustomDescriptor(models.Model):
390394

391395
class BoxJoinModel(models.Model):
392396
name = models.CharField(max_length=32)
393-
objects = JoinManager()
397+
objects: ClassVar[JoinManager[BoxJoinModel]] = JoinManager()
394398

395399

396400
class JoinItemForeignKey(models.Model):
@@ -400,7 +404,7 @@ class JoinItemForeignKey(models.Model):
400404
null=True,
401405
on_delete=models.CASCADE
402406
)
403-
objects = JoinManager()
407+
objects: ClassVar[JoinManager[JoinItemForeignKey]] = JoinManager()
404408

405409

406410
class CustomUUIDModel(UUIDModel):

tests/settings.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"USER": os.environ.get("POSTGRES_USER", 'postgres'),
2020
"PASSWORD": os.environ.get("POSTGRES_PASSWORD", ""),
2121
"HOST": os.environ.get("POSTGRES_HOST", "localhost"),
22-
"PORT": os.environ.get("POSTGRES_PORT", 5432)
22+
"PORT": os.environ.get("POSTGRES_PORT", "5432")
2323
},
2424
}
2525
SECRET_KEY = 'dummy'

tests/test_fields/test_field_tracker.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
from __future__ import annotations
2+
13
from unittest import skip
24

35
from django.core.cache import cache
46
from django.core.exceptions import FieldError
7+
from django.db import models
58
from django.db.models.fields.files import FieldFile
69
from django.test import TestCase
710

@@ -73,7 +76,7 @@ def test_pre_save_previous(self):
7376

7477
class FieldTrackerTests(FieldTrackerTestCase, FieldTrackerCommonTests):
7578

76-
tracked_class = Tracked
79+
tracked_class: type[models.Model] = Tracked
7780

7881
def setUp(self):
7982
self.instance = self.tracked_class()
@@ -280,7 +283,7 @@ def test_with_deferred_fields_access_multiple(self):
280283
class FieldTrackedModelCustomTests(FieldTrackerTestCase,
281284
FieldTrackerCommonTests):
282285

283-
tracked_class = TrackedNotDefault
286+
tracked_class: type[models.Model] = TrackedNotDefault
284287

285288
def setUp(self):
286289
self.instance = self.tracked_class()
@@ -411,7 +414,7 @@ def test_current(self):
411414
class FieldTrackedModelMultiTests(FieldTrackerTestCase,
412415
FieldTrackerCommonTests):
413416

414-
tracked_class = TrackedMultiple
417+
tracked_class: type[models.Model] = TrackedMultiple
415418

416419
def setUp(self):
417420
self.instance = self.tracked_class()
@@ -502,8 +505,8 @@ def test_current(self):
502505

503506
class FieldTrackerForeignKeyTests(FieldTrackerTestCase):
504507

505-
fk_class = Tracked
506-
tracked_class = TrackedFK
508+
fk_class: type[models.Model] = Tracked
509+
tracked_class: type[models.Model] = TrackedFK
507510

508511
def setUp(self):
509512
self.old_fk = self.fk_class.objects.create(number=8)
@@ -729,7 +732,7 @@ def test_current(self):
729732

730733
class ModelTrackerTests(FieldTrackerTests):
731734

732-
tracked_class = ModelTracked
735+
tracked_class: type[models.Model] = ModelTracked
733736

734737
def test_cache_compatible(self):
735738
cache.set('key', self.instance)

tox.ini

+12-1
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ envlist =
88
py{310,311,312}-dj{main}
99
flake8
1010
isort
11+
mypy
1112

1213
[gh-actions]
1314
python =
1415
3.7: py37
15-
3.8: py38, flake8, isort
16+
3.8: py38, flake8, isort, mypy
1617
3.9: py39
1718
3.10: py310
1819
3.11: py311
@@ -63,3 +64,13 @@ deps = isort
6364
commands =
6465
isort model_utils tests setup.py --check-only --diff
6566
skip_install = True
67+
68+
[testenv:mypy]
69+
basepython = python3.8
70+
deps =
71+
time-machine==2.8.2
72+
-r requirements-mypy.txt
73+
set_env =
74+
SQLITE=1
75+
commands =
76+
mypy model_utils tests

0 commit comments

Comments
 (0)