remove some asserts that could be validly triggered

This commit is contained in:
Maxim Kurnikov
2019-07-25 19:53:12 +03:00
parent 409c01eb24
commit 62dac1d468
10 changed files with 77 additions and 35 deletions

View File

@@ -1,4 +1 @@
[mypy] [mypy]
[mypy-mypy_django_plugin.monkeypatch.*]
ignore_errors = True

View File

@@ -1,20 +1,21 @@
import os import os
from collections import defaultdict from collections import defaultdict
from contextlib import contextmanager from contextlib import contextmanager
from typing import Dict, Iterator, List, Optional, TYPE_CHECKING, Tuple, Type from typing import TYPE_CHECKING, Dict, Iterator, List, Optional, Tuple, Type
from django.contrib.postgres.fields import ArrayField
from django.core.exceptions import FieldError from django.core.exceptions import FieldError
from django.db.models.base import Model from django.db.models.base import Model
from django.db.models.fields import AutoField, CharField, Field
from django.db.models.fields.related import ForeignKey, RelatedField from django.db.models.fields.related import ForeignKey, RelatedField
from django.db.models.fields.reverse_related import ForeignObjectRel from django.db.models.fields.reverse_related import ForeignObjectRel
from django.db.models.sql.query import Query from django.db.models.sql.query import Query
from django.utils.functional import cached_property from django.utils.functional import cached_property
from mypy.checker import TypeChecker from mypy.checker import TypeChecker
from mypy.nodes import TypeInfo from mypy.types import AnyType, Instance
from mypy.types import AnyType, Instance, Type as MypyType, TypeOfAny from mypy.types import Type as MypyType
from mypy.types import TypeOfAny
from django.contrib.postgres.fields import ArrayField
from django.db.models.fields import AutoField, CharField, Field
from mypy_django_plugin.lib import helpers from mypy_django_plugin.lib import helpers
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -104,7 +105,8 @@ class DjangoFieldsContext:
def get_field_get_type(self, api: TypeChecker, field: Field, *, method: str) -> MypyType: def get_field_get_type(self, api: TypeChecker, field: Field, *, method: str) -> MypyType:
""" Get a type of __get__ for this specific Django field. """ """ Get a type of __get__ for this specific Django field. """
field_info = helpers.lookup_class_typeinfo(api, field.__class__) field_info = helpers.lookup_class_typeinfo(api, field.__class__)
assert isinstance(field_info, TypeInfo) if field_info is None:
return AnyType(TypeOfAny.unannotated)
is_nullable = self.get_field_nullability(field, method) is_nullable = self.get_field_nullability(field, method)
if isinstance(field, RelatedField): if isinstance(field, RelatedField):
@@ -113,7 +115,8 @@ class DjangoFieldsContext:
return self.get_field_get_type(api, primary_key_field, method=method) return self.get_field_get_type(api, primary_key_field, method=method)
model_info = helpers.lookup_class_typeinfo(api, field.related_model) model_info = helpers.lookup_class_typeinfo(api, field.related_model)
assert isinstance(model_info, TypeInfo) if model_info is None:
return AnyType(TypeOfAny.unannotated)
return Instance(model_info, []) return Instance(model_info, [])
else: else:
@@ -215,14 +218,19 @@ class DjangoContext:
if isinstance(field, ForeignKey): if isinstance(field, ForeignKey):
field_name = field.name field_name = field.name
foreign_key_info = helpers.lookup_class_typeinfo(api, field.__class__) foreign_key_info = helpers.lookup_class_typeinfo(api, field.__class__)
assert isinstance(foreign_key_info, TypeInfo) if foreign_key_info is None:
# maybe there's no type annotation for the field
expected_types[field_name] = AnyType(TypeOfAny.unannotated)
continue
related_model = field.related_model related_model = field.related_model
if related_model._meta.proxy_for_model: if related_model._meta.proxy_for_model:
related_model = field.related_model._meta.proxy_for_model related_model = field.related_model._meta.proxy_for_model
related_model_info = helpers.lookup_class_typeinfo(api, related_model) related_model_info = helpers.lookup_class_typeinfo(api, related_model)
assert isinstance(related_model_info, TypeInfo) if related_model_info is None:
expected_types[field_name] = AnyType(TypeOfAny.unannotated)
continue
is_nullable = self.fields_context.get_field_nullability(field, method) is_nullable = self.fields_context.get_field_nullability(field, method)
foreign_key_set_type = helpers.get_private_descriptor_type(foreign_key_info, foreign_key_set_type = helpers.get_private_descriptor_type(foreign_key_info,

View File

@@ -1,13 +1,19 @@
from collections import OrderedDict from collections import OrderedDict
from typing import Any, Dict, List, Optional, Set, TYPE_CHECKING, Union, cast from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Union, cast
from mypy import checker from mypy import checker
from mypy.checker import TypeChecker from mypy.checker import TypeChecker
from mypy.mro import calculate_mro from mypy.mro import calculate_mro
from mypy.nodes import (Block, ClassDef, Expression, GDEF, MDEF, MemberExpr, MypyFile, NameExpr, StrExpr, SymbolNode, from mypy.nodes import (
SymbolTable, SymbolTableNode, TypeInfo, Var) GDEF, MDEF, Block, ClassDef, Expression, MemberExpr, MypyFile, NameExpr, StrExpr, SymbolNode, SymbolTable,
from mypy.plugin import AttributeContext, CheckerPluginInterface, FunctionContext, MethodContext SymbolTableNode, TypeInfo, Var,
from mypy.types import AnyType, Instance, NoneTyp, TupleType, Type as MypyType, TypeOfAny, TypedDictType, UnionType )
from mypy.plugin import (
AttributeContext, CheckerPluginInterface, FunctionContext, MethodContext,
)
from mypy.types import AnyType, Instance, NoneTyp, TupleType
from mypy.types import Type as MypyType
from mypy.types import TypedDictType, TypeOfAny, UnionType
if TYPE_CHECKING: if TYPE_CHECKING:
from mypy_django_plugin.django.context import DjangoContext from mypy_django_plugin.django.context import DjangoContext

View File

@@ -6,7 +6,9 @@ from django.db.models.fields.related import RelatedField
from mypy.errors import Errors from mypy.errors import Errors
from mypy.nodes import MypyFile, TypeInfo from mypy.nodes import MypyFile, TypeInfo
from mypy.options import Options from mypy.options import Options
from mypy.plugin import AnalyzeTypeContext, AttributeContext, ClassDefContext, FunctionContext, MethodContext, Plugin from mypy.plugin import (
AnalyzeTypeContext, AttributeContext, ClassDefContext, FunctionContext, MethodContext, Plugin,
)
from mypy.types import Type as MypyType from mypy.types import Type as MypyType
from mypy_django_plugin.django.context import DjangoContext from mypy_django_plugin.django.context import DjangoContext

View File

@@ -2,7 +2,7 @@ from typing import Optional, Tuple, cast
from django.db.models.fields import Field from django.db.models.fields import Field
from django.db.models.fields.related import RelatedField from django.db.models.fields.related import RelatedField
from mypy.nodes import AssignmentStmt, TypeInfo, NameExpr from mypy.nodes import AssignmentStmt, NameExpr, TypeInfo
from mypy.plugin import FunctionContext from mypy.plugin import FunctionContext
from mypy.types import AnyType, Instance from mypy.types import AnyType, Instance
from mypy.types import Type as MypyType from mypy.types import Type as MypyType
@@ -22,7 +22,8 @@ def _get_current_field_from_assignment(ctx: FunctionContext, django_context: Dja
for stmt in outer_model_info.defn.defs.body: for stmt in outer_model_info.defn.defs.body:
if isinstance(stmt, AssignmentStmt): if isinstance(stmt, AssignmentStmt):
if stmt.rvalue == ctx.context: if stmt.rvalue == ctx.context:
assert isinstance(stmt.lvalues[0], NameExpr) if not isinstance(stmt.lvalues[0], NameExpr):
return None
field_name = stmt.lvalues[0].name field_name = stmt.lvalues[0].name
break break
if field_name is None: if field_name is None:
@@ -50,16 +51,24 @@ def fill_descriptor_types_for_related_field(ctx: FunctionContext, django_context
typechecker_api = helpers.get_typechecker_api(ctx) typechecker_api = helpers.get_typechecker_api(ctx)
related_model_info = helpers.lookup_class_typeinfo(typechecker_api, related_model) related_model_info = helpers.lookup_class_typeinfo(typechecker_api, related_model)
assert isinstance(related_model_info, TypeInfo) if related_model_info is None:
# maybe no type stub
related_model_type = AnyType(TypeOfAny.unannotated)
else:
related_model_type = Instance(related_model_info, []) # type: ignore
related_model_to_set_info = helpers.lookup_class_typeinfo(typechecker_api, related_model_to_set) related_model_to_set_info = helpers.lookup_class_typeinfo(typechecker_api, related_model_to_set)
assert isinstance(related_model_to_set_info, TypeInfo) if related_model_to_set_info is None:
# maybe no type stub
related_model_to_set_type = AnyType(TypeOfAny.unannotated)
else:
related_model_to_set_type = Instance(related_model_to_set_info, []) # type: ignore
default_related_field_type = set_descriptor_types_for_field(ctx) default_related_field_type = set_descriptor_types_for_field(ctx)
# replace Any with referred_to_type # replace Any with referred_to_type
args = [ args = [
helpers.convert_any_to_type(default_related_field_type.args[0], Instance(related_model_to_set_info, [])), helpers.convert_any_to_type(default_related_field_type.args[0], related_model_to_set_type),
helpers.convert_any_to_type(default_related_field_type.args[1], Instance(related_model_info, [])), helpers.convert_any_to_type(default_related_field_type.args[1], related_model_type),
] ]
return helpers.reparametrize_instance(default_related_field_type, new_args=args) return helpers.reparametrize_instance(default_related_field_type, new_args=args)

View File

@@ -2,7 +2,8 @@ from typing import List, Tuple, Type, Union
from django.db.models.base import Model from django.db.models.base import Model
from mypy.plugin import FunctionContext, MethodContext from mypy.plugin import FunctionContext, MethodContext
from mypy.types import Instance, Type as MypyType from mypy.types import Instance
from mypy.types import Type as MypyType
from mypy_django_plugin.django.context import DjangoContext from mypy_django_plugin.django.context import DjangoContext
from mypy_django_plugin.lib import helpers from mypy_django_plugin.lib import helpers

View File

@@ -1,5 +1,4 @@
from django.core.exceptions import FieldDoesNotExist from django.core.exceptions import FieldDoesNotExist
from mypy.nodes import TypeInfo
from mypy.plugin import MethodContext from mypy.plugin import MethodContext
from mypy.types import AnyType, Instance from mypy.types import AnyType, Instance
from mypy.types import Type as MypyType from mypy.types import Type as MypyType
@@ -12,7 +11,8 @@ from mypy_django_plugin.lib import fullnames, helpers
def _get_field_instance(ctx: MethodContext, field_fullname: str) -> MypyType: def _get_field_instance(ctx: MethodContext, field_fullname: str) -> MypyType:
field_info = helpers.lookup_fully_qualified_typeinfo(helpers.get_typechecker_api(ctx), field_info = helpers.lookup_fully_qualified_typeinfo(helpers.get_typechecker_api(ctx),
field_fullname) field_fullname)
assert isinstance(field_info, TypeInfo) if field_info is None:
return AnyType(TypeOfAny.unannotated)
return Instance(field_info, [AnyType(TypeOfAny.explicit), AnyType(TypeOfAny.explicit)]) return Instance(field_info, [AnyType(TypeOfAny.explicit), AnyType(TypeOfAny.explicit)])

View File

@@ -5,8 +5,10 @@ from django.core.exceptions import FieldError
from django.db.models.base import Model from django.db.models.base import Model
from mypy.newsemanal.typeanal import TypeAnalyser from mypy.newsemanal.typeanal import TypeAnalyser
from mypy.nodes import Expression, NameExpr, TypeInfo from mypy.nodes import Expression, NameExpr, TypeInfo
from mypy.plugin import FunctionContext, MethodContext, AnalyzeTypeContext from mypy.plugin import AnalyzeTypeContext, FunctionContext, MethodContext
from mypy.types import AnyType, Instance, Type as MypyType, TypeOfAny from mypy.types import AnyType, Instance
from mypy.types import Type as MypyType
from mypy.types import TypeOfAny
from mypy_django_plugin.django.context import DjangoContext from mypy_django_plugin.django.context import DjangoContext
from mypy_django_plugin.lib import fullnames, helpers from mypy_django_plugin.lib import fullnames, helpers

View File

@@ -1,6 +1,8 @@
from mypy.nodes import MemberExpr, TypeInfo from mypy.nodes import MemberExpr
from mypy.plugin import AttributeContext, FunctionContext from mypy.plugin import AttributeContext, FunctionContext
from mypy.types import Instance, Type as MypyType, TypeType from mypy.types import AnyType, Instance
from mypy.types import Type as MypyType
from mypy.types import TypeOfAny, TypeType
from mypy_django_plugin.django.context import DjangoContext from mypy_django_plugin.django.context import DjangoContext
from mypy_django_plugin.lib import helpers from mypy_django_plugin.lib import helpers
@@ -11,9 +13,10 @@ def get_user_model_hook(ctx: FunctionContext, django_context: DjangoContext) ->
model_cls = django_context.apps_registry.get_model(auth_user_model) model_cls = django_context.apps_registry.get_model(auth_user_model)
model_cls_fullname = helpers.get_class_fullname(model_cls) model_cls_fullname = helpers.get_class_fullname(model_cls)
model_info = helpers.lookup_fully_qualified_generic(model_cls_fullname, model_info = helpers.lookup_fully_qualified_typeinfo(helpers.get_typechecker_api(ctx),
helpers.get_typechecker_api(ctx).modules) model_cls_fullname)
assert isinstance(model_info, TypeInfo) if model_info is None:
return AnyType(TypeOfAny.unannotated)
return TypeType(Instance(model_info, [])) return TypeType(Instance(model_info, []))

View File

@@ -34,3 +34,17 @@
out: | out: |
main:2: note: Revealed type is 'Any' main:2: note: Revealed type is 'Any'
main:2: error: 'Settings' object has no attribute 'NOT_EXISTING' main:2: error: 'Settings' object has no attribute 'NOT_EXISTING'
- case: override_default_setting_with_different_type_in_the_different_module
custom_settings: |
from settings.basic_settings import *
main: |
from django.conf import settings
reveal_type(settings.MEDIA_ROOT) # N: Revealed type is 'pathlib.Path'
reveal_type(settings.MEDIA_ROOT / 'part') # N: Revealed type is 'pathlib.Path*'
files:
- path: settings/__init__.py
- path: settings/basic_settings.py
content: |
from pathlib import Path
MEDIA_ROOT = Path()