44import inspect
55from functools import lru_cache
66from textwrap import dedent
7- from typing import Union , get_type_hints
8-
9- RECURSIVE_NODES = (ast .If , ast .IfExp , ast .Try , ast .With )
7+ from typing import get_type_hints
108
9+ try :
10+ from ast import unparse # type: ignore
11+ except ImportError :
12+ from astunparse import unparse
1113
12- def node_to_annotation (node ) -> Union [str , object ]:
13- if isinstance (node , ast .AnnAssign ):
14- if isinstance (node .annotation , ast .Name ):
15- return node .annotation .id
16- elif isinstance (node .annotation , (ast .Constant , ast .Str )):
17- return node .annotation .s
18- elif isinstance (node .annotation , ast .Subscript ):
19- value_id = node .annotation .value .id # type: ignore
20- if hasattr (node .annotation .slice , "value" ):
21- value = node .annotation .slice .value # type: ignore
22- else :
23- value = node .annotation .slice
24- return f"{ value_id } [{ node_to_annotation (value )} ]"
25- else :
26- return inspect .Signature .empty
27- elif isinstance (node , ast .Subscript ):
28- return f"{ node .value .id } [{ node_to_annotation (node .slice .value )} ]" # type: ignore
29- elif isinstance (node , ast .Tuple ):
30- annotations = [node_to_annotation (n ) for n in node .elts ]
31- return ", " .join (a for a in annotations if a is not inspect .Signature .empty ) # type: ignore
32- elif isinstance (node , ast .Name ):
33- return node .id
34- return inspect .Signature .empty
14+ RECURSIVE_NODES = (ast .If , ast .IfExp , ast .Try , ast .With )
3515
3616
3717def get_nodes (obj ):
@@ -144,6 +124,11 @@ def pick_target(target):
144124 return isinstance (target , ast .Attribute ) and isinstance (target .value , ast .Name ) and target .value .id == "self"
145125
146126
127+ def unparse_annotation (node ):
128+ code = unparse (node ).rstrip ("\n " )
129+ return code .replace ("(" , "" ).replace (")" , "" )
130+
131+
147132@lru_cache ()
148133def get_instance_attributes (func ):
149134 nodes = get_nodes (func )
@@ -157,7 +142,7 @@ def get_instance_attributes(func):
157142 if isinstance (assignment , ast .AnnAssign ):
158143 if pick_target (assignment .target ):
159144 names = [assignment .target .attr ]
160- annotation = node_to_annotation (assignment )
145+ annotation = unparse_annotation (assignment . annotation )
161146 else :
162147 names = [target .attr for target in assignment .targets if pick_target (target )]
163148
0 commit comments