From c962b8ac68856e5ff39748444c20d8fb99ab9f0b Mon Sep 17 00:00:00 2001 From: Maxim Kurnikov Date: Fri, 1 Mar 2019 02:07:53 +0300 Subject: [PATCH] attempt to add flake8 and isort --- .travis.yml | 16 ++++-- dev-requirements.txt | 2 + mypy_django_plugin/config.py | 14 +++--- mypy_django_plugin/helpers.py | 9 ++-- mypy_django_plugin/main.py | 23 ++++++--- .../dependencies.py => monkeypatch.py} | 0 mypy_django_plugin/monkeypatch/__init__.py | 4 -- mypy_django_plugin/transformers/fields.py | 8 +-- mypy_django_plugin/transformers/forms.py | 1 + .../transformers/init_create.py | 18 ++++--- mypy_django_plugin/transformers/migrations.py | 1 + mypy_django_plugin/transformers/models.py | 26 +++++----- mypy_django_plugin/transformers/settings.py | 13 +++-- pytest.ini | 1 - scripts/typecheck_tests.py | 49 ++++++++++++------- setup.cfg | 29 +++++++++++ 16 files changed, 142 insertions(+), 72 deletions(-) rename mypy_django_plugin/{monkeypatch/dependencies.py => monkeypatch.py} (100%) delete mode 100644 mypy_django_plugin/monkeypatch/__init__.py create mode 100644 setup.cfg diff --git a/.travis.yml b/.travis.yml index 16caef5..4ea2261 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,6 @@ dist: xenial sudo: required jobs: include: - - name: Typecheck Django test suite - python: 3.7 - script: 'python ./scripts/typecheck_tests.py' - - name: Run plugin test suite with python 3.7 python: 3.7 script: | @@ -20,10 +16,22 @@ jobs: set -e pytest + - name: Typecheck Django test suite + python: 3.7 + script: 'python ./scripts/typecheck_tests.py' + - name: Lint with black python: 3.7 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: | # Upgrade pip, setuptools, and wheel pip install -U pip setuptools wheel diff --git a/dev-requirements.txt b/dev-requirements.txt index e94d86e..24d30a5 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,3 +1,5 @@ black pytest-mypy-plugins +flake8 +isort==4.3.4 -e . diff --git a/mypy_django_plugin/config.py b/mypy_django_plugin/config.py index c43b22c..3845b2d 100644 --- a/mypy_django_plugin/config.py +++ b/mypy_django_plugin/config.py @@ -1,5 +1,5 @@ from configparser import ConfigParser -from typing import List, Optional +from typing import Optional from dataclasses import dataclass @@ -16,10 +16,12 @@ class Config: if not ini_config.has_section('mypy_django_plugin'): raise ValueError('Invalid config file: no [mypy_django_plugin] section') - django_settings = ini_config.get('mypy_django_plugin', 'django_settings', - fallback=None) - if django_settings: + django_settings = ini_config.get('mypy_django_plugin', 'django_settings') + if type(django_settings) == object: + django_settings = None + else: django_settings = django_settings.strip() + return Config(django_settings_module=django_settings, - ignore_missing_settings=ini_config.get('mypy_django_plugin', 'ignore_missing_settings', - fallback=False)) + ignore_missing_settings=bool(ini_config.get('mypy_django_plugin', 'ignore_missing_settings', + fallback=False))) diff --git a/mypy_django_plugin/helpers.py b/mypy_django_plugin/helpers.py index 97acc39..ee3a98b 100644 --- a/mypy_django_plugin/helpers.py +++ b/mypy_django_plugin/helpers.py @@ -2,10 +2,13 @@ import typing from typing import Dict, Optional from mypy.checker import TypeChecker -from mypy.nodes import AssignmentStmt, ClassDef, Expression, ImportedName, Lvalue, MypyFile, NameExpr, SymbolNode, \ - TypeInfo +from mypy.nodes import ( + AssignmentStmt, ClassDef, Expression, ImportedName, Lvalue, MypyFile, NameExpr, SymbolNode, TypeInfo, +) 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' FIELD_FULLNAME = 'django.db.models.fields.Field' diff --git a/mypy_django_plugin/main.py b/mypy_django_plugin/main.py index 78eeb31..dfe02cf 100644 --- a/mypy_django_plugin/main.py +++ b/mypy_django_plugin/main.py @@ -2,19 +2,28 @@ import os from typing import Callable, Dict, Optional, Union, cast 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.plugin import AttributeContext, ClassDefContext, FunctionContext, MethodContext, Plugin -from mypy.types import AnyType, Instance, Type, TypeOfAny, TypeType, UnionType, CallableType, NoneTyp +from mypy.plugin import ( + 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.config import Config 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.migrations import determine_model_cls_from_string_for_migrations, \ - get_string_value_from_expr +from mypy_django_plugin.transformers.forms import ( + make_meta_nested_class_inherit_from_any, +) +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.settings import AddSettingValuesToDjangoConfObject, get_settings_metadata +from mypy_django_plugin.transformers.settings import ( + AddSettingValuesToDjangoConfObject, get_settings_metadata, +) def transform_model_class(ctx: ClassDefContext) -> None: diff --git a/mypy_django_plugin/monkeypatch/dependencies.py b/mypy_django_plugin/monkeypatch.py similarity index 100% rename from mypy_django_plugin/monkeypatch/dependencies.py rename to mypy_django_plugin/monkeypatch.py diff --git a/mypy_django_plugin/monkeypatch/__init__.py b/mypy_django_plugin/monkeypatch/__init__.py deleted file mode 100644 index 7404c26..0000000 --- a/mypy_django_plugin/monkeypatch/__init__.py +++ /dev/null @@ -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) diff --git a/mypy_django_plugin/transformers/fields.py b/mypy_django_plugin/transformers/fields.py index 66eebcc..11a616b 100644 --- a/mypy_django_plugin/transformers/fields.py +++ b/mypy_django_plugin/transformers/fields.py @@ -3,9 +3,11 @@ from typing import Optional, cast from mypy.checker import TypeChecker from mypy.nodes import ListExpr, NameExpr, StrExpr, TupleExpr, TypeInfo, Var 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.transformers.models import iter_over_assignments 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 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): field_name = name_expr.name break diff --git a/mypy_django_plugin/transformers/forms.py b/mypy_django_plugin/transformers/forms.py index 535c0e8..d12ba42 100644 --- a/mypy_django_plugin/transformers/forms.py +++ b/mypy_django_plugin/transformers/forms.py @@ -1,4 +1,5 @@ from mypy.plugin import ClassDefContext + from mypy_django_plugin import helpers diff --git a/mypy_django_plugin/transformers/init_create.py b/mypy_django_plugin/transformers/init_create.py index dde5160..77b7b7f 100644 --- a/mypy_django_plugin/transformers/init_create.py +++ b/mypy_django_plugin/transformers/init_create.py @@ -4,8 +4,8 @@ from mypy.checker import TypeChecker from mypy.nodes import TypeInfo, Var from mypy.plugin import FunctionContext, MethodContext from mypy.types import AnyType, Instance, Type, TypeOfAny + 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 @@ -106,7 +106,7 @@ def redefine_and_typecheck_model_create(ctx: MethodContext) -> Type: 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: return field_metadata['choices'] return None @@ -117,7 +117,7 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo, api = cast(TypeChecker, ctx.api) 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: # no explicit primary key, set pk to Any and add id 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) elif isinstance(typ, Instance): - field_type = extract_field_setter_type(typ) + field_type = helpers.extract_field_setter_type(typ) if field_type is None: continue @@ -156,8 +156,9 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo, if is_nullable: 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): - pk_type = extract_explicit_set_type_of_model_primary_key(referred_to_model.type) + if isinstance(referred_to_model, Instance) and referred_to_model.type.has_base( + helpers.MODEL_CLASS_FULLNAME): + pk_type = helpers.extract_explicit_set_type_of_model_primary_key(referred_to_model.type) if not pk_type: # extract set type of 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 - field_metadata = get_fields_metadata(model).get(name, {}) + field_metadata = helpers.get_fields_metadata(model).get(name, {}) if field_type: # 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, @@ -178,7 +179,8 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo, field_type = helpers.make_optional(field_type) # 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) expected_types[name] = field_type diff --git a/mypy_django_plugin/transformers/migrations.py b/mypy_django_plugin/transformers/migrations.py index 7371f67..b6baad8 100644 --- a/mypy_django_plugin/transformers/migrations.py +++ b/mypy_django_plugin/transformers/migrations.py @@ -4,6 +4,7 @@ from mypy.checker import TypeChecker from mypy.nodes import Expression, StrExpr, TypeInfo from mypy.plugin import MethodContext from mypy.types import Instance, Type, TypeType + from mypy_django_plugin import helpers diff --git a/mypy_django_plugin/transformers/models.py b/mypy_django_plugin/transformers/models.py index 83da0c5..32c5e3f 100644 --- a/mypy_django_plugin/transformers/models.py +++ b/mypy_django_plugin/transformers/models.py @@ -2,14 +2,16 @@ from abc import ABCMeta, abstractmethod from typing import Dict, Iterator, List, Optional, Tuple, cast import dataclasses -from mypy.nodes import ARG_STAR, ARG_STAR2, Argument, CallExpr, ClassDef, Expression, IndexExpr, \ - Lvalue, MDEF, MemberExpr, MypyFile, NameExpr, StrExpr, SymbolTableNode, TypeInfo, Var +from mypy.nodes import ( + 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.plugins.common import add_method from mypy.semanal import SemanticAnalyzerPass2 from mypy.types import AnyType, Instance, NoneTyp, TypeOfAny + from mypy_django_plugin import helpers -from mypy_django_plugin.helpers import iter_over_assignments @dataclasses.dataclass @@ -48,7 +50,7 @@ class ModelClassInitializer(metaclass=ABCMeta): 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): 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]]: for lvalue, rvalue in iter_call_assignments(klass): if (isinstance(lvalue, NameExpr) - and isinstance(rvalue.callee, MemberExpr)): + and isinstance(rvalue.callee, MemberExpr)): if rvalue.callee.fullname in {helpers.FOREIGN_KEY_FULLNAME, helpers.ONETOONE_FIELD_FULLNAME}: yield lvalue, rvalue @@ -107,8 +109,8 @@ class AddDefaultObjectsManager(ModelClassInitializer): if isinstance(callee_expr, IndexExpr): callee_expr = callee_expr.analyzed.expr if isinstance(callee_expr, (MemberExpr, NameExpr)) \ - and isinstance(callee_expr.node, TypeInfo) \ - and callee_expr.node.has_base(helpers.BASE_MANAGER_CLASS_FULLNAME): + and isinstance(callee_expr.node, TypeInfo) \ + and callee_expr.node.has_base(helpers.BASE_MANAGER_CLASS_FULLNAME): managers.append((manager_name, callee_expr.node)) return managers @@ -147,7 +149,7 @@ class AddIdAttributeIfPrimaryKeyTrueIsNotSet(ModelClassInitializer): for _, rvalue in iter_call_assignments(self.model_classdef): 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 else: 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): module = module_file.names.get(expr.callee.expr.name) if module \ - and module.fullname == 'django.db.models' \ - and expr.callee.name in {'ForeignKey', - 'OneToOneField', - 'ManyToManyField'}: + and module.fullname == 'django.db.models' \ + and expr.callee.name in {'ForeignKey', + 'OneToOneField', + 'ManyToManyField'}: return True return False diff --git a/mypy_django_plugin/transformers/settings.py b/mypy_django_plugin/transformers/settings.py index 472fb60..cef5893 100644 --- a/mypy_django_plugin/transformers/settings.py +++ b/mypy_django_plugin/transformers/settings.py @@ -1,6 +1,8 @@ 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.semanal import SemanticAnalyzerPass2 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 else: 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_metadata[name] = module.fullname() @@ -67,11 +69,12 @@ def get_import_star_modules(api: SemanticAnalyzerPass2, module: MypyFile) -> Lis for module_import in module.imports: # relative import * are not resolved by mypy if isinstance(module_import, ImportAll) and module_import.relative: - absolute_import_path, correct = correct_relative_import(module.fullname(), module_import.relative, module_import.id, - is_cur_package_init_file=False) + absolute_import_path, correct = correct_relative_import(module.fullname(), module_import.relative, + module_import.id, is_cur_package_init_file=False) if not correct: 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: import_star_modules.append(path) return import_star_modules diff --git a/pytest.ini b/pytest.ini index 33b1310..af5af9b 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,5 +1,4 @@ [pytest] - testpaths = ./test-data addopts = --tb=native diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py index 9d06044..244f641 100644 --- a/scripts/typecheck_tests.py +++ b/scripts/typecheck_tests.py @@ -37,7 +37,8 @@ IGNORED_ERRORS = { # settings re.compile(r'Module has no attribute "[A-Z_]+"'), # 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 re.compile(r'Incompatible types in assignment \(expression has type "Tuple\[\]", ' r'variable has type "Tuple\[[A-Za-z, ]+\]"'), @@ -54,8 +55,9 @@ IGNORED_ERRORS = { 'ValuesIterable', '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 "loads" has incompatible type "Union[bytes, str, None]"; expected "Union[str, bytes, bytearray]"', - 'Incompatible types in assignment (expression has type "None", variable has type Module)' + 'Argument 1 to "loads" has incompatible type "Union[bytes, str, None]"; ' + + 'expected "Union[str, bytes, bytearray]"', + 'Incompatible types in assignment (expression has type "None", variable has type Module)', ], 'admin_changelist': [ 'Incompatible types in assignment (expression has type "FilteredChildAdmin", variable has type "ChildAdmin")' @@ -65,8 +67,9 @@ IGNORED_ERRORS = { ], 'admin_widgets': [ 'Incompatible types in assignment (expression has type "RelatedFieldWidgetWrapper", ' - 'variable has type "AdminRadioSelect")', - 'Incompatible types in assignment (expression has type "Union[Widget, Any]", variable has type "AutocompleteSelect")' + + 'variable has type "AdminRadioSelect")', + 'Incompatible types in assignment (expression has type "Union[Widget, Any]", ' + + 'variable has type "AutocompleteSelect")' ], 'admin_utils': [ 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", ' + 'variable has type "ValuesListIterable")', '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': [ '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"' ], 'apps': [ @@ -176,8 +181,8 @@ IGNORED_ERRORS = { 'variable has type "SongForm"', '"full_clean" of "BaseForm" does not return a value', 'No overload variant of "zip" matches argument types "Tuple[str, str, str]", "object"', - 'note:', - 'Incompatible types in assignment (expression has type "GetDateShowHiddenInitial", variable has type "GetDate")', + 'Incompatible types in assignment (expression has type "GetDateShowHiddenInitial", ' + + 'variable has type "GetDate")', 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\]"\)'), 'List or tuple expected as variable arguments', @@ -216,13 +221,13 @@ IGNORED_ERRORS = { ], 'lookup': [ 'Unexpected keyword argument "headline__startswith" for "in_bulk" of "QuerySet"', - 'note: ' ], 'many_to_one': [ 'Incompatible type for "parent" of "Child" (got "None", expected "Union[Parent, Combinable]")' ], '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': [ '"object" has no attribute "items"', @@ -238,10 +243,10 @@ IGNORED_ERRORS = { 'Cannot assign multiple types to name "PersonTwoImages" without an explicit "Type[...]" annotation', 'Incompatible types in assignment (expression has type "Type[Person]", ' + 'base class "ImageFieldTestMixin" defined the type as "Type[PersonWithHeightAndWidth]")', - 'note: "Person" defined here' ], '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': [ '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]]', 'DummyArrayField', '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"', - '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': [ 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]")' ], 'test_client': [ - 'Incompatible types in assignment (expression has type "StreamingHttpResponse", variable has type "HttpResponse")', - 'Incompatible types in assignment (expression has type "HttpResponse", variable has type "StreamingHttpResponse")' + 'Incompatible types in assignment (expression has type "StreamingHttpResponse", ' + + 'variable has type "HttpResponse")', + 'Incompatible types in assignment (expression has type "HttpResponse", ' + + 'variable has type "StreamingHttpResponse")' ], 'test_client_regress': [ - 'Incompatible types in assignment (expression has type "Dict[, ]", variable has type "SessionBase")', + 'Incompatible types in assignment (expression has type "Dict[, ]", ' + + 'variable has type "SessionBase")', 'Unsupported left operand type for + ("None")', 'Both left and right operands are unions' ], @@ -348,7 +358,8 @@ IGNORED_ERRORS = { 'test_runner': [ 'Value of type "TestSuite" is not indexable', '"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"', 'MockTestRunner', 'Incompatible types in assignment (expression has type "Tuple[Union[TestCase, TestSuite], ...]", ' diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..fd1f72a --- /dev/null +++ b/setup.cfg @@ -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