1616    SymbolTableNode ,
1717    TypeInfo ,
1818)
19- from  mypy .plugin  import  AttributeContext , ClassDefContext , DynamicClassDefContext , MethodContext 
19+ from  mypy .plugin  import  AttributeContext , ClassDefContext , DynamicClassDefContext 
20+ from  mypy .plugins .common  import  add_method_to_class 
2021from  mypy .semanal  import  SemanticAnalyzer 
2122from  mypy .semanal_shared  import  has_placeholder 
2223from  mypy .subtypes  import  find_member 
@@ -482,44 +483,37 @@ def populate_manager_from_queryset(manager_info: TypeInfo, queryset_info: TypeIn
482483        )
483484
484485
485- def  create_new_manager_class_from_as_manager_method (ctx : DynamicClassDefContext ) ->  None :
486-     """ 
487-     Insert a new manager class node for a 
488- 
489-     ``` 
490-     <manager name> = <QuerySet>.as_manager() 
491-     ``` 
492-     """ 
486+ def  add_as_manager_to_queryset_class (ctx : ClassDefContext ) ->  None :
493487    semanal_api  =  helpers .get_semanal_api (ctx )
494-     # Don't redeclare the manager class if we've already defined it. 
495-     manager_node  =  semanal_api .lookup_current_scope (ctx .name )
496-     if  manager_node  and  manager_node .type  is  not None :
497-         # This is just a deferral run where our work is already finished 
498-         return 
499488
500-     manager_sym  =  semanal_api .lookup_fully_qualified_or_none (fullnames .MANAGER_CLASS_FULLNAME )
501-     assert  manager_sym  is  not None 
502-     manager_base  =  manager_sym .node 
503-     if  manager_base  is  None :
489+     def  _defer () ->  None :
504490        if  not  semanal_api .final_iteration :
505491            semanal_api .defer ()
506-         return 
507492
508-     assert  isinstance (manager_base , TypeInfo )
493+     queryset_info  =  semanal_api .type 
494+     if  queryset_info  is  None :
495+         return  _defer ()
509496
510-     callee   =   ctx . call . callee 
511-     assert   isinstance ( callee ,  MemberExpr ) 
512-     assert   isinstance ( callee . expr ,  RefExpr ) 
497+     # either a manual `as_manager` definition or this is a deferral pass 
498+     if   "as_manager"   in   queryset_info . names : 
499+          return 
513500
514-     queryset_info  =  callee .expr .node 
515-     if  queryset_info  is  None :
516-         if  not  semanal_api .final_iteration :
517-             semanal_api .defer ()
501+     base_as_manager  =  queryset_info .get ("as_manager" )
502+     if  (
503+         base_as_manager  is  None 
504+         or  not  isinstance (base_as_manager .type , CallableType )
505+         or  not  isinstance (base_as_manager .type .ret_type , Instance )
506+     ):
518507        return 
519508
520-     assert  isinstance (queryset_info , TypeInfo )
509+     base_ret_type  =  base_as_manager .type .ret_type .type 
510+ 
511+     manager_sym  =  semanal_api .lookup_fully_qualified_or_none (fullnames .MANAGER_CLASS_FULLNAME )
512+     if  manager_sym  is  None  or  not  isinstance (manager_sym .node , TypeInfo ):
513+         return  _defer ()
521514
522-     manager_class_name  =  manager_base .name  +  "From"  +  queryset_info .name 
515+     manager_base  =  manager_sym .node 
516+     manager_class_name  =  f"{ manager_base .name } { queryset_info .name }  
523517    current_module  =  semanal_api .modules [semanal_api .cur_mod_id ]
524518    existing_sym  =  current_module .names .get (manager_class_name )
525519    if  (
@@ -535,54 +529,37 @@ def create_new_manager_class_from_as_manager_method(ctx: DynamicClassDefContext)
535529        try :
536530            new_manager_info  =  create_manager_class (
537531                api = semanal_api ,
538-                 base_manager_info = manager_base ,
532+                 base_manager_info = base_ret_type ,
539533                name = manager_class_name ,
540-                 line = ctx . call .line ,
534+                 line = queryset_info .line ,
541535                with_unique_name = True ,
542536            )
543537        except  helpers .IncompleteDefnException :
544-             if  not  semanal_api .final_iteration :
545-                 semanal_api .defer ()
546-             return 
538+             return  _defer ()
547539
548540        populate_manager_from_queryset (new_manager_info , queryset_info )
549541        register_dynamically_created_manager (
550542            fullname = new_manager_info .fullname ,
551543            manager_name = manager_class_name ,
552544            manager_base = manager_base ,
553545        )
554-         queryset_info .metadata .setdefault ("django_as_manager_names" , {})
555-         queryset_info .metadata ["django_as_manager_names" ][semanal_api .cur_mod_id ] =  new_manager_info .name 
556546
557547    # Add the new manager to the current module 
558-     added  =  semanal_api .add_symbol_table_node (
559-         # We'll use `new_manager_info.name` instead of `manager_class_name` here 
560-         # to handle possible name collisions, as it's unique. 
561-         new_manager_info .name ,
548+     # We'll use `new_manager_info.name` instead of `manager_class_name` here 
549+     # to handle possible name collisions, as it's unique. 
550+     current_module .names [new_manager_info .name ] =  (
562551        # Note that the generated manager type is always inserted at module level 
563-         SymbolTableNode (GDEF , new_manager_info , plugin_generated = True ), 
552+         SymbolTableNode (GDEF , new_manager_info , plugin_generated = True )
564553    )
565-     assert  added 
566- 
567554
568- def  construct_as_manager_instance (ctx : MethodContext , * , info : TypeInfo ) ->  MypyType :
569-     api  =  helpers .get_typechecker_api (ctx )
570-     module  =  helpers .get_current_module (api )
571-     try :
572-         manager_name  =  info .metadata ["django_as_manager_names" ][module .fullname ]
573-     except  KeyError :
574-         return  ctx .default_return_type 
575- 
576-     manager_node  =  api .lookup (manager_name )
577-     if  not  isinstance (manager_node .node , TypeInfo ):
578-         return  ctx .default_return_type 
579- 
580-     # Whenever `<QuerySet>.as_manager()` isn't called at class level, we want to ensure 
581-     # that the variable is an instance of our generated manager. Instead of the return 
582-     # value of `.as_manager()`. Though model argument is populated as `Any`. 
583-     # `transformers.models.AddManagers` will populate a model's manager(s), when it 
584-     # finds it on class level. 
585-     return  Instance (manager_node .node , [AnyType (TypeOfAny .from_omitted_generics )])
555+     add_method_to_class (
556+         semanal_api ,
557+         ctx .cls ,
558+         "as_manager" ,
559+         args = [],
560+         return_type = Instance (new_manager_info , [AnyType (TypeOfAny .from_omitted_generics )]),
561+         is_classmethod = True ,
562+     )
586563
587564
588565def  reparametrize_any_manager_hook (ctx : ClassDefContext ) ->  None :
0 commit comments