@@ -172,6 +172,81 @@ def make_func(
172172 return new_func
173173
174174
175+ def _get_local_defns (boxed : Boxed ) -> tuple [dict [str , Any ], dict [str , Any ]]:
176+ annos : dict [str , Any ] = {}
177+ dct : dict [str , Any ] = {}
178+
179+ if af := getattr (boxed .cls , "__annotate__" , None ):
180+ # Class has annotations, let's resolve generic arguments
181+
182+ args = tuple (
183+ types .CellType (
184+ boxed .cls .__dict__
185+ if name == "__classdict__"
186+ else boxed .str_args [name ]
187+ )
188+ for name in af .__code__ .co_freevars
189+ )
190+
191+ ff = types .FunctionType (
192+ af .__code__ , af .__globals__ , af .__name__ , None , args
193+ )
194+ rr = ff (annotationlib .Format .VALUE )
195+
196+ if rr :
197+ for k , v in rr .items ():
198+ if isinstance (v , str ):
199+ # Handle cases where annotation is explicitly a string,
200+ # e.g.:
201+ #
202+ # class Foo[X]:
203+ # x: "Foo[X | None]"
204+
205+ annos [k ] = eval (v , af .__globals__ , boxed .str_args )
206+ else :
207+ annos [k ] = v
208+ elif af := getattr (boxed .cls , "__annotations__" , None ):
209+ annos .update (af )
210+
211+ for name , orig in boxed .cls .__dict__ .items ():
212+ if name in typing .EXCLUDED_ATTRIBUTES : # type: ignore[attr-defined]
213+ continue
214+
215+ stuff = inspect .unwrap (orig )
216+
217+ if isinstance (stuff , types .FunctionType ):
218+ if af := getattr (stuff , "__annotate__" , None ):
219+ params = dict (
220+ zip (
221+ map (str , stuff .__type_params__ ),
222+ stuff .__type_params__ ,
223+ strict = True ,
224+ )
225+ )
226+
227+ args = tuple (
228+ types .CellType (
229+ boxed .cls .__dict__
230+ if name == "__classdict__"
231+ else params [name ]
232+ if name in params
233+ else boxed .str_args [name ]
234+ )
235+ for name in af .__code__ .co_freevars
236+ )
237+
238+ ff = types .FunctionType (
239+ af .__code__ , af .__globals__ , af .__name__ , None , args
240+ )
241+ rr = ff (annotationlib .Format .VALUE )
242+
243+ dct [name ] = make_func (orig , rr )
244+ elif af := getattr (stuff , "__annotations__" , None ):
245+ dct [name ] = stuff
246+
247+ return annos , dct
248+
249+
175250def apply (
176251 cls : type [Any ], ctx : _eval_typing .EvalContext
177252) -> type [_eval_typing ._EvalProxy ]:
@@ -197,73 +272,9 @@ def apply(
197272
198273 # Run through the mro
199274 for boxed in reversed (mro_boxed ):
200- if af := getattr (boxed .cls , "__annotate__" , None ):
201- # Class has annotations, let's resolve generic arguments
202-
203- args = tuple (
204- types .CellType (
205- boxed .cls .__dict__
206- if name == "__classdict__"
207- else boxed .str_args [name ]
208- )
209- for name in af .__code__ .co_freevars
210- )
211-
212- ff = types .FunctionType (
213- af .__code__ , af .__globals__ , af .__name__ , None , args
214- )
215- rr = ff (annotationlib .Format .VALUE )
216-
217- if rr :
218- for k , v in rr .items ():
219- if isinstance (v , str ):
220- # Handle cases where annotation is explicitly a string,
221- # e.g.:
222- #
223- # class Foo[X]:
224- # x: "Foo[X | None]"
225-
226- annos [k ] = eval (v , af .__globals__ , boxed .str_args )
227- else :
228- annos [k ] = v
229- elif af := getattr (boxed .cls , "__annotations__" , None ):
230- annos .update (af )
231-
232- for name , orig in boxed .cls .__dict__ .items ():
233- if name in typing .EXCLUDED_ATTRIBUTES : # type: ignore[attr-defined]
234- continue
235-
236- stuff = inspect .unwrap (orig )
237-
238- if isinstance (stuff , types .FunctionType ):
239- if af := getattr (stuff , "__annotate__" , None ):
240- params = dict (
241- zip (
242- map (str , stuff .__type_params__ ),
243- stuff .__type_params__ ,
244- strict = True ,
245- )
246- )
247-
248- args = tuple (
249- types .CellType (
250- boxed .cls .__dict__
251- if name == "__classdict__"
252- else params [name ]
253- if name in params
254- else boxed .str_args [name ]
255- )
256- for name in af .__code__ .co_freevars
257- )
258-
259- ff = types .FunctionType (
260- af .__code__ , af .__globals__ , af .__name__ , None , args
261- )
262- rr = ff (annotationlib .Format .VALUE )
263-
264- dct [name ] = make_func (orig , rr )
265- elif af := getattr (stuff , "__annotations__" , None ):
266- dct [name ] = stuff
275+ lannos , ldct = _get_local_defns (boxed )
276+ annos .update (lannos )
277+ dct .update (ldct )
267278
268279 for k , v in annos .items ():
269280 annos [k ] = _eval_typing ._eval_types (v , ctx = ctx )
0 commit comments