Skip to content

Commit 79f9f4f

Browse files
committed
Heavily refactor apply to create classes for the whole mro
1 parent 5c1620e commit 79f9f4f

2 files changed

Lines changed: 55 additions & 30 deletions

File tree

typemap/type_eval/_apply_generic.py

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ def __post_init__(self):
3535
_compute_mro(self),
3636
)
3737

38+
def alias_type(self):
39+
if self.args:
40+
return self.cls[*self.args.values()]
41+
else:
42+
return self.cls
43+
3844
def __repr__(self):
3945
return f"Boxed<{self.cls} {self.args}>"
4046

@@ -253,39 +259,58 @@ def apply(
253259
cls_boxed = box(cls)
254260
mro_boxed = cls_boxed.mro
255261

256-
annos: dict[str, Any] = {}
257-
dct: dict[str, Any] = {}
258-
259-
# We create it early so we can add it to seen, to handle recursion
260-
ctx.seen[cls] = ret = type(
261-
cls.__name__,
262-
(_eval_typing._EvalProxy,),
263-
{
264-
"__module__": cls.__module__,
265-
"__name__": cls.__name__,
266-
"__origin__": cls,
267-
},
268-
)
269-
270262
# TODO: I think we want to create the whole mro chain...
271263
# before we evaluate the contents?
272264

273-
# Run through the mro
265+
# FIXME: right now we flatten out all the attributes... but should we??
266+
267+
new = {}
268+
269+
# Run through the mro and populate everything
274270
for boxed in reversed(mro_boxed):
275-
lannos, ldct = _get_local_defns(boxed)
276-
annos.update(lannos)
277-
dct.update(ldct)
271+
# We create it early so we can add it to seen, to handle recursion
272+
# XXX: currently we are doing this even for types with no generics...
273+
# that simplifies the flow... - probably keep it this way until
274+
# we stop flattening attributes into every class
275+
name = boxed.cls.__name__
276+
cboxed: Any
277+
cboxed = type(
278+
boxed.cls.__name__,
279+
(_eval_typing._EvalProxy,),
280+
{
281+
"__module__": boxed.cls.__module__,
282+
"__name__": name,
283+
"__origin__": boxed.cls,
284+
"__local_args__": tuple(boxed.args.values()),
285+
},
286+
)
287+
ctx.seen[boxed.alias_type()] = new[boxed] = cboxed
288+
289+
annos: dict[str, Any] = {}
290+
dct: dict[str, Any] = {}
291+
292+
cboxed.__local_annotations__, cboxed.__local_defns__ = _get_local_defns(
293+
boxed
294+
)
295+
for base in reversed(boxed.mro):
296+
cbase = new[base]
297+
annos.update(cbase.__local_annotations__)
298+
dct.update(cbase.__local_defns__) # uh.
278299

279-
for k, v in annos.items():
280-
annos[k] = _eval_typing._eval_types(v, ctx=ctx)
300+
cboxed.__defn_names__ = set(dct)
301+
cboxed.__annotations__ = annos
302+
cboxed.__generalized_mro__ = [new[b] for b in boxed.mro]
281303

282-
for k, v in dct.items():
283-
dct[k] = _eval_typing._eval_types(v, ctx=ctx)
304+
for k, v in dct.items():
305+
setattr(cboxed, k, v)
284306

285-
dct["__annotations__"] = annos
286-
dct["__generalized_mro__"] = mro_boxed
307+
# Run through the mro again and evaluate everything
308+
for cboxed in new.values():
309+
for k, v in cboxed.__annotations__.items():
310+
cboxed.__annotations__[k] = _eval_typing._eval_types(v, ctx=ctx)
287311

288-
for k, v in dct.items():
289-
setattr(ret, k, v)
312+
for k in cboxed.__defn_names__:
313+
v = cboxed.__dict__[k]
314+
setattr(cboxed, k, _eval_typing._eval_types(v, ctx=ctx))
290315

291-
return ret
316+
return new[cls_boxed]

typemap/type_eval/_eval_operators.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,9 @@ def _get_raw_args(tp, base_head, ctx) -> typing.Any:
302302

303303
# Scan the fully-annotated MRO to find the base
304304
elif gen_mro := getattr(evaled, "__generalized_mro__", None):
305-
for box in gen_mro:
306-
if box.cls is base_head:
307-
return tuple(box.args.values())
305+
for anc in gen_mro:
306+
if _typing_inspect.get_head(anc) is base_head:
307+
return anc.__local_args__
308308
return None
309309

310310
else:

0 commit comments

Comments
 (0)