@@ -319,11 +319,18 @@ def reparametrize_dynamically_created_manager(self, manager_name: str, manager_i
319319 assert manager_info is not None
320320 # Reparameterize dynamically created manager with model type
321321 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
322325 self .add_new_node_to_model_class (manager_name , manager_type , is_classvar = True )
323326
324327 def run_with_model_cls (self , model_cls : Type [Model ]) -> None :
325328 manager_info : Optional [TypeInfo ]
326329
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+
327334 incomplete_manager_defs = set ()
328335 for manager_name , manager in model_cls ._meta .managers_map .items ():
329336 manager_node = self .model_classdef .info .get (manager_name )
@@ -345,7 +352,24 @@ def run_with_model_cls(self, model_cls: Type[Model]) -> None:
345352
346353 assert self .model_classdef .info .self_type is not None
347354 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 )
349373
350374 if incomplete_manager_defs :
351375 if not self .api .final_iteration :
@@ -360,6 +384,7 @@ def run_with_model_cls(self, model_cls: Type[Model]) -> None:
360384 # setting _some_ type
361385 fallback_manager_info = self .get_or_create_manager_with_any_fallback ()
362386 if fallback_manager_info is not None :
387+ cast_var_to_classvar (self .model_classdef .info .get (manager_name ))
363388 assert self .model_classdef .info .self_type is not None
364389 manager_type = helpers .fill_manager (fallback_manager_info , self .model_classdef .info .self_type )
365390 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:
958983 ):
959984 del ctx .cls .info .names ["MultipleObjectsReturned" ]
960985
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-
967986 def get_exception_bases (self , name : str ) -> List [Instance ]:
968987 bases = []
969988 for model_base in self .model_classdef .info .direct_base_classes ():
0 commit comments