Skip to content

Commit ac2b526

Browse files
authored
Do models.Model adjustments from get_metaclass_hook (#2322)
The called hook expects/wants the class body analyzed, but the `get_customize_class_mro_hook` hook, that it was previously called from, invokes the hook before the class body has been analyzed..
1 parent d173a18 commit ac2b526

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

mypy_django_plugin/main.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,6 @@ def get_method_hook(self, fullname: str) -> Optional[Callable[[MethodContext], M
223223
return None
224224

225225
def get_customize_class_mro_hook(self, fullname: str) -> Optional[Callable[[ClassDefContext], None]]:
226-
if fullname == fullnames.MODEL_CLASS_FULLNAME:
227-
return MetaclassAdjustments.adjust_model_class
228-
229226
sym = self.lookup_fully_qualified(fullname)
230227
if (
231228
sym is not None
@@ -236,6 +233,11 @@ def get_customize_class_mro_hook(self, fullname: str) -> Optional[Callable[[Clas
236233
else:
237234
return None
238235

236+
def get_metaclass_hook(self, fullname: str) -> Optional[Callable[[ClassDefContext], None]]:
237+
if fullname == fullnames.MODEL_METACLASS_FULLNAME:
238+
return MetaclassAdjustments.adjust_model_class
239+
return None
240+
239241
def get_base_class_hook(self, fullname: str) -> Optional[Callable[[ClassDefContext], None]]:
240242
# Base class is a Model class definition
241243
sym = self.lookup_fully_qualified(fullname)

tests/typecheck/managers/test_managers.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,3 +761,53 @@
761761
generic_manager = models.Manager()
762762
generic_manager_from_generic_queryset = GenericManagerFromGenericQuerySet()
763763
generic_manager_from_populated_queryset = GenericManagerFromPopulatedQuerySet()
764+
765+
# Regression test for #2304
766+
- case: test_objects_managers_is_kept_with_specific_import_graph
767+
main: |
768+
from zerver.models import RealmFilter
769+
reveal_type(RealmFilter.objects) # N: Revealed type is "django.db.models.manager.Manager[zerver.models.linkifiers.RealmFilter]"
770+
installed_apps:
771+
- django.contrib.auth
772+
- django.contrib.contenttypes
773+
- confirmation
774+
- zerver
775+
files:
776+
- path: confirmation/__init__.py
777+
- path: confirmation/models.py
778+
content: |
779+
from django.db import models
780+
from zerver.models import Realm
781+
class Confirmation(models.Model):
782+
realm = models.ForeignKey(Realm, on_delete=models.CASCADE)
783+
- path: zerver/__init__.py
784+
- path: zerver/models/__init__.py
785+
content: |
786+
from zerver.models.linkifiers import RealmFilter as RealmFilter
787+
from zerver.models.realms import Realm as Realm
788+
from zerver.models.streams import Stream as Stream
789+
from zerver.models.users import UserProfile as UserProfile
790+
RealmFilter.objects
791+
- path: zerver/models/linkifiers.py
792+
content: |
793+
from django.db import models
794+
class RealmFilter(models.Model):
795+
pass
796+
- path: zerver/models/realms.py
797+
content: |
798+
from django.db import models
799+
class Realm(models.Model):
800+
pass
801+
- path: zerver/models/streams.py
802+
content: |
803+
from django.db import models
804+
from zerver.models.realms import Realm
805+
from zerver.models.users import UserProfile
806+
class Stream(models.Model):
807+
realm = models.ForeignKey(Realm, on_delete=models.RESTRICT)
808+
creator = models.ForeignKey(UserProfile, on_delete=models.RESTRICT)
809+
- path: zerver/models/users.py
810+
content: |
811+
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
812+
class UserProfile(AbstractBaseUser, PermissionsMixin):
813+
pass

0 commit comments

Comments
 (0)