attempt to add flake8 and isort

This commit is contained in:
Maxim Kurnikov
2019-03-01 02:07:53 +03:00
parent 70c3126348
commit c962b8ac68
16 changed files with 142 additions and 72 deletions

View File

@@ -4,10 +4,6 @@ dist: xenial
sudo: required sudo: required
jobs: jobs:
include: include:
- name: Typecheck Django test suite
python: 3.7
script: 'python ./scripts/typecheck_tests.py'
- name: Run plugin test suite with python 3.7 - name: Run plugin test suite with python 3.7
python: 3.7 python: 3.7
script: | script: |
@@ -20,10 +16,22 @@ jobs:
set -e set -e
pytest pytest
- name: Typecheck Django test suite
python: 3.7
script: 'python ./scripts/typecheck_tests.py'
- name: Lint with black - name: Lint with black
python: 3.7 python: 3.7
script: 'black --check --line-length=120 django-stubs/' script: 'black --check --line-length=120 django-stubs/'
- name: Lint plugin code with flake8
python: 3.7
script: 'flake8'
- name: Lint plugin code with isort
python: 3.7
script: 'isort --check'
before_install: | before_install: |
# Upgrade pip, setuptools, and wheel # Upgrade pip, setuptools, and wheel
pip install -U pip setuptools wheel pip install -U pip setuptools wheel

View File

@@ -1,3 +1,5 @@
black black
pytest-mypy-plugins pytest-mypy-plugins
flake8
isort==4.3.4
-e . -e .

View File

@@ -1,5 +1,5 @@
from configparser import ConfigParser from configparser import ConfigParser
from typing import List, Optional from typing import Optional
from dataclasses import dataclass from dataclasses import dataclass
@@ -16,10 +16,12 @@ class Config:
if not ini_config.has_section('mypy_django_plugin'): if not ini_config.has_section('mypy_django_plugin'):
raise ValueError('Invalid config file: no [mypy_django_plugin] section') raise ValueError('Invalid config file: no [mypy_django_plugin] section')
django_settings = ini_config.get('mypy_django_plugin', 'django_settings', django_settings = ini_config.get('mypy_django_plugin', 'django_settings')
fallback=None) if type(django_settings) == object:
if django_settings: django_settings = None
else:
django_settings = django_settings.strip() django_settings = django_settings.strip()
return Config(django_settings_module=django_settings, return Config(django_settings_module=django_settings,
ignore_missing_settings=ini_config.get('mypy_django_plugin', 'ignore_missing_settings', ignore_missing_settings=bool(ini_config.get('mypy_django_plugin', 'ignore_missing_settings',
fallback=False)) fallback=False)))

View File

@@ -2,10 +2,13 @@ import typing
from typing import Dict, Optional from typing import Dict, Optional
from mypy.checker import TypeChecker from mypy.checker import TypeChecker
from mypy.nodes import AssignmentStmt, ClassDef, Expression, ImportedName, Lvalue, MypyFile, NameExpr, SymbolNode, \ from mypy.nodes import (
TypeInfo AssignmentStmt, ClassDef, Expression, ImportedName, Lvalue, MypyFile, NameExpr, SymbolNode, TypeInfo,
)
from mypy.plugin import FunctionContext, MethodContext from mypy.plugin import FunctionContext, MethodContext
from mypy.types import AnyType, Instance, NoneTyp, Type, TypeOfAny, TypeVarType, UnionType from mypy.types import (
AnyType, Instance, NoneTyp, Type, TypeOfAny, TypeVarType, UnionType,
)
MODEL_CLASS_FULLNAME = 'django.db.models.base.Model' MODEL_CLASS_FULLNAME = 'django.db.models.base.Model'
FIELD_FULLNAME = 'django.db.models.fields.Field' FIELD_FULLNAME = 'django.db.models.fields.Field'

View File

