add mypy setup to tox.ini

This commit is contained in:
Maxim Kurnikov 2019-10-11 20:39:39 +03:00
parent 0fd72f17ee
commit 371caaf538
12 changed files with 40 additions and 22 deletions

2
mypy.ini Normal file
View File

@ -0,0 +1,2 @@
[mypy]
ignore_missing_imports = True

View File

@ -0,0 +1 @@
mypy==0.730

View File

@ -117,14 +117,14 @@ except ImportError:
try: try:
import yaml import yaml
except ImportError: except ImportError:
yaml = None yaml = None # type: ignore
# requests is optional # requests is optional
try: try:
import requests import requests
except ImportError: except ImportError:
requests = None requests = None # type: ignore
# PATCH method is not implemented by Django # PATCH method is not implemented by Django
@ -156,7 +156,7 @@ try:
md_filter_add_syntax_highlight(md) md_filter_add_syntax_highlight(md)
return md.convert(text) return md.convert(text)
except ImportError: except ImportError:
apply_markdown = None apply_markdown = None # type: ignore
markdown = None markdown = None

View File

@ -7,6 +7,7 @@ import re
import uuid import uuid
from collections import OrderedDict from collections import OrderedDict
from collections.abc import Mapping from collections.abc import Mapping
from typing import Callable, List, Any, Optional, Dict
from django.conf import settings from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
@ -302,9 +303,9 @@ class Field:
'required': _('This field is required.'), 'required': _('This field is required.'),
'null': _('This field may not be null.') 'null': _('This field may not be null.')
} }
default_validators = [] default_validators = [] # type: List[Callable[[Any], None]]
default_empty_html = empty default_empty_html = empty # type: Optional[Any]
initial = None initial = None # type: Optional[Any]
def __init__(self, read_only=False, write_only=False, def __init__(self, read_only=False, write_only=False,
required=None, default=empty, initial=empty, source=None, required=None, default=empty, initial=empty, source=None,
@ -1456,7 +1457,7 @@ class MultipleChoiceField(ChoiceField):
'not_a_list': _('Expected a list of items but got type "{input_type}".'), 'not_a_list': _('Expected a list of items but got type "{input_type}".'),
'empty': _('This selection may not be empty.') 'empty': _('This selection may not be empty.')
} }
default_empty_html = [] default_empty_html = [] # type: List[Any]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.allow_empty = kwargs.pop('allow_empty', True) self.allow_empty = kwargs.pop('allow_empty', True)
@ -1597,7 +1598,7 @@ class _UnvalidatedField(Field):
class ListField(Field): class ListField(Field):
child = _UnvalidatedField() child = _UnvalidatedField()
initial = [] initial = [] # type: List[Any]
default_error_messages = { default_error_messages = {
'not_a_list': _('Expected a list of items but got type "{input_type}".'), 'not_a_list': _('Expected a list of items but got type "{input_type}".'),
'empty': _('This list may not be empty.'), 'empty': _('This list may not be empty.'),
@ -1675,8 +1676,8 @@ class ListField(Field):
class DictField(Field): class DictField(Field):
child = _UnvalidatedField() child = _UnvalidatedField() # type: Field
initial = {} initial = {} # type: Dict[str, Any]
default_error_messages = { default_error_messages = {
'not_a_dict': _('Expected a dictionary of items but got type "{input_type}".'), 'not_a_dict': _('Expected a dictionary of items but got type "{input_type}".'),
'empty': _('This dictionary may not be empty.'), 'empty': _('This dictionary may not be empty.'),

View File

@ -5,6 +5,7 @@ They give us a generic way of being able to handle various media types
on the request, such as form content or json encoded data. on the request, such as form content or json encoded data.
""" """
import codecs import codecs
from typing import Optional
from urllib import parse from urllib import parse
from django.conf import settings from django.conf import settings
@ -33,7 +34,7 @@ class BaseParser:
All parsers should extend `BaseParser`, specifying a `media_type` All parsers should extend `BaseParser`, specifying a `media_type`
attribute, and overriding the `.parse()` method. attribute, and overriding the `.parse()` method.
""" """
media_type = None media_type = None # type: Optional[str]
def parse(self, stream, media_type=None, parser_context=None): def parse(self, stream, media_type=None, parser_context=None):
""" """

View File

@ -1,5 +1,6 @@
import sys import sys
from collections import OrderedDict from collections import OrderedDict
from typing import List, Any
from urllib import parse from urllib import parse
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
@ -472,8 +473,8 @@ class ManyRelatedField(Field):
You shouldn't generally need to be using this class directly yourself, You shouldn't generally need to be using this class directly yourself,
and should instead simply set 'many=True' on the relationship. and should instead simply set 'many=True' on the relationship.
""" """
initial = [] initial = [] # type: List[Any]
default_empty_html = [] default_empty_html = [] # type: List[Any]
default_error_messages = { default_error_messages = {
'not_a_list': _('Expected a list of items but got type "{input_type}".'), 'not_a_list': _('Expected a list of items but got type "{input_type}".'),
'empty': _('This list may not be empty.') 'empty': _('This list may not be empty.')

View File

@ -8,6 +8,7 @@ REST framework also provides an HTML renderer that renders the browsable API.
""" """
import base64 import base64
from collections import OrderedDict from collections import OrderedDict
from typing import Optional
from urllib import parse from urllib import parse
from django import forms from django import forms
@ -42,9 +43,9 @@ class BaseRenderer:
All renderers should extend this class, setting the `media_type` All renderers should extend this class, setting the `media_type`
and `format` attributes, and override the `.render()` method. and `format` attributes, and override the `.render()` method.
""" """
media_type = None media_type = None # type: Optional[str]
format = None format = None # type: Optional[str]
charset = 'utf-8' charset = 'utf-8' # type: Optional[str]
render_style = 'text' render_style = 'text'
def render(self, data, accepted_media_type=None, renderer_context=None): def render(self, data, accepted_media_type=None, renderer_context=None):

View File

@ -15,6 +15,7 @@ import inspect
import traceback import traceback
from collections import OrderedDict from collections import OrderedDict
from collections.abc import Mapping from collections.abc import Mapping
from typing import Type
from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured
from django.core.exceptions import ValidationError as DjangoValidationError from django.core.exceptions import ValidationError as DjangoValidationError
@ -891,7 +892,7 @@ class ModelSerializer(Serializer):
} }
if ModelDurationField is not None: if ModelDurationField is not None:
serializer_field_mapping[ModelDurationField] = DurationField serializer_field_mapping[ModelDurationField] = DurationField
serializer_related_field = PrimaryKeyRelatedField serializer_related_field = PrimaryKeyRelatedField # type: Type[RelatedField]
serializer_related_to_field = SlugRelatedField serializer_related_to_field = SlugRelatedField
serializer_url_field = HyperlinkedIdentityField serializer_url_field = HyperlinkedIdentityField
serializer_choice_field = ChoiceField serializer_choice_field = ChoiceField

View File

@ -115,7 +115,7 @@ if requests is not None:
return super().request(method, url, *args, **kwargs) return super().request(method, url, *args, **kwargs)
else: else:
def RequestsClient(*args, **kwargs): def RequestsClient(*args, **kwargs): # type: ignore
raise ImproperlyConfigured('requests must be installed in order to use RequestsClient.') raise ImproperlyConfigured('requests must be installed in order to use RequestsClient.')
@ -131,7 +131,7 @@ if coreapi is not None:
return self._session return self._session
else: else:
def CoreAPIClient(*args, **kwargs): def CoreAPIClient(*args, **kwargs): # type: ignore
raise ImproperlyConfigured('coreapi must be installed in order to use CoreAPIClient.') raise ImproperlyConfigured('coreapi must be installed in order to use CoreAPIClient.')

View File

@ -2,6 +2,7 @@
Provides various throttling policies. Provides various throttling policies.
""" """
import time import time
from typing import Optional
from django.core.cache import cache as default_cache from django.core.cache import cache as default_cache
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
@ -62,7 +63,7 @@ class SimpleRateThrottle(BaseThrottle):
cache = default_cache cache = default_cache
timer = time.time timer = time.time
cache_format = 'throttle_%(scope)s_%(ident)s' cache_format = 'throttle_%(scope)s_%(ident)s'
scope = None scope = None # type: Optional[str]
THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
def __init__(self): def __init__(self):

View File

@ -1,6 +1,8 @@
""" """
Provides an APIView class that is the base of all views in REST framework. Provides an APIView class that is the base of all views in REST framework.
""" """
from typing import Optional
from django.conf import settings from django.conf import settings
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.db import connection, models, transaction from django.db import connection, models, transaction
@ -15,6 +17,7 @@ from rest_framework import exceptions, status
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.schemas import DefaultSchema from rest_framework.schemas import DefaultSchema
from rest_framework.schemas.inspectors import ViewInspector
from rest_framework.settings import api_settings from rest_framework.settings import api_settings
from rest_framework.utils import formatting from rest_framework.utils import formatting
@ -116,7 +119,7 @@ class APIView(View):
# Allow dependency injection of other settings to make testing easier. # Allow dependency injection of other settings to make testing easier.
settings = api_settings settings = api_settings
schema = DefaultSchema() schema = DefaultSchema() # type: Optional[ViewInspector]
@classmethod @classmethod
def as_view(cls, **initkwargs): def as_view(cls, **initkwargs):

View File

@ -5,7 +5,7 @@ envlist =
{py35,py36,py37}-django21 {py35,py36,py37}-django21
{py35,py36,py37}-django22 {py35,py36,py37}-django22
{py36,py37}-djangomaster, {py36,py37}-djangomaster,
base,dist,lint,docs, base,dist,lint,docs,mypy,
[travis:env] [travis:env]
DJANGO = DJANGO =
@ -57,3 +57,9 @@ commands = mkdocs build
deps = deps =
-rrequirements/requirements-testing.txt -rrequirements/requirements-testing.txt
-rrequirements/requirements-documentation.txt -rrequirements/requirements-documentation.txt
[testenv:mypy]
basepython = python3.7
commands = mypy ./rest_framework
deps =
-rrequirements/requirements-mypy.txt