@@ -319,11 +319,18 @@ def reparametrize_dynamically_created_manager(self, manager_name: str, manager_i
319
319
assert manager_info is not None
320
320
# Reparameterize dynamically created manager with model type
321
321
manager_type = helpers .fill_manager (manager_info , Instance (self .model_classdef .info , []))
322
+ manager_node = self .model_classdef .info .get (manager_name )
323
+ if manager_node and isinstance (manager_node .node , Var ):
324
+ manager_node .node .type = manager_type
322
325
self .add_new_node_to_model_class (manager_name , manager_type , is_classvar = True )
323
326
324
327
def run_with_model_cls (self , model_cls : Type [Model ]) -> None :
325
328
manager_info : Optional [TypeInfo ]
326
329
330
+ def cast_var_to_classvar (symbol : Optional [SymbolTableNode ]) -> None :
331
+ if symbol and isinstance (symbol .node , Var ):
332
+ symbol .node .is_classvar = True
333
+
327
334
incomplete_manager_defs = set ()
328
335
for manager_name , manager in model_cls ._meta .managers_map .items ():
329
336
manager_node = self .model_classdef .info .get (manager_name )
@@ -345,7 +352,24 @@ def run_with_model_cls(self, model_cls: Type[Model]) -> None:
345
352
346
353
assert self .model_classdef .info .self_type is not None
347
354
manager_type = helpers .fill_manager (manager_info , self .model_classdef .info .self_type )
348
- self .add_new_node_to_model_class (manager_name , manager_type , is_classvar = True )
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 )
369
+ if manager_fullname == manager_info .fullname and manager_node and isinstance (manager_node .node , Var ):
370
+ manager_node .node .type = manager_type
371
+ else :
372
+ self .add_new_node_to_model_class (manager_name , manager_type , is_classvar = True )
349
373
350
374
if incomplete_manager_defs :
351
375
if not self .api .final_iteration :
@@ -360,6 +384,7 @@ def run_with_model_cls(self, model_cls: Type[Model]) -> None:
360
384
# setting _some_ type
361
385
fallback_manager_info = self .get_or_create_manager_with_any_fallback ()
362
386
if fallback_manager_info is not None :
387
+ cast_var_to_classvar (self .model_classdef .info .get (manager_name ))
363
388
assert self .model_classdef .info .self_type is not None
364
389
manager_type = helpers .fill_manager (fallback_manager_info , self .model_classdef .info .self_type )
365
390
self .add_new_node_to_model_class (manager_name , manager_type , is_classvar = True )
@@ -958,12 +983,6 @@ def adjust_model_class(cls, ctx: ClassDefContext) -> None:
958
983
):
959
984
del ctx .cls .info .names ["MultipleObjectsReturned" ]
960
985
961
- objects = ctx .cls .info .names .get ("objects" )
962
- if objects is not None and isinstance (objects .node , Var ) and not objects .plugin_generated :
963
- del ctx .cls .info .names ["objects" ]
964
-
965
- return
966
-
967
986
def get_exception_bases (self , name : str ) -> List [Instance ]:
968
987
bases = []
969
988
for model_base in self .model_classdef .info .direct_base_classes ():
0 commit comments