@@ -2,19 +2,28 @@ import os
from typing import Callable, Dict, Optional, Union, cast from typing import Callable, Dict, Optional, Union, cast
from mypy.checker import TypeChecker from mypy.checker import TypeChecker
from mypy.nodes import MemberExpr, TypeInfo, NameExpr from mypy.nodes import MemberExpr, NameExpr, TypeInfo
from mypy.options import Options from mypy.options import Options
from mypy.plugin import AttributeContext, ClassDefContext, FunctionContext, MethodContext, Plugin from mypy.plugin import (
from mypy.types import AnyType, Instance, Type, TypeOfAny, TypeType, UnionType, CallableType, NoneTyp AttributeContext, ClassDefContext, FunctionContext, MethodContext, Plugin,
)
from mypy.types import (
AnyType, CallableType, Instance, NoneTyp, Type, TypeOfAny, TypeType, UnionType,
)
from mypy_django_plugin import helpers, monkeypatch from mypy_django_plugin import helpers, monkeypatch
from mypy_django_plugin.config import Config from mypy_django_plugin.config import Config
from mypy_django_plugin.transformers import fields, init_create from mypy_django_plugin.transformers import fields, init_create
from mypy_django_plugin.transformers.forms import make_meta_nested_class_inherit_from_any from mypy_django_plugin.transformers.forms import (
from mypy_django_plugin.transformers.migrations import determine_model_cls_from_string_for_migrations, \ make_meta_nested_class_inherit_from_any,
get_string_value_from_expr )
from mypy_django_plugin.transformers.migrations import (
determine_model_cls_from_string_for_migrations, get_string_value_from_expr,
)
from mypy_django_plugin.transformers.models import process_model_class from mypy_django_plugin.transformers.models import process_model_class
from mypy_django_plugin.transformers.settings import AddSettingValuesToDjangoConfObject, get_settings_metadata from mypy_django_plugin.transformers.settings import (
AddSettingValuesToDjangoConfObject, get_settings_metadata,
)
def transform_model_class(ctx: ClassDefContext) -> None: def transform_model_class(ctx: ClassDefContext) -> None:

View File

@@ -1,4 +0,0 @@
from .dependencies import (add_modules_as_a_source_seed_files,
inject_modules_as_dependencies_for_django_conf_settings,
restore_original_load_graph,
restore_original_dependencies_handling)

View File

@@ -3,9 +3,11 @@ from typing import Optional, cast
from mypy.checker import TypeChecker from mypy.checker import TypeChecker
from mypy.nodes import ListExpr, NameExpr, StrExpr, TupleExpr, TypeInfo, Var from mypy.nodes import ListExpr, NameExpr, StrExpr, TupleExpr, TypeInfo, Var
from mypy.plugin import FunctionContext from mypy.plugin import FunctionContext
from mypy.types import AnyType, CallableType, Instance, TupleType, Type, TypeOfAny, UnionType from mypy.types import (
AnyType, CallableType, Instance, TupleType, Type, TypeOfAny, UnionType,
)
from mypy_django_plugin import helpers from mypy_django_plugin import helpers
from mypy_django_plugin.transformers.models import iter_over_assignments
def extract_referred_to_type(ctx: FunctionContext) -> Optional[Instance]: def extract_referred_to_type(ctx: FunctionContext) -> Optional[Instance]:
@@ -154,7 +156,7 @@ def record_field_properties_into_outer_model_class(ctx: FunctionContext) -> None
return return
field_name = None field_name = None
for name_expr, stmt in iter_over_assignments(outer_model.defn): for name_expr, stmt in helpers.iter_over_assignments(outer_model.defn):
if stmt == ctx.context and isinstance(name_expr, NameExpr): if stmt == ctx.context and isinstance(name_expr, NameExpr):
field_name = name_expr.name field_name = name_expr.name
break break

View File

@@ -1,4 +1,5 @@
from mypy.plugin import ClassDefContext from mypy.plugin import ClassDefContext
from mypy_django_plugin import helpers from mypy_django_plugin import helpers

View File

