diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ *.tar.bz2 *.tar.lzma .tox/ +.mypy_cache/ diff --git a/MANIFEST.in b/MANIFEST.in --- a/MANIFEST.in +++ b/MANIFEST.in @@ -8,3 +8,4 @@ recursive-include swh/deposit/static * recursive-include swh/deposit/fixtures * recursive-include swh/deposit/templates * +recursive-include swh py.typed diff --git a/Makefile.local b/Makefile.local --- a/Makefile.local +++ b/Makefile.local @@ -28,3 +28,10 @@ test: ./swh/deposit/manage.py test + +# Override default rule to make sure DJANGO env var is properly set. It +# *should* work without any override thanks to the mypy django-stubs plugin, +# but it currently doesn't; see +# https://github.com/typeddjango/django-stubs/issues/166 +typecheck: + DJANGO_SETTINGS_MODULE=swh.deposit.settings.testing $(MYPY) $(MYPYFLAGS) -p $(PYMODULE) diff --git a/mypy.ini b/mypy.ini new file mode 100644 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,31 @@ +[mypy] +namespace_packages = True +warn_unused_ignores = True + + +# support for django magic: https://github.com/typeddjango/django-stubs +plugins = mypy_django_plugin.main + +[mypy.plugins.django-stubs] +django_settings_module = swh.deposit.settings.testing + + +# 3rd party libraries without stubs (yet) + +[mypy-celery.*] +ignore_missing_imports = True + +[mypy-iso8601.*] +ignore_missing_imports = True + +[mypy-pkg_resources.*] +ignore_missing_imports = True + +[mypy-pytest.*] +ignore_missing_imports = True + +[mypy-rest_framework.*] +ignore_missing_imports = True + +[mypy-xmltodict.*] +ignore_missing_imports = True diff --git a/requirements-test.txt b/requirements-test.txt --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,3 +1,4 @@ pytest<4 pytest-django swh.scheduler[testing] +django-stubs diff --git a/swh/deposit/api/common.py b/swh/deposit/api/common.py --- a/swh/deposit/api/common.py +++ b/swh/deposit/api/common.py @@ -5,6 +5,8 @@ import hashlib +from typing import Any, Tuple + from abc import ABCMeta, abstractmethod from django.urls import reverse from django.http import HttpResponse @@ -46,7 +48,7 @@ authentication check """ - authentication_classes = (BasicAuthentication, ) + authentication_classes: Tuple[Any, ...] = (BasicAuthentication, ) permission_classes = (IsAuthenticated, ) diff --git a/swh/deposit/config.py b/swh/deposit/config.py --- a/swh/deposit/config.py +++ b/swh/deposit/config.py @@ -6,6 +6,8 @@ import os import logging +from typing import Any, Dict, Tuple + from swh.core.config import SWHConfig from swh.scheduler import get_scheduler @@ -97,7 +99,7 @@ }) } - ADDITIONAL_CONFIG = {} + ADDITIONAL_CONFIG: Dict[str, Tuple[str, Any]] = {} def __init__(self, **config): super().__init__() diff --git a/swh/deposit/models.py b/swh/deposit/models.py --- a/swh/deposit/models.py +++ b/swh/deposit/models.py @@ -76,7 +76,10 @@ """ collections = ArrayField(models.IntegerField(), null=True) - objects = UserManager() + objects = UserManager() # type: ignore + # this typing hint is due to a mypy/django-stubs limitation, + # see https://github.com/typeddjango/django-stubs/issues/174 + provider_url = models.TextField(null=False) domain = models.TextField(null=False) @@ -121,7 +124,7 @@ default=DEPOSIT_STATUS_PARTIAL) status_detail = JSONField(null=True) # deposit can have one parent - parent = models.ForeignKey('self', null=True) + parent = models.ForeignKey('self', on_delete=models.PROTECT, null=True) check_task_id = models.TextField( blank=True, null=True, verbose_name="Scheduler's associated checking task id" diff --git a/swh/deposit/py.typed b/swh/deposit/py.typed new file mode 100644 --- /dev/null +++ b/swh/deposit/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561. diff --git a/swh/deposit/tests/__init__.py b/swh/deposit/tests/__init__.py --- a/swh/deposit/tests/__init__.py +++ b/swh/deposit/tests/__init__.py @@ -67,7 +67,7 @@ # monkey patch classes method permits to override, for tests purposes, # the default configuration without side-effect, i.e do not load the # configuration from disk -SWHDefaultConfig.parse_config_file = parse_deposit_config_file -BufferedLoader.parse_config_file = parse_loader_config_file +SWHDefaultConfig.parse_config_file = parse_deposit_config_file # type: ignore +BufferedLoader.parse_config_file = parse_loader_config_file # type: ignore setup_django_for('testing') diff --git a/swh/deposit/tests/loader/conftest.py b/swh/deposit/tests/loader/conftest.py --- a/swh/deposit/tests/loader/conftest.py +++ b/swh/deposit/tests/loader/conftest.py @@ -2,7 +2,7 @@ from swh.scheduler.tests.conftest import * # noqa -@pytest.fixture(scope='session') +@pytest.fixture(scope='session') # type: ignore # expected redefinition def celery_includes(): return [ 'swh.deposit.loader.tasks',