Skip to content

Commit c23696a

Browse files
committed
Special case AST conversion for generic aliases
Special case name replacement to render correct strings
1 parent a942431 commit c23696a

1 file changed

Lines changed: 66 additions & 0 deletions

File tree

‎Lib/annotationlib.py‎

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import keyword
77
import sys
88
import types
9+
lazy import typing
910

1011
__all__ = [
1112
"Format",
@@ -410,6 +411,48 @@ def __convert_to_ast(self, other):
410411
elts.append(new_elt)
411412
ast_class = {list: ast.List, tuple: ast.Tuple, set: ast.Set}[type(other)]
412413
return ast_class(elts), extra_names
414+
elif type(other) is types.GenericAlias or _is_annotated_alias(other):
415+
if _is_annotated_alias(other):
416+
annotated_alias = True
417+
origin = typing.get_origin(other)
418+
args = typing.get_args(other)
419+
else:
420+
annotated_alias = False
421+
origin = other.__origin__
422+
args = other.__args__
423+
424+
extra_names = {}
425+
elts = []
426+
427+
origin_ast, origin_names = self.__convert_to_ast(origin)
428+
if origin_names is not None:
429+
extra_names |= origin_names
430+
431+
for elt in args:
432+
new_elt, new_extra_names = self.__convert_to_ast(elt)
433+
if new_extra_names is not None:
434+
extra_names |= new_extra_names
435+
elts.append(new_elt)
436+
437+
if len(elts) == 1:
438+
elts = elts[0]
439+
else:
440+
elts = ast.Tuple(elts=elts)
441+
442+
if annotated_alias:
443+
new_ast = ast.Subscript(
444+
value=origin_ast,
445+
slice=elts,
446+
)
447+
else:
448+
# Generic Alias is not guaranteed to be from subscript
449+
alias_ast, alias_names = self.__convert_to_ast(types.GenericAlias)
450+
extra_names |= alias_names
451+
new_ast = ast.Call(
452+
func=alias_ast,
453+
args=[origin_ast, elts],
454+
)
455+
return new_ast, extra_names
413456
else:
414457
name = self.__stringifier_dict__.create_unique_name()
415458
return ast.Name(id=name), {name: other}
@@ -1191,7 +1234,30 @@ class _ExtraNameFixer(ast.NodeTransformer):
11911234
def __init__(self, extra_names):
11921235
self.extra_names = extra_names
11931236

1237+
def visit_Call(self, node: ast.Call):
1238+
# Convert calls to `GenericAlias` to their string representation
1239+
if (
1240+
isinstance((func := node.func), ast.Name)
1241+
and self.extra_names.get(func.id) is types.GenericAlias
1242+
):
1243+
new_node = ast.Subscript(
1244+
value=node.args[0],
1245+
slice=node.args[1],
1246+
)
1247+
self.generic_visit(new_node)
1248+
return new_node
1249+
1250+
self.generic_visit(node)
1251+
return node
1252+
11941253
def visit_Name(self, node: ast.Name):
11951254
if (new_name := self.extra_names.get(node.id, _sentinel)) is not _sentinel:
11961255
node = ast.Name(id=type_repr(new_name))
11971256
return node
1257+
1258+
1259+
def _is_annotated_alias(obj):
1260+
return (
1261+
(typing := sys.modules.get("typing"))
1262+
and typing.get_origin(obj) is typing.Annotated
1263+
)

0 commit comments

Comments
 (0)