@@ -4,8 +4,8 @@ from mypy.checker import TypeChecker
from mypy.nodes import TypeInfo, Var from mypy.nodes import TypeInfo, Var
from mypy.plugin import FunctionContext, MethodContext from mypy.plugin import FunctionContext, MethodContext
from mypy.types import AnyType, Instance, Type, TypeOfAny from mypy.types import AnyType, Instance, Type, TypeOfAny
from mypy_django_plugin import helpers from mypy_django_plugin import helpers
from mypy_django_plugin.helpers import extract_field_setter_type, extract_explicit_set_type_of_model_primary_key, get_fields_metadata
from mypy_django_plugin.transformers.fields import get_private_descriptor_type from mypy_django_plugin.transformers.fields import get_private_descriptor_type
@@ -106,7 +106,7 @@ def redefine_and_typecheck_model_create(ctx: MethodContext) -> Type:
def extract_choices_type(model: TypeInfo, field_name: str) -> Optional[str]: def extract_choices_type(model: TypeInfo, field_name: str) -> Optional[str]:
field_metadata = get_fields_metadata(model).get(field_name, {}) field_metadata = helpers.get_fields_metadata(model).get(field_name, {})
if 'choices' in field_metadata: if 'choices' in field_metadata:
return field_metadata['choices'] return field_metadata['choices']
return None return None
@@ -117,7 +117,7 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo,
api = cast(TypeChecker, ctx.api) api = cast(TypeChecker, ctx.api)
expected_types: Dict[str, Type] = {} expected_types: Dict[str, Type] = {}
primary_key_type = extract_explicit_set_type_of_model_primary_key(model) primary_key_type = helpers.extract_explicit_set_type_of_model_primary_key(model)
if not primary_key_type: if not primary_key_type:
# no explicit primary key, set pk to Any and add id # no explicit primary key, set pk to Any and add id
primary_key_type = AnyType(TypeOfAny.special_form) primary_key_type = AnyType(TypeOfAny.special_form)
@@ -143,7 +143,7 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo,
expected_types[name + '_id'] = AnyType(TypeOfAny.from_unimported_type) expected_types[name + '_id'] = AnyType(TypeOfAny.from_unimported_type)
elif isinstance(typ, Instance): elif isinstance(typ, Instance):
field_type = extract_field_setter_type(typ) field_type = helpers.extract_field_setter_type(typ)
if field_type is None: if field_type is None:
continue continue
@@ -156,8 +156,9 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo,
if is_nullable: if is_nullable:
referred_to_model = helpers.make_required(typ.args[1]) referred_to_model = helpers.make_required(typ.args[1])
if isinstance(referred_to_model, Instance) and referred_to_model.type.has_base(helpers.MODEL_CLASS_FULLNAME): if isinstance(referred_to_model, Instance) and referred_to_model.type.has_base(
pk_type = extract_explicit_set_type_of_model_primary_key(referred_to_model.type) helpers.MODEL_CLASS_FULLNAME):
pk_type = helpers.extract_explicit_set_type_of_model_primary_key(referred_to_model.type)
if not pk_type: if not pk_type:
# extract set type of AutoField # extract set type of AutoField
autofield_info = api.lookup_typeinfo('django.db.models.fields.AutoField') autofield_info = api.lookup_typeinfo('django.db.models.fields.AutoField')
@@ -170,7 +171,7 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo,
expected_types[name + '_id'] = related_primary_key_type expected_types[name + '_id'] = related_primary_key_type
field_metadata = get_fields_metadata(model).get(name, {}) field_metadata = helpers.get_fields_metadata(model).get(name, {})
if field_type: if field_type:
# related fields could be None in __init__ (but should be specified before save()) # related fields could be None in __init__ (but should be specified before save())
if helpers.has_any_of_bases(typ.type, (helpers.FOREIGN_KEY_FULLNAME, if helpers.has_any_of_bases(typ.type, (helpers.FOREIGN_KEY_FULLNAME,
@@ -178,7 +179,8 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo,
field_type = helpers.make_optional(field_type) field_type = helpers.make_optional(field_type)
# if primary_key=True and default specified # if primary_key=True and default specified
elif field_metadata.get('primary_key', False) and field_metadata.get('default_specified', False): elif field_metadata.get('primary_key', False) and field_metadata.get('default_specified',
False):
field_type = helpers.make_optional(field_type) field_type = helpers.make_optional(field_type)
expected_types[name] = field_type expected_types[name] = field_type

View File

@@ -4,6 +4,7 @@ from mypy.checker import TypeChecker
from mypy.nodes import Expression, StrExpr, TypeInfo from mypy.nodes import Expression, StrExpr, TypeInfo
from mypy.plugin import MethodContext from mypy.plugin import MethodContext
from mypy.types import Instance, Type, TypeType from mypy.types import Instance, Type, TypeType
from mypy_django_plugin import helpers from mypy_django_plugin import helpers

View File

@@ -2,14 +2,16 @@ from abc import ABCMeta, abstractmethod
from typing import Dict, Iterator, List, Optional, Tuple, cast from typing import Dict, Iterator, List, Optional, Tuple, cast
import dataclasses import dataclasses
from mypy.nodes import ARG_STAR, ARG_STAR2, Argument, CallExpr, ClassDef, Expression, IndexExpr, \ from mypy.nodes import (
Lvalue, MDEF, MemberExpr, MypyFile, NameExpr, StrExpr, SymbolTableNode, TypeInfo, Var ARG_STAR, ARG_STAR2, MDEF, Argument, CallExpr, ClassDef, Expression, IndexExpr, Lvalue, MemberExpr, MypyFile,
NameExpr, StrExpr, SymbolTableNode, TypeInfo, Var,
)
from mypy.plugin import ClassDefContext from mypy.plugin import ClassDefContext
from mypy.plugins.common import add_method from mypy.plugins.common import add_method
from mypy.semanal import SemanticAnalyzerPass2 from mypy.semanal import SemanticAnalyzerPass2
from mypy.types import AnyType, Instance, NoneTyp, TypeOfAny from mypy.types import AnyType, Instance, NoneTyp, TypeOfAny
from mypy_django_plugin import helpers from mypy_django_plugin import helpers
from mypy_django_plugin.helpers import iter_over_assignments
@dataclasses.dataclass @dataclasses.dataclass
@@ -48,7 +50,7 @@ class ModelClassInitializer(metaclass=ABCMeta):
def iter_call_assignments(klass: ClassDef) -> Iterator[Tuple[Lvalue, CallExpr]]: def iter_call_assignments(klass: ClassDef) -> Iterator[Tuple[Lvalue, CallExpr]]:
for lvalue, rvalue in iter_over_assignments(klass): for lvalue, rvalue in helpers.iter_over_assignments(klass):
if isinstance(rvalue, CallExpr): if isinstance(rvalue, CallExpr):
yield lvalue, rvalue yield lvalue, rvalue
@@ -56,7 +58,7 @@ def iter_call_assignments(klass: ClassDef) -> Iterator[Tuple[Lvalue, CallExpr]]:
def iter_over_one_to_n_related_fields(klass: ClassDef) -> Iterator[Tuple[NameExpr, CallExpr]]: def iter_over_one_to_n_related_fields(klass: ClassDef) -> Iterator[Tuple[NameExpr, CallExpr]]:
for lvalue, rvalue in iter_call_assignments(klass): for lvalue, rvalue in iter_call_assignments(klass):
if (isinstance(lvalue, NameExpr) if (isinstance(lvalue, NameExpr)
and isinstance(rvalue.callee, MemberExpr)): and isinstance(rvalue.callee, MemberExpr)):
if rvalue.callee.fullname in {helpers.FOREIGN_KEY_FULLNAME, if rvalue.callee.fullname in {helpers.FOREIGN_KEY_FULLNAME,
helpers.ONETOONE_FIELD_FULLNAME}: helpers.ONETOONE_FIELD_FULLNAME}:
yield lvalue, rvalue yield lvalue, rvalue
@@ -107,8 +109,8 @@ class AddDefaultObjectsManager(ModelClassInitializer):
if isinstance(callee_expr, IndexExpr): if isinstance(callee_expr, IndexExpr):
callee_expr = callee_expr.analyzed.expr callee_expr = callee_expr.analyzed.expr
if isinstance(callee_expr, (MemberExpr, NameExpr)) \ if isinstance(callee_expr, (MemberExpr, NameExpr)) \
and isinstance(callee_expr.node, TypeInfo) \ and isinstance(callee_expr.node, TypeInfo) \
and callee_expr.node.has_base(helpers.BASE_MANAGER_CLASS_FULLNAME): and callee_expr.node.has_base(helpers.BASE_MANAGER_CLASS_FULLNAME):
managers.append((manager_name, callee_expr.node)) managers.append((manager_name, callee_expr.node))
return managers return managers
@@ -147,7 +149,7 @@ class AddIdAttributeIfPrimaryKeyTrueIsNotSet(ModelClassInitializer):
for _, rvalue in iter_call_assignments(self.model_classdef): for _, rvalue in iter_call_assignments(self.model_classdef):
if ('primary_key' in rvalue.arg_names if ('primary_key' in rvalue.arg_names
and self.api.parse_bool(rvalue.args[rvalue.arg_names.index('primary_key')])): and self.api.parse_bool(rvalue.args[rvalue.arg_names.index('primary_key')])):
break break
else: else:
self.add_new_node_to_model_class('id', self.api.builtin_type('builtins.object')) self.add_new_node_to_model_class('id', self.api.builtin_type('builtins.object'))
@@ -202,10 +204,10 @@ def is_related_field(expr: CallExpr, module_file: MypyFile) -> bool:
if isinstance(expr.callee, MemberExpr) and isinstance(expr.callee.expr, NameExpr): if isinstance(expr.callee, MemberExpr) and isinstance(expr.callee.expr, NameExpr):
module = module_file.names.get(expr.callee.expr.name) module = module_file.names.get(expr.callee.expr.name)
if module \ if module \
and module.fullname == 'django.db.models' \ and module.fullname == 'django.db.models' \
and expr.callee.name in {'ForeignKey', and expr.callee.name in {'ForeignKey',
'OneToOneField', 'OneToOneField',
'ManyToManyField'}: 'ManyToManyField'}:
return True return True
return False return False

View File

@@ -1,6 +1,8 @@
from typing import Iterable, List, Optional, cast from typing import Iterable, List, Optional, cast
from mypy.nodes import ClassDef, Context, ImportAll, MypyFile, SymbolNode, SymbolTableNode, TypeInfo, Var from mypy.nodes import (
ClassDef, Context, ImportAll, MypyFile, SymbolNode, SymbolTableNode, TypeInfo, Var,
)
from mypy.plugin import ClassDefContext from mypy.plugin import ClassDefContext
from mypy.semanal import SemanticAnalyzerPass2 from mypy.semanal import SemanticAnalyzerPass2
from mypy.types import AnyType, Instance, NoneTyp, Type, TypeOfAny, UnionType from mypy.types import AnyType, Instance, NoneTyp, Type, TypeOfAny, UnionType
@@ -56,7 +58,7 @@ def load_settings_from_names(settings_classdef: ClassDef,
settings_classdef.info.names[name] = copied settings_classdef.info.names[name] = copied
else: else:
var = Var(name, AnyType(TypeOfAny.unannotated)) var = Var(name, AnyType(TypeOfAny.unannotated))
var.info = api.named_type('__builtins__.object').type var.info = api.named_type('__builtins__.object').type # outer class type
settings_classdef.info.names[name] = SymbolTableNode(sym.kind, var) settings_classdef.info.names[name] = SymbolTableNode(sym.kind, var)
settings_metadata[name] = module.fullname() settings_metadata[name] = module.fullname()
@@ -67,11 +69,12 @@ def get_import_star_modules(api: SemanticAnalyzerPass2, module: MypyFile) -> Lis
for module_import in module.imports: for module_import in module.imports:
# relative import * are not resolved by mypy # relative import * are not resolved by mypy
if isinstance(module_import, ImportAll) and module_import.relative: if isinstance(module_import, ImportAll) and module_import.relative:
absolute_import_path, correct = correct_relative_import(module.fullname(), module_import.relative, module_import.id, absolute_import_path, correct = correct_relative_import(module.fullname(), module_import.relative,
is_cur_package_init_file=False) module_import.id, is_cur_package_init_file=False)
if not correct: if not correct:
return [] return []
for path in [absolute_import_path] + get_import_star_modules(api, module=api.modules.get(absolute_import_path)): for path in [absolute_import_path] + get_import_star_modules(api,
module=api.modules.get(absolute_import_path)):
if path not in import_star_modules: if path not in import_star_modules:
import_star_modules.append(path) import_star_modules.append(path)
return import_star_modules return import_star_modules

View File

@@ -1,5 +1,4 @@
[pytest] [pytest]
testpaths = ./test-data testpaths = ./test-data
addopts = addopts =
--tb=native --tb=native

View File

@@ -37,7 +37,8 @@ IGNORED_ERRORS = {
# settings # settings
re.compile(r'Module has no attribute "[A-Z_]+"'), re.compile(r'Module has no attribute "[A-Z_]+"'),
# attributes assigned to test functions # attributes assigned to test functions
re.compile(r'"Callable\[(\[(Any(, )?)*((, )?VarArg\(Any\))?((, )?KwArg\(Any\))?\]|\.\.\.), Any\]" has no attribute'), re.compile(
r'"Callable\[(\[(Any(, )?)*((, )?VarArg\(Any\))?((, )?KwArg\(Any\))?\]|\.\.\.), Any\]" has no attribute'),
# assign empty tuple # assign empty tuple
re.compile(r'Incompatible types in assignment \(expression has type "Tuple\[\]", ' re.compile(r'Incompatible types in assignment \(expression has type "Tuple\[\]", '
r'variable has type "Tuple\[[A-Za-z, ]+\]"'), r'variable has type "Tuple\[[A-Za-z, ]+\]"'),
@@ -54,8 +55,9 @@ IGNORED_ERRORS = {
'ValuesIterable', 'ValuesIterable',
'Value of type "Optional[Dict[str, Any]]" is not indexable', 'Value of type "Optional[Dict[str, Any]]" is not indexable',
'Argument 1 to "len" has incompatible type "Optional[List[_Record]]"; expected "Sized"', 'Argument 1 to "len" has incompatible type "Optional[List[_Record]]"; expected "Sized"',
'Argument 1 to "loads" has incompatible type "Union[bytes, str, None]"; expected "Union[str, bytes, bytearray]"', 'Argument 1 to "loads" has incompatible type "Union[bytes, str, None]"; '
'Incompatible types in assignment (expression has type "None", variable has type Module)' + 'expected "Union[str, bytes, bytearray]"',
'Incompatible types in assignment (expression has type "None", variable has type Module)',
], ],
'admin_changelist': [ 'admin_changelist': [
'Incompatible types in assignment (expression has type "FilteredChildAdmin", variable has type "ChildAdmin")' 'Incompatible types in assignment (expression has type "FilteredChildAdmin", variable has type "ChildAdmin")'
@@ -65,8 +67,9 @@ IGNORED_ERRORS = {
], ],
'admin_widgets': [ 'admin_widgets': [
'Incompatible types in assignment (expression has type "RelatedFieldWidgetWrapper", ' 'Incompatible types in assignment (expression has type "RelatedFieldWidgetWrapper", '
'variable has type "AdminRadioSelect")', + 'variable has type "AdminRadioSelect")',
'Incompatible types in assignment (expression has type "Union[Widget, Any]", variable has type "AutocompleteSelect")' 'Incompatible types in assignment (expression has type "Union[Widget, Any]", '
+ 'variable has type "AutocompleteSelect")'
], ],
'admin_utils': [ 'admin_utils': [
re.compile(r'Argument [0-9] to "lookup_field" has incompatible type'), re.compile(r'Argument [0-9] to "lookup_field" has incompatible type'),
@@ -91,11 +94,13 @@ IGNORED_ERRORS = {
'Incompatible types in assignment (expression has type "FlatValuesListIterable", ' 'Incompatible types in assignment (expression has type "FlatValuesListIterable", '
+ 'variable has type "ValuesListIterable")', + 'variable has type "ValuesListIterable")',
'Incompatible type for "contact" of "Book" (got "Optional[Author]", expected "Union[Author, Combinable]")', 'Incompatible type for "contact" of "Book" (got "Optional[Author]", expected "Union[Author, Combinable]")',
'Incompatible type for "publisher" of "Book" (got "Optional[Publisher]", expected "Union[Publisher, Combinable]")' 'Incompatible type for "publisher" of "Book" (got "Optional[Publisher]", '
+ 'expected "Union[Publisher, Combinable]")'
], ],
'aggregation_regress': [ 'aggregation_regress': [
'Incompatible types in assignment (expression has type "List[str]", variable has type "QuerySet[Author]")', 'Incompatible types in assignment (expression has type "List[str]", variable has type "QuerySet[Author]")',
'Incompatible types in assignment (expression has type "FlatValuesListIterable", variable has type "QuerySet[Any]")', 'Incompatible types in assignment (expression has type "FlatValuesListIterable", '
+ 'variable has type "QuerySet[Any]")',
'Too few arguments for "count" of "Sequence"' 'Too few arguments for "count" of "Sequence"'
], ],
'apps': [ 'apps': [
@@ -176,8 +181,8 @@ IGNORED_ERRORS = {
'variable has type "SongForm"', 'variable has type "SongForm"',
'"full_clean" of "BaseForm" does not return a value', '"full_clean" of "BaseForm" does not return a value',
'No overload variant of "zip" matches argument types "Tuple[str, str, str]", "object"', 'No overload variant of "zip" matches argument types "Tuple[str, str, str]", "object"',
'note:', 'Incompatible types in assignment (expression has type "GetDateShowHiddenInitial", '
'Incompatible types in assignment (expression has type "GetDateShowHiddenInitial", variable has type "GetDate")', + 'variable has type "GetDate")',
re.compile(r'Incompatible types in assignment \(expression has type "[a-zA-Z]+Field", ' re.compile(r'Incompatible types in assignment \(expression has type "[a-zA-Z]+Field", '
r'base class "BaseForm" defined the type as "Dict\[str, Any\]"\)'), r'base class "BaseForm" defined the type as "Dict\[str, Any\]"\)'),
'List or tuple expected as variable arguments', 'List or tuple expected as variable arguments',
@@ -216,13 +221,13 @@ IGNORED_ERRORS = {
], ],
'lookup': [ 'lookup': [
'Unexpected keyword argument "headline__startswith" for "in_bulk" of "QuerySet"', 'Unexpected keyword argument "headline__startswith" for "in_bulk" of "QuerySet"',
'note: '
], ],
'many_to_one': [ 'many_to_one': [
'Incompatible type for "parent" of "Child" (got "None", expected "Union[Parent, Combinable]")' 'Incompatible type for "parent" of "Child" (got "None", expected "Union[Parent, Combinable]")'
], ],
'model_inheritance_regress': [ 'model_inheritance_regress': [
'Incompatible types in assignment (expression has type "List[Supplier]", variable has type "QuerySet[Supplier]")' 'Incompatible types in assignment (expression has type "List[Supplier]", '
+ 'variable has type "QuerySet[Supplier]")'
], ],
'model_meta': [ 'model_meta': [
'"object" has no attribute "items"', '"object" has no attribute "items"',
@@ -238,10 +243,10 @@ IGNORED_ERRORS = {
'Cannot assign multiple types to name "PersonTwoImages" without an explicit "Type[...]" annotation', 'Cannot assign multiple types to name "PersonTwoImages" without an explicit "Type[...]" annotation',
'Incompatible types in assignment (expression has type "Type[Person]", ' 'Incompatible types in assignment (expression has type "Type[Person]", '
+ 'base class "ImageFieldTestMixin" defined the type as "Type[PersonWithHeightAndWidth]")', + 'base class "ImageFieldTestMixin" defined the type as "Type[PersonWithHeightAndWidth]")',
'note: "Person" defined here'
], ],
'model_formsets': [ 'model_formsets': [
'Incompatible types in string interpolation (expression has type "object", placeholder has type "Union[int, float]")' 'Incompatible types in string interpolation (expression has type "object", '
+ 'placeholder has type "Union[int, float]")'
], ],
'model_formsets_regress': [ 'model_formsets_regress': [
'Incompatible types in assignment (expression has type "Model", variable has type "User")' 'Incompatible types in assignment (expression has type "Model", variable has type "User")'
@@ -287,9 +292,11 @@ IGNORED_ERRORS = {
'Incompatible types in assignment (expression has type "Type[Field[Any, Any]]', 'Incompatible types in assignment (expression has type "Type[Field[Any, Any]]',
'DummyArrayField', 'DummyArrayField',
'DummyJSONField', 'DummyJSONField',
'Argument "encoder" to "JSONField" has incompatible type "DjangoJSONEncoder"; expected "Optional[Type[JSONEncoder]]"', 'Argument "encoder" to "JSONField" has incompatible type "DjangoJSONEncoder"; '
+ 'expected "Optional[Type[JSONEncoder]]"',
'for model "CITestModel"', 'for model "CITestModel"',
'Incompatible type for "field" of "IntegerArrayModel" (got "None", expected "Union[Sequence[int], Combinable]")' 'Incompatible type for "field" of "IntegerArrayModel" (got "None", '
+ 'expected "Union[Sequence[int], Combinable]")'
], ],
'properties': [ 'properties': [
re.compile('Unexpected attribute "(full_name|full_name_2)" for model "Person"') re.compile('Unexpected attribute "(full_name|full_name_2)" for model "Person"')
@@ -334,11 +341,14 @@ IGNORED_ERRORS = {
'Incompatible types in assignment (expression has type "Thread", variable has type "Callable[[], Any]")' 'Incompatible types in assignment (expression has type "Thread", variable has type "Callable[[], Any]")'
], ],
'test_client': [ 'test_client': [
'Incompatible types in assignment (expression has type "StreamingHttpResponse", variable has type "HttpResponse")', 'Incompatible types in assignment (expression has type "StreamingHttpResponse", '
'Incompatible types in assignment (expression has type "HttpResponse", variable has type "StreamingHttpResponse")' + 'variable has type "HttpResponse")',
'Incompatible types in assignment (expression has type "HttpResponse", '
+ 'variable has type "StreamingHttpResponse")'
], ],
'test_client_regress': [ 'test_client_regress': [
'Incompatible types in assignment (expression has type "Dict[<nothing>, <nothing>]", variable has type "SessionBase")', 'Incompatible types in assignment (expression has type "Dict[<nothing>, <nothing>]", '
+ 'variable has type "SessionBase")',
'Unsupported left operand type for + ("None")', 'Unsupported left operand type for + ("None")',
'Both left and right operands are unions' 'Both left and right operands are unions'
], ],
@@ -348,7 +358,8 @@ IGNORED_ERRORS = {
'test_runner': [ 'test_runner': [
'Value of type "TestSuite" is not indexable', 'Value of type "TestSuite" is not indexable',
'"TestSuite" has no attribute "_tests"', '"TestSuite" has no attribute "_tests"',
'Argument "result" to "run" of "TestCase" has incompatible type "RemoteTestResult"; expected "Optional[TestResult]"', 'Argument "result" to "run" of "TestCase" has incompatible type "RemoteTestResult"; '
+ 'expected "Optional[TestResult]"',
'Item "TestSuite" of "Union[TestCase, TestSuite]" has no attribute "id"', 'Item "TestSuite" of "Union[TestCase, TestSuite]" has no attribute "id"',
'MockTestRunner', 'MockTestRunner',
'Incompatible types in assignment (expression has type "Tuple[Union[TestCase, TestSuite], ...]", ' 'Incompatible types in assignment (expression has type "Tuple[Union[TestCase, TestSuite], ...]", '

29
setup.cfg Normal file
View File

@@ -0,0 +1,29 @@
[isort]
skip =
django-sources,
django-stubs,
test-data
include_trailing_comma = true
multi_line_output = 5
wrap_length = 120
[flake8]
exclude =
django-sources,
django-stubs,
test-data
max_line_length = 120
[tool:pytest]
testpaths = ./test-data
addopts =
--tb=native
--mypy-ini-file=./test-data/plugins.ini
-s
-v
[bdist_wheel]
universal = 1
[metadata]
license_file = LICENSE.txt