Skip to content

Commit 41bb6d1

Browse files
authored
Merge pull request #90 from HackSoftware/add-django-stubs
mypy / django-stubs support
2 parents a8537fb + 2be0f66 commit 41bb6d1

File tree

10 files changed

+71
-86
lines changed

10 files changed

+71
-86
lines changed

.github/workflows/django.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ jobs:
2424
run: |
2525
python -m pip install --upgrade pip
2626
pip install -r requirements/local.txt
27-
pip install -r requirements/tests.txt
27+
- name: Type check
28+
run: mypy styleguide_example/
2829
- name: Run migrations
2930
run: python manage.py migrate
3031
- name: Run tests

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ Few important things:
2222
* It comes with [`whitenoise`](http://whitenoise.evans.io/en/stable/) setup.
2323
* It can be easily deployed to Heroku.
2424
* It comes with an example list API, that uses [`django-filter`](https://django-filter.readthedocs.io/en/stable/) for filtering & pagination from DRF.
25+
* It comes with [`mypy`](https://mypy.readthedocs.io/en/stable/) configured, using both <https://github.com/typeddjango/django-stubs> and <https://github.com/typeddjango/djangorestframework-stubs/>
26+
* Basic `mypy` configuration is located in [`setup.cfg`](setup.cfg)
27+
* `mypy` is ran as a build step in [`.github/workflows/django.yml`](.github/workflows/django.yml)
2528

2629
## General API Stuff
2730

requirements/local.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
pytest==6.2.5
44
pytest-django==4.5.2
5+
6+
factory-boy==3.2.1
7+
Faker==11.3.0
8+
59
flake8==4.0.1
10+
611
ipdb==0.13.9
712
ipython==7.31.0
13+
14+
mypy==0.931
15+
django-stubs==1.9.0
16+
djangorestframework-stubs==1.4.0

requirements/tests.txt

Lines changed: 0 additions & 6 deletions
This file was deleted.

setup.cfg

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,39 @@ exclude =
44
.git,
55
__pycache__,
66
*/migrations/*
7+
8+
[mypy]
9+
plugins =
10+
mypy_django_plugin.main,
11+
mypy_drf_plugin.main
12+
13+
[mypy.plugins.django-stubs]
14+
django_settings_module = "config.django.base"
15+
16+
[mypy-config.*]
17+
# Ignore everything related to Django config
18+
ignore_errors = true
19+
20+
[mypy-styleguide_example.*.migrations.*]
21+
# Ignore Django migrations
22+
ignore_errors = true
23+
24+
[mypy-celery.*]
25+
# Remove this when celery stubs are present
26+
ignore_missing_imports = True
27+
28+
[mypy-django_celery_beat.*]
29+
# Remove this when django_celery_beat stubs are present
30+
ignore_missing_imports = True
31+
32+
[mypy-django_filters.*]
33+
# Remove this when django_filters stubs are present
34+
ignore_missing_imports = True
35+
36+
[mypy-factory.*]
37+
# Remove this when factory stubs are present
38+
ignore_missing_imports = True
39+
40+
[mypy-rest_framework_jwt.*]
41+
# Remove this when rest_framework_jwt stubs are present
42+
ignore_missing_imports = True

styleguide_example/api/mixins.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
from typing import Sequence, Type, TYPE_CHECKING
2+
13
from importlib import import_module
24

35
from django.conf import settings
46

57
from django.contrib import auth
68

7-
from rest_framework.permissions import IsAuthenticated
9+
from rest_framework.permissions import IsAuthenticated, BasePermission
810
from rest_framework.authentication import SessionAuthentication, BaseAuthentication
911

1012
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
@@ -60,10 +62,20 @@ def enforce_csrf(self, request):
6062
return
6163

6264

65+
if TYPE_CHECKING:
66+
# This is going to be resolved in the stub library
67+
# https://github.com/typeddjango/djangorestframework-stubs/
68+
from rest_framework.permissions import _PermissionClass
69+
70+
PermissionClassesType = Sequence[_PermissionClass]
71+
else:
72+
PermissionClassesType = Sequence[Type[BasePermission]]
73+
74+
6375
class ApiAuthMixin:
64-
authentication_classes = (
76+
authentication_classes: Sequence[Type[BaseAuthentication]] = [
6577
CsrfExemptedSessionAuthentication,
6678
SessionAsHeaderAuthentication,
6779
JSONWebTokenAuthentication
68-
)
69-
permission_classes = (IsAuthenticated, )
80+
]
81+
permission_classes: PermissionClassesType = (IsAuthenticated, )

styleguide_example/common/types.py

Lines changed: 0 additions & 70 deletions
This file was deleted.

styleguide_example/testing_examples/selectors/schools.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from datetime import date
2-
from typing import Optional, Iterable
2+
from typing import Optional
33

4-
from django.db.models.query import Q
4+
from django.db.models.query import Q, QuerySet
55
from django.core.exceptions import ValidationError
66

77
from styleguide_example.testing_examples.models import School, SchoolCourse
@@ -16,7 +16,7 @@ def school_list_school_courses(
1616
school: School,
1717
start_date: Optional[date] = None,
1818
end_date: Optional[date] = None
19-
) -> Iterable[SchoolCourse]:
19+
) -> QuerySet[SchoolCourse]:
2020
if start_date is None and end_date:
2121
raise ValidationError(SCHOOL_LIST_SCHOOL_COURSES_PROVIDE_START_DATE_MSG)
2222

styleguide_example/users/selectors.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from styleguide_example.common.types import QuerySetType
1+
from django.db.models.query import QuerySet
22

33
from styleguide_example.users.models import BaseUser
44
from styleguide_example.users.filters import BaseUserFilter
@@ -14,7 +14,7 @@ def user_get_login_data(*, user: BaseUser):
1414
}
1515

1616

17-
def user_list(*, filters=None) -> QuerySetType[BaseUser]:
17+
def user_list(*, filters=None) -> QuerySet[BaseUser]:
1818
filters = filters or {}
1919

2020
qs = BaseUser.objects.all()

styleguide_example/utils/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)