Skip to content

Commit c7a4ae4

Browse files
committed
fixup! Don't remove objects attribute from Model in plugin
1 parent a7f78fd commit c7a4ae4

File tree

4 files changed

+30
-33
lines changed

4 files changed

+30
-33
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from typing import TypeVar
22

3+
from django.contrib.sites.models import Site
34
from django.db import models
45

5-
_T = TypeVar("_T", bound=models.Model)
6+
_T = TypeVar("_T", bound=Site)
67

78
class CurrentSiteManager(models.Manager[_T]):
89
def __init__(self, field_name: str | None = ...) -> None: ...

mypy_django_plugin/transformers/models.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -352,23 +352,23 @@ def cast_var_to_classvar(symbol: Optional[SymbolTableNode]) -> None:
352352

353353
assert self.model_classdef.info.self_type is not None
354354
manager_type = Instance(manager_info, [self.model_classdef.info.self_type])
355+
# It seems that the type checker fetches a Var from expressions, but looks
356+
# through the symbol table for the type(at some later stage?). Currently we
357+
# don't overwrite the reference mypy holds from an expression to a Var
358+
# instance when adding a new node, we only overwrite the reference to the
359+
# Var in the symbol table. That means there's a lingering Var instance
360+
# attached to expressions and if we don't flip that to a ClassVar, the
361+
# checker will emit an error for overriding a class variable with an
362+
# instance variable. As mypy seems to check that via the expression and not
363+
# the symbol table. Optimally we want to just set a type on the existing Var
364+
# like:
365+
# manager_node.node.type = manager_type
366+
# but for some reason that doesn't work. It only works replacing the
367+
# existing Var with a new one in the symbol table.
368+
cast_var_to_classvar(manager_node)
355369
if manager_fullname == manager_info.fullname and manager_node and isinstance(manager_node.node, Var):
356370
manager_node.node.type = manager_type
357371
else:
358-
# It seems that the type checker fetches a Var from expressions, but
359-
# looks through the symbol table for the type(at some later stage?).
360-
# Currently we don't overwrite the reference mypy holds from an
361-
# expression to a Var instance when adding a new node, we only overwrite
362-
# the reference to the Var in the symbol table. That means there's a
363-
# lingering Var instance attached to expressions and if we don't flip
364-
# that to a ClassVar, the checker will emit an error for overriding a
365-
# class variable with an instance variable. As mypy seems to check that
366-
# via the expression and not the symbol table. Optimally we want to just
367-
# set a type on the existing Var like
368-
# manager_node.node.type = manager_type
369-
# but for some reason that doesn't work. It only works replacing the
370-
# existing Var with a new one in the symbol table.
371-
cast_var_to_classvar(manager_node)
372372
self.add_new_node_to_model_class(manager_name, manager_type, is_classvar=True)
373373

374374
if incomplete_manager_defs:

