diff --git a/README.md b/README.md index 182ef4f..75a9f13 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ pip install django-stubs | django-stubs | mypy version | django version | python version | ------------ | ---- | ---- | ---- | +| 1.3.0 | 0.750 | 2.2.x | ^3.6 | 1.2.0 | 0.730 | 2.2.x | ^3.6 | 1.1.0 | 0.720 | 2.2.x | ^3.6 | 0.12.x | old semantic analyzer (<0.711), dmypy support | 2.1.x | ^3.6 diff --git a/django-stubs/test/utils.pyi b/django-stubs/test/utils.pyi index af1776e..18b192a 100644 --- a/django-stubs/test/utils.pyi +++ b/django-stubs/test/utils.pyi @@ -1,9 +1,22 @@ import decimal -import warnings from contextlib import contextmanager from decimal import Decimal from io import StringIO -from typing import Any, Callable, Dict, Iterable, Iterator, List, Mapping, Optional, Set, Tuple, Type, Union +from typing import ( + Any, + Callable, + Dict, + Iterable, + Iterator, + List, + Mapping, + Optional, + Set, + Tuple, + Type, + Union, + ContextManager, +) from django.apps.registry import Apps from django.core.checks.registry import CheckRegistry @@ -86,7 +99,7 @@ class ignore_warnings(TestContextDecorator): ignore_kwargs: Dict[str, Any] = ... filter_func: Callable = ... def __init__(self, **kwargs: Any) -> None: ... - catch_warnings: warnings.catch_warnings = ... + catch_warnings: ContextManager[Optional[list]] = ... requires_tz_support: Any diff --git a/mypy_django_plugin/django/context.py b/mypy_django_plugin/django/context.py index 6adc50d..1e68763 100644 --- a/mypy_django_plugin/django/context.py +++ b/mypy_django_plugin/django/context.py @@ -367,7 +367,7 @@ class DjangoContext: lookup_type: MypyType = lookup_base.args[0] # if it's Field, consider lookup_type a __get__ of current field if (isinstance(lookup_type, Instance) - and lookup_type.type.fullname() == fullnames.FIELD_FULLNAME): + and lookup_type.type.fullname == fullnames.FIELD_FULLNAME): field_info = helpers.lookup_class_typeinfo(helpers.get_typechecker_api(ctx), field.__class__) if field_info is None: return AnyType(TypeOfAny.explicit) diff --git a/mypy_django_plugin/lib/helpers.py b/mypy_django_plugin/lib/helpers.py index 07952e0..af99bf6 100644 --- a/mypy_django_plugin/lib/helpers.py +++ b/mypy_django_plugin/lib/helpers.py @@ -179,10 +179,10 @@ def add_new_class_for_module(module: MypyFile, name: str, bases: List[Instance], # make new class expression classdef = ClassDef(new_class_unique_name, Block([])) - classdef.fullname = module.fullname() + '.' + new_class_unique_name + classdef.fullname = module.fullname + '.' + new_class_unique_name # make new TypeInfo - new_typeinfo = TypeInfo(SymbolTable(), classdef, module.fullname()) + new_typeinfo = TypeInfo(SymbolTable(), classdef, module.fullname) new_typeinfo.bases = bases calculate_mro(new_typeinfo) new_typeinfo.calculate_metaclass_type() @@ -191,7 +191,7 @@ def add_new_class_for_module(module: MypyFile, name: str, bases: List[Instance], for field_name, field_type in fields.items(): var = Var(field_name, type=field_type) var.info = new_typeinfo - var._fullname = new_typeinfo.fullname() + '.' + field_name + var._fullname = new_typeinfo.fullname + '.' + field_name new_typeinfo.names[field_name] = SymbolTableNode(MDEF, var, plugin_generated=True) classdef.info = new_typeinfo @@ -276,7 +276,7 @@ def get_typechecker_api(ctx: Union[AttributeContext, MethodContext, FunctionCont def is_model_subclass_info(info: TypeInfo, django_context: 'DjangoContext') -> bool: - return (info.fullname() in django_context.all_registered_model_class_fullnames + return (info.fullname in django_context.all_registered_model_class_fullnames or info.has_base(fullnames.MODEL_CLASS_FULLNAME)) @@ -293,7 +293,7 @@ def add_new_sym_for_info(info: TypeInfo, *, name: str, sym_type: MypyType) -> No var = Var(name=name, type=sym_type) # var.info: type of the object variable is bound to var.info = info - var._fullname = info.fullname() + '.' + name + var._fullname = info.fullname + '.' + name var.is_initialized_in_class = True var.is_inferred = True info.names[name] = SymbolTableNode(MDEF, var, diff --git a/mypy_django_plugin/main.py b/mypy_django_plugin/main.py index 5a39b85..3ea89be 100644 --- a/mypy_django_plugin/main.py +++ b/mypy_django_plugin/main.py @@ -121,17 +121,17 @@ class NewSemanalDjangoPlugin(Plugin): def get_additional_deps(self, file: MypyFile) -> List[Tuple[int, str, int]]: # for settings - if file.fullname() == 'django.conf' and self.django_context.django_settings_module: + if file.fullname == 'django.conf' and self.django_context.django_settings_module: return [self._new_dependency(self.django_context.django_settings_module)] # for values / values_list - if file.fullname() == 'django.db.models': + if file.fullname == 'django.db.models': return [self._new_dependency('mypy_extensions'), self._new_dependency('typing')] # for `get_user_model()` if self.django_context.settings: - if (file.fullname() == 'django.contrib.auth' - or file.fullname() in {'django.http', 'django.http.request'}): + if (file.fullname == 'django.contrib.auth' + or file.fullname in {'django.http', 'django.http.request'}): auth_user_model_name = self.django_context.settings.AUTH_USER_MODEL try: auth_user_module = self.django_context.apps_registry.get_model(auth_user_model_name).__module__ @@ -141,7 +141,7 @@ class NewSemanalDjangoPlugin(Plugin): return [self._new_dependency(auth_user_module)] # ensure that all mentioned to='someapp.SomeModel' are loaded with corresponding related Fields - defined_model_classes = self.django_context.model_modules.get(file.fullname()) + defined_model_classes = self.django_context.model_modules.get(file.fullname) if not defined_model_classes: return [] deps = set() @@ -153,13 +153,13 @@ class NewSemanalDjangoPlugin(Plugin): if related_model_cls is None: continue related_model_module = related_model_cls.__module__ - if related_model_module != file.fullname(): + if related_model_module != file.fullname: deps.add(self._new_dependency(related_model_module)) # reverse relations for relation in model_class._meta.related_objects: related_model_cls = self.django_context.get_field_related_model_cls(relation) related_model_module = related_model_cls.__module__ - if related_model_module != file.fullname(): + if related_model_module != file.fullname: deps.add(self._new_dependency(related_model_module)) return list(deps) diff --git a/mypy_django_plugin/transformers/fields.py b/mypy_django_plugin/transformers/fields.py index 32d20bf..b88fdbf 100644 --- a/mypy_django_plugin/transformers/fields.py +++ b/mypy_django_plugin/transformers/fields.py @@ -29,7 +29,7 @@ def _get_current_field_from_assignment(ctx: FunctionContext, django_context: Dja if field_name is None: return None - model_cls = django_context.get_model_class_by_fullname(outer_model_info.fullname()) + model_cls = django_context.get_model_class_by_fullname(outer_model_info.fullname) if model_cls is None: return None diff --git a/mypy_django_plugin/transformers/init_create.py b/mypy_django_plugin/transformers/init_create.py index 2edfdef..fe0b19e 100644 --- a/mypy_django_plugin/transformers/init_create.py +++ b/mypy_django_plugin/transformers/init_create.py @@ -54,7 +54,7 @@ def typecheck_model_method(ctx: Union[FunctionContext, MethodContext], django_co def redefine_and_typecheck_model_init(ctx: FunctionContext, django_context: DjangoContext) -> MypyType: assert isinstance(ctx.default_return_type, Instance) - model_fullname = ctx.default_return_type.type.fullname() + model_fullname = ctx.default_return_type.type.fullname model_cls = django_context.get_model_class_by_fullname(model_fullname) if model_cls is None: return ctx.default_return_type @@ -67,7 +67,7 @@ def redefine_and_typecheck_model_create(ctx: MethodContext, django_context: Djan # only work with ctx.default_return_type = model Instance return ctx.default_return_type - model_fullname = ctx.default_return_type.type.fullname() + model_fullname = ctx.default_return_type.type.fullname model_cls = django_context.get_model_class_by_fullname(model_fullname) if model_cls is None: return ctx.default_return_type diff --git a/mypy_django_plugin/transformers/meta.py b/mypy_django_plugin/transformers/meta.py index 2b83df6..9549ac9 100644 --- a/mypy_django_plugin/transformers/meta.py +++ b/mypy_django_plugin/transformers/meta.py @@ -28,7 +28,7 @@ def return_proper_field_type_from_get_field(ctx: MethodContext, django_context: if not isinstance(model_type, Instance): return ctx.default_return_type - model_cls = django_context.get_model_class_by_fullname(model_type.type.fullname()) + model_cls = django_context.get_model_class_by_fullname(model_type.type.fullname) if model_cls is None: return ctx.default_return_type diff --git a/mypy_django_plugin/transformers/models.py b/mypy_django_plugin/transformers/models.py index aa95cdb..7cd26b7 100644 --- a/mypy_django_plugin/transformers/models.py +++ b/mypy_django_plugin/transformers/models.py @@ -43,7 +43,7 @@ class ModelClassInitializer: var = Var(name=name, type=typ) # var.info: type of the object variable is bound to var.info = self.model_classdef.info - var._fullname = self.model_classdef.info.fullname() + '.' + name + var._fullname = self.model_classdef.info.fullname + '.' + name var.is_initialized_in_class = True var.is_inferred = True return var @@ -126,7 +126,7 @@ class AddRelatedModelsId(ModelClassInitializer): class AddManagers(ModelClassInitializer): def _is_manager_any(self, typ: Instance) -> bool: - return typ.type.fullname() == fullnames.MANAGER_CLASS_FULLNAME and type(typ.args[0]) == AnyType + return typ.type.fullname == fullnames.MANAGER_CLASS_FULLNAME and type(typ.args[0]) == AnyType def run_with_model_cls(self, model_cls: Type[Model]) -> None: for manager_name, manager in model_cls._meta.managers_map.items(): @@ -163,7 +163,7 @@ class AddManagers(ModelClassInitializer): if isinstance(new_sym.node, Var): new_var = Var(name, type=sym.type) new_var.info = custom_manager_info - new_var._fullname = custom_manager_info.fullname() + '.' + name + new_var._fullname = custom_manager_info.fullname + '.' + name new_sym.node = new_var custom_manager_info.names[name] = new_sym diff --git a/mypy_django_plugin/transformers/orm_lookups.py b/mypy_django_plugin/transformers/orm_lookups.py index e1ed913..0aa516b 100644 --- a/mypy_django_plugin/transformers/orm_lookups.py +++ b/mypy_django_plugin/transformers/orm_lookups.py @@ -16,7 +16,7 @@ def typecheck_queryset_filter(ctx: MethodContext, django_context: DjangoContext) if not ctx.type.args or not isinstance(ctx.type.args[0], Instance): return ctx.default_return_type - model_cls_fullname = ctx.type.args[0].type.fullname() + model_cls_fullname = ctx.type.args[0].type.fullname model_cls = django_context.get_model_class_by_fullname(model_cls_fullname) if model_cls is None: return ctx.default_return_type @@ -44,7 +44,7 @@ def typecheck_queryset_filter(ctx: MethodContext, django_context: DjangoContext) def resolve_combinable_type(combinable_type: Instance, django_context: DjangoContext) -> MypyType: - if combinable_type.type.fullname() != fullnames.F_EXPRESSION_FULLNAME: + if combinable_type.type.fullname != fullnames.F_EXPRESSION_FULLNAME: # Combinables aside from F expressions are unsupported return AnyType(TypeOfAny.explicit) diff --git a/mypy_django_plugin/transformers/querysets.py b/mypy_django_plugin/transformers/querysets.py index 8789995..5c086ef 100644 --- a/mypy_django_plugin/transformers/querysets.py +++ b/mypy_django_plugin/transformers/querysets.py @@ -117,7 +117,7 @@ def extract_proper_type_queryset_values_list(ctx: MethodContext, django_context: if model_type is None: return AnyType(TypeOfAny.from_omitted_generics) - model_cls = django_context.get_model_class_by_fullname(model_type.type.fullname()) + model_cls = django_context.get_model_class_by_fullname(model_type.type.fullname) if model_cls is None: return ctx.default_return_type @@ -166,7 +166,7 @@ def extract_proper_type_queryset_values(ctx: MethodContext, django_context: Djan if model_type is None: return AnyType(TypeOfAny.from_omitted_generics) - model_cls = django_context.get_model_class_by_fullname(model_type.type.fullname()) + model_cls = django_context.get_model_class_by_fullname(model_type.type.fullname) if model_cls is None: return ctx.default_return_type diff --git a/setup.py b/setup.py index e66da9a..9e5bbe0 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ with open('README.md', 'r') as f: readme = f.read() dependencies = [ - 'mypy>=0.740,<0.750', + 'mypy>=0.750,<0.760', 'typing-extensions', 'django', ] diff --git a/test-data/typecheck/managers/test_managers.yml b/test-data/typecheck/managers/test_managers.yml index 939a782..885ee0e 100644 --- a/test-data/typecheck/managers/test_managers.yml +++ b/test-data/typecheck/managers/test_managers.yml @@ -318,7 +318,7 @@ content: | from django.db import models class MyManager(models.Manager): - def get_instance(self) -> int: + def get_instance(self: "models.Manager[User]") -> int: pass class User(models.Model): objects = MyManager()