Skip to content

Commit 5c1620e

Browse files
committed
Refactor apply some - factor out some code
1 parent 11f57e3 commit 5c1620e

1 file changed

Lines changed: 78 additions & 67 deletions

File tree

typemap/type_eval/_apply_generic.py

Lines changed: 78 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
175250
def 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

Comments
 (0)