11import ast
22
3+ from python_minifier .rename .mapper import add_parent
4+
5+
36class NodeVisitor (object ):
47
58 def visit (self , node ):
@@ -35,6 +38,53 @@ def visit_Constant(self, node):
3538 visitor = getattr (self , method , self .generic_visit )
3639 return visitor (node )
3740
41+ def is_node (self , node , types ):
42+ """
43+ Is a node one of the specified node types
44+
45+ A node type may be an actual ast class, or a string naming one.
46+ types is a single node type or an iterable of many.
47+
48+ If a node_type specified a specific Constant type (Str, Bytes, Num etc),
49+ returns true for Constant nodes of the correct type.
50+
51+ :type node: ast.AST
52+ :param types:
53+ :rtype: bool
54+ """
55+
56+
57+ if not isinstance (types , tuple ):
58+ types = types ,
59+
60+ actual_types = []
61+ for type in types :
62+ if isinstance (type , str ):
63+ node_type = getattr (ast , type , None )
64+ if node_type is not None :
65+ actual_types .append (node_type )
66+ else :
67+ actual_types .append (type )
68+
69+ if isinstance (node , tuple (actual_types )):
70+ return True
71+
72+ if hasattr (ast , 'Constant' ) and isinstance (node , ast .Constant ):
73+ if node .value in [None , True , False ]:
74+ return ast .NameConstant in types
75+ elif isinstance (node .value , (int , float , complex )):
76+ return ast .Num in types
77+ elif isinstance (node .value , str ):
78+ return ast .Str in types
79+ elif isinstance (node .value , bytes ):
80+ return ast .Bytes in types
81+ elif node .value == Ellipsis :
82+ return ast .Ellipsis in types
83+ else :
84+ raise RuntimeError ('Unknown Constant value %r' % type (node .value ))
85+
86+ return False
87+
3888class SuiteTransformer (NodeVisitor ):
3989 """
4090 Transform suites of instructions
@@ -44,17 +94,39 @@ def __call__(self, node):
4494 return self .visit (node )
4595
4696 def visit_ClassDef (self , node ):
97+ node .bases = [self .visit (b ) for b in node .bases ]
98+
4799 node .body = self .suite (node .body , parent = node )
100+ node .decorator_list = [self .visit (d ) for d in node .decorator_list ]
101+
102+ if hasattr (node , 'starargs' ) and node .starargs is not None :
103+ node .starargs = self .visit (node .starargs )
104+
105+ if hasattr (node , 'kwargs' ) and node .kwargs is not None :
106+ node .kwargs = self .visit (node .kwargs )
107+
108+ if hasattr (node , 'keywords' ):
109+ node .keywords = [self .visit (kw ) for kw in node .keywords ]
110+
48111 return node
49112
50113 def visit_FunctionDef (self , node ):
114+ node .args = self .visit (node .args )
51115 node .body = self .suite (node .body , parent = node )
116+ node .decorator_list = [self .visit (d ) for d in node .decorator_list ]
117+
118+ if hasattr (node , 'returns' ) and node .returns is not None :
119+ node .returns = self .visit (node .returns )
120+
52121 return node
53122
54123 def visit_AsyncFunctionDef (self , node ):
55124 return self .visit_FunctionDef (node )
56125
57126 def visit_For (self , node ):
127+ node .target = self .visit (node .target )
128+ node .iter = self .visit (node .iter )
129+
58130 node .body = self .suite (node .body , parent = node )
59131
60132 if node .orelse :
@@ -63,15 +135,13 @@ def visit_For(self, node):
63135 return node
64136
65137 def visit_AsyncFor (self , node ):
66- node .body = self .suite (node .body , parent = node )
67-
68- if node .orelse :
69- node .orelse = self .suite (node .orelse , parent = node )
70-
71- return node
138+ return self .visit_For (node )
72139
73140 def visit_If (self , node ):
141+ node .test = self .visit (node .test )
142+
74143 node .body = self .suite (node .body , parent = node )
144+
75145 if node .orelse :
76146 node .orelse = self .suite (node .orelse , parent = node )
77147
@@ -80,6 +150,8 @@ def visit_If(self, node):
80150 def visit_Try (self , node ):
81151 node .body = self .suite (node .body , parent = node )
82152
153+ node .handlers = [self .visit (h ) for h in node .handlers ]
154+
83155 if node .orelse :
84156 node .orelse = self .suite (node .orelse , parent = node )
85157
@@ -89,6 +161,8 @@ def visit_Try(self, node):
89161 return node
90162
91163 def visit_While (self , node ):
164+ node .test = self .visit (node .test )
165+
92166 node .body = self .suite (node .body , parent = node )
93167
94168 if node .orelse :
@@ -97,12 +171,20 @@ def visit_While(self, node):
97171 return node
98172
99173 def visit_With (self , node ):
174+
175+ if hasattr (node , 'items' ):
176+ node .items = [self .visit (i ) for i in node .items ]
177+ else :
178+ if node .context_expr :
179+ node .context_expr = self .visit (node .context_expr )
180+ if node .optional_vars :
181+ node .optional_vars = self .visit (node .optional_vars )
182+
100183 node .body = self .suite (node .body , parent = node )
101184 return node
102185
103186 def visit_AsyncWith (self , node ):
104- node .body = self .suite (node .body , parent = node )
105- return node
187+ return self .visit_With (node )
106188
107189 def visit_Module (self , node ):
108190 node .body = self .suite (node .body , parent = node )
@@ -132,3 +214,29 @@ def generic_visit(self, node):
132214 else :
133215 setattr (node , field , new_node )
134216 return node
217+
218+ def add_child (self , child , parent , namespace = None ):
219+
220+ def nearest_function_namespace (node ):
221+ """
222+ Return the namespace node for the nearest function scope.
223+
224+ This could be itself.
225+
226+ :param node: The node to get the function namespace of
227+ :type node: ast.Node
228+ :rtype: ast.Node
229+
230+ """
231+
232+ if isinstance (node , (ast .FunctionDef , ast .Module )):
233+ return node
234+ if hasattr (ast , 'AsyncFunctionDef' ) and isinstance (node , ast .AsyncFunctionDef ):
235+ return node
236+ return nearest_function_namespace (node .parent )
237+
238+ if namespace is None :
239+ namespace = nearest_function_namespace (parent )
240+
241+ add_parent (child , parent = parent , namespace = namespace )
242+ return child
0 commit comments