mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-08 13:04:47 +08:00
allow manager classes nested inside model classes
This commit is contained in:
@@ -31,15 +31,30 @@ def get_django_metadata(model_info: TypeInfo) -> Dict[str, Any]:
|
|||||||
def lookup_fully_qualified_sym(fullname: str, all_modules: Dict[str, MypyFile]) -> Optional[SymbolTableNode]:
|
def lookup_fully_qualified_sym(fullname: str, all_modules: Dict[str, MypyFile]) -> Optional[SymbolTableNode]:
|
||||||
if '.' not in fullname:
|
if '.' not in fullname:
|
||||||
return None
|
return None
|
||||||
module, cls_name = fullname.rsplit('.', 1)
|
|
||||||
|
|
||||||
module_file = all_modules.get(module)
|
module_file = None
|
||||||
|
parts = fullname.split('.')
|
||||||
|
for i in range(len(parts), 0, -1):
|
||||||
|
possible_module_name = '.'.join(parts[:i])
|
||||||
|
if possible_module_name in all_modules:
|
||||||
|
module_file = all_modules[possible_module_name]
|
||||||
|
break
|
||||||
|
|
||||||
if module_file is None:
|
if module_file is None:
|
||||||
return None
|
return None
|
||||||
sym = module_file.names.get(cls_name)
|
|
||||||
if sym is None:
|
cls_name = fullname.replace(module_file.fullname, '').lstrip('.')
|
||||||
return None
|
sym_table = module_file.names
|
||||||
return sym
|
if '.' in cls_name:
|
||||||
|
parent_cls_name, _, cls_name = cls_name.rpartition('.')
|
||||||
|
# nested class
|
||||||
|
for parent_cls_name in parent_cls_name.split('.'):
|
||||||
|
sym = sym_table.get(parent_cls_name)
|
||||||
|
if sym is None:
|
||||||
|
return None
|
||||||
|
sym_table = sym.node.names
|
||||||
|
|
||||||
|
return sym_table.get(cls_name)
|
||||||
|
|
||||||
|
|
||||||
def lookup_fully_qualified_generic(name: str, all_modules: Dict[str, MypyFile]) -> Optional[SymbolNode]:
|
def lookup_fully_qualified_generic(name: str, all_modules: Dict[str, MypyFile]) -> Optional[SymbolNode]:
|
||||||
|
|||||||
@@ -310,4 +310,4 @@ def instantiate_anonymous_queryset_from_as_manager(ctx: MethodContext) -> MypyTy
|
|||||||
assert module_name == current_module.fullname
|
assert module_name == current_module.fullname
|
||||||
|
|
||||||
generated_manager_info = current_module.names[class_name].node
|
generated_manager_info = current_module.names[class_name].node
|
||||||
return fill_typevars(generated_manager_info)
|
return Instance(generated_manager_info, [])
|
||||||
|
|||||||
@@ -314,6 +314,9 @@ IGNORED_ERRORS = {
|
|||||||
'model_enums': [
|
'model_enums': [
|
||||||
"'bool' is not a valid base class",
|
"'bool' is not a valid base class",
|
||||||
],
|
],
|
||||||
|
'multiple_database': [
|
||||||
|
'Unexpected attribute "extra_arg" for model "Book"',
|
||||||
|
],
|
||||||
'null_queries': [
|
'null_queries': [
|
||||||
"Cannot resolve keyword 'foo' into field"
|
"Cannot resolve keyword 'foo' into field"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -335,3 +335,23 @@
|
|||||||
objects = MyManager()
|
objects = MyManager()
|
||||||
class ChildUser(models.Model):
|
class ChildUser(models.Model):
|
||||||
objects = MyManager()
|
objects = MyManager()
|
||||||
|
|
||||||
|
|
||||||
|
- case: manager_defined_in_the_nested_class
|
||||||
|
main: |
|
||||||
|
from myapp.models import MyModel
|
||||||
|
reveal_type(MyModel.objects) # N: Revealed type is 'myapp.models.MyModel_MyManager[myapp.models.MyModel]'
|
||||||
|
reveal_type(MyModel.objects.get()) # N: Revealed type is 'myapp.models.MyModel*'
|
||||||
|
reveal_type(MyModel.objects.mymethod()) # N: Revealed type is 'builtins.int'
|
||||||
|
installed_apps:
|
||||||
|
- myapp
|
||||||
|
files:
|
||||||
|
- path: myapp/__init__.py
|
||||||
|
- path: myapp/models.py
|
||||||
|
content: |
|
||||||
|
from django.db import models
|
||||||
|
class MyModel(models.Model):
|
||||||
|
class MyManager(models.Manager):
|
||||||
|
def mymethod(self) -> int:
|
||||||
|
pass
|
||||||
|
objects = MyManager()
|
||||||
Reference in New Issue
Block a user