1515 StrExpr ,
1616 SymbolTableNode ,
1717 TypeInfo ,
18- Var ,
1918)
20- from mypy .plugin import AttributeContext , ClassDefContext , DynamicClassDefContext
19+ from mypy .plugin import AttributeContext , ClassDefContext , DynamicClassDefContext , MethodContext
2120from mypy .semanal import SemanticAnalyzer
2221from mypy .semanal_shared import has_placeholder
22+ from mypy .subtypes import find_member
2323from mypy .types import (
2424 AnyType ,
2525 CallableType ,
2828 Overloaded ,
2929 ProperType ,
3030 TypeOfAny ,
31+ TypeType ,
3132 TypeVarType ,
3233 UnionType ,
3334 get_proper_type ,
@@ -121,15 +122,11 @@ def _process_dynamic_method(
121122 variables = method_type .variables
122123 ret_type = method_type .ret_type
123124
124- if not is_fallback_queryset :
125- queryset_instance = Instance (queryset_info , manager_instance .args )
126- else :
127- # The fallback queryset inherits _QuerySet, which has two generics
128- # instead of the one exposed on QuerySet. That means that we need
129- # to add the model twice. In real code it's not possible to inherit
130- # from _QuerySet, as it doesn't exist at runtime, so this fix is
131- # only needed for plugin-generated querysets.
132- queryset_instance = Instance (queryset_info , [manager_instance .args [0 ], manager_instance .args [0 ]])
125+ manager_model = find_member ("model" , manager_instance , manager_instance )
126+ assert isinstance (manager_model , TypeType ), manager_model
127+ manager_model_type = manager_model .item
128+
129+ queryset_instance = Instance (queryset_info , (manager_model_type ,) * len (queryset_info .type_vars ))
133130
134131 # For methods on the manager that return a queryset we need to override the
135132 # return type to be the actual queryset class, not the base QuerySet that's
@@ -554,23 +551,9 @@ def create_new_manager_class_from_as_manager_method(ctx: DynamicClassDefContext)
554551 manager_name = manager_class_name ,
555552 manager_base = manager_base ,
556553 )
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
557556
558- # Whenever `<QuerySet>.as_manager()` isn't called at class level, we want to ensure
559- # that the variable is an instance of our generated manager. Instead of the return
560- # value of `.as_manager()`. Though model argument is populated as `Any`.
561- # `transformers.models.AddManagers` will populate a model's manager(s), when it
562- # finds it on class level.
563- var = Var (name = ctx .name , type = Instance (new_manager_info , [AnyType (TypeOfAny .from_omitted_generics )]))
564- var .info = new_manager_info
565- var ._fullname = f"{ current_module .fullname } .{ ctx .name } "
566- var .is_inferred = True
567- # Note: Order of `add_symbol_table_node` calls matters. Depending on what level
568- # we've found the `.as_manager()` call. Point here being that we want to replace the
569- # `.as_manager` return value with our newly created manager.
570- added = semanal_api .add_symbol_table_node (
571- ctx .name , SymbolTableNode (semanal_api .current_symbol_kind (), var , plugin_generated = True )
572- )
573- assert added
574557 # Add the new manager to the current module
575558 added = semanal_api .add_symbol_table_node (
576559 # We'll use `new_manager_info.name` instead of `manager_class_name` here
@@ -582,6 +565,26 @@ def create_new_manager_class_from_as_manager_method(ctx: DynamicClassDefContext)
582565 assert added
583566
584567
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 )])
586+
587+
585588def reparametrize_any_manager_hook (ctx : ClassDefContext ) -> None :
586589 """
587590 Add implicit generics to manager classes that are defined without generic.
0 commit comments