tests/typecheck/managers/test_managers.yml

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -169,29 +169,28 @@
169169
main: |
170170
from myapp.models import AbstractPerson, Book
171171
reveal_type(AbstractPerson.abstract_persons) # N: Revealed type is "django.db.models.manager.Manager[myapp.models.AbstractPerson]"
172-
reveal_type(Book.published_objects) # N: Revealed type is "myapp.models.PublishedBookManager"
172+
reveal_type(Book.published_objects) # N: Revealed type is "myapp.models.PublishedBookManager[myapp.models.Book]"
173173
Book.published_objects.create(title='hello')
174-
reveal_type(Book.annotated_objects) # N: Revealed type is "myapp.models.AnnotatedBookManager"
174+
reveal_type(Book.annotated_objects) # N: Revealed type is "myapp.models.AnnotatedBookManager[myapp.models.Book]"
175175
Book.annotated_objects.create(title='hello')
176176
installed_apps:
177177
- myapp
178178
files:
179179
- path: myapp/__init__.py
180180
- path: myapp/models.py
181181
content: |
182-
from typing import ClassVar
183182
from django.db import models
184183
185184
class AbstractPerson(models.Model):
186-
abstract_persons: ClassVar[models.Manager["AbstractPerson"]] = models.Manager['AbstractPerson']()
185+
abstract_persons = models.Manager['AbstractPerson']()
187186
class PublishedBookManager(models.Manager['Book']):
188187
pass
189188
class AnnotatedBookManager(models.Manager['Book']):
190189
pass
191190
class Book(models.Model):
192191
title = models.CharField(max_length=50)
193-
published_objects: ClassVar[PublishedBookManager] = PublishedBookManager()
194-
annotated_objects: ClassVar[AnnotatedBookManager] = AnnotatedBookManager()
192+
published_objects = PublishedBookManager()
193+
annotated_objects = AnnotatedBookManager()
195194
196195
- case: managers_inherited_from_abstract_classes_multiple_inheritance
197196
main: |
@@ -201,32 +200,31 @@
201200
reveal_type(AbstractBase1.manager1)
202201
reveal_type(AbstractBase2.restricted)
203202
out: |
204-
main:2: note: Revealed type is "myapp.models.CustomManager1"
205-
main:3: note: Revealed type is "myapp.models.CustomManager2"
206-
main:4: note: Revealed type is "myapp.models.CustomManager1"
207-
main:5: note: Revealed type is "myapp.models.CustomManager2"
203+
main:2: note: Revealed type is "myapp.models.CustomManager1[myapp.models.Child]"
204+
main:3: note: Revealed type is "myapp.models.CustomManager2[myapp.models.Child]"
205+
main:4: note: Revealed type is "myapp.models.CustomManager1[myapp.models.AbstractBase1]"
206+
main:5: note: Revealed type is "myapp.models.CustomManager2[myapp.models.AbstractBase2]"
208207
installed_apps:
209208
- myapp
210209
files:
211210
- path: myapp/__init__.py
212211
- path: myapp/models.py
213212
content: |
214-
from typing import ClassVar
215213
from django.db import models
216214
class CustomManager1(models.Manager['AbstractBase1']):
217215
pass
218216
class AbstractBase1(models.Model):
219217
class Meta:
220218
abstract = True
221219
name = models.CharField(max_length=50)
222-
manager1: ClassVar[CustomManager1] = CustomManager1()
220+
manager1 = CustomManager1()
223221
class CustomManager2(models.Manager['AbstractBase2']):
224222
pass
225223
class AbstractBase2(models.Model):
226224
class Meta:
227225
abstract = True
228226
value = models.CharField(max_length=50)
229-
restricted: ClassVar[CustomManager2] = CustomManager2()
227+
restricted = CustomManager2()
230228
231229
class Child(AbstractBase1, AbstractBase2):
232230
pass
@@ -453,15 +451,13 @@
453451
- path: myapp/__init__.py
454452
- path: myapp/models.py
455453
content: |
456-
from typing import ClassVar
457-
from typing_extensions import Self
458454
from django.db import models
459455
from django.contrib.sites.models import Site
460456
from django.contrib.sites.managers import CurrentSiteManager
461457
462458
class MyModel(models.Model):
463459
site = models.ForeignKey(Site, on_delete=models.CASCADE)
464-
on_site: ClassVar[CurrentSiteManager[Self]] = CurrentSiteManager()
460+
on_site = CurrentSiteManager()
465461
466462
- case: test_emits_error_for_unresolved_managers
467463
main: |

tests/typecheck/models/test_contrib_models.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
- case: can_override_abstract_user_manager
3939
main: |
4040
from myapp.models import MyBaseUser, MyUser
41-
reveal_type(MyBaseUser.objects) # N: Revealed type is "myapp.models.MyBaseUserManager"
41+
reveal_type(MyBaseUser.objects) # N: Revealed type is "myapp.models.MyBaseUserManager[myapp.models.MyBaseUser]"
4242
reveal_type(MyBaseUser.objects.all()) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyBaseUser, myapp.models.MyBaseUser]"
4343
reveal_type(MyUser.objects) # N: Revealed type is "myapp.models.MyUserManager"
4444
reveal_type(MyUser.objects.all()) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyUser, myapp.models.MyUser]"
@@ -56,7 +56,7 @@
5656
...
5757
5858
class MyBaseUser(AbstractBaseUser):
59-
objects: ClassVar[MyBaseUserManager] = MyBaseUserManager()
59+
objects = MyBaseUserManager()
6060
6161
class MyUserManager(UserManager["MyUser"]):
6262
...

0 commit comments

Comments
 (0)