gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / astroid / as_string.py @ 745
History | View | Annotate | Download (20.3 KB)
1 |
# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
|
---|---|
2 |
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
|
3 |
#
|
4 |
# This file is part of astroid.
|
5 |
#
|
6 |
# astroid is free software: you can redistribute it and/or modify it
|
7 |
# under the terms of the GNU Lesser General Public License as published by the
|
8 |
# Free Software Foundation, either version 2.1 of the License, or (at your
|
9 |
# option) any later version.
|
10 |
#
|
11 |
# astroid is distributed in the hope that it will be useful, but
|
12 |
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13 |
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
14 |
# for more details.
|
15 |
#
|
16 |
# You should have received a copy of the GNU Lesser General Public License along
|
17 |
# with astroid. If not, see <http://www.gnu.org/licenses/>.
|
18 |
"""This module renders Astroid nodes as string:
|
19 |
|
20 |
* :func:`to_code` function return equivalent (hopefuly valid) python string
|
21 |
|
22 |
* :func:`dump` function return an internal representation of nodes found
|
23 |
in the tree, useful for debugging or understanding the tree structure
|
24 |
"""
|
25 |
import sys |
26 |
|
27 |
import six |
28 |
|
29 |
INDENT = ' ' # 4 spaces ; keep indentation variable |
30 |
|
31 |
|
32 |
def dump(node, ids=False): |
33 |
"""print a nice astroid tree representation.
|
34 |
|
35 |
:param ids: if true, we also print the ids (usefull for debugging)
|
36 |
"""
|
37 |
result = [] |
38 |
_repr_tree(node, result, ids=ids) |
39 |
return "\n".join(result) |
40 |
|
41 |
def _repr_tree(node, result, indent='', _done=None, ids=False): |
42 |
"""built a tree representation of a node as a list of lines"""
|
43 |
if _done is None: |
44 |
_done = set()
|
45 |
if not hasattr(node, '_astroid_fields'): # not a astroid node |
46 |
return
|
47 |
if node in _done: |
48 |
result.append(indent + 'loop in tree: %s' % node)
|
49 |
return
|
50 |
_done.add(node) |
51 |
node_str = str(node)
|
52 |
if ids:
|
53 |
node_str += ' . \t%x' % id(node) |
54 |
result.append(indent + node_str) |
55 |
indent += INDENT |
56 |
for field in node._astroid_fields: |
57 |
value = getattr(node, field)
|
58 |
if isinstance(value, (list, tuple)): |
59 |
result.append(indent + field + " = [")
|
60 |
for child in value: |
61 |
if isinstance(child, (list, tuple)): |
62 |
# special case for Dict # FIXME
|
63 |
_repr_tree(child[0], result, indent, _done, ids)
|
64 |
_repr_tree(child[1], result, indent, _done, ids)
|
65 |
result.append(indent + ',')
|
66 |
else:
|
67 |
_repr_tree(child, result, indent, _done, ids) |
68 |
result.append(indent + "]")
|
69 |
else:
|
70 |
result.append(indent + field + " = ")
|
71 |
_repr_tree(value, result, indent, _done, ids) |
72 |
|
73 |
|
74 |
class AsStringVisitor(object): |
75 |
"""Visitor to render an Astroid node as a valid python code string"""
|
76 |
|
77 |
def __call__(self, node): |
78 |
"""Makes this visitor behave as a simple function"""
|
79 |
return node.accept(self) |
80 |
|
81 |
def _stmt_list(self, stmts): |
82 |
"""return a list of nodes to string"""
|
83 |
stmts = '\n'.join([nstr for nstr in [n.accept(self) for n in stmts] if nstr]) |
84 |
return INDENT + stmts.replace('\n', '\n'+INDENT) |
85 |
|
86 |
|
87 |
## visit_<node> methods ###########################################
|
88 |
|
89 |
def visit_arguments(self, node): |
90 |
"""return an astroid.Function node as string"""
|
91 |
return node.format_args()
|
92 |
|
93 |
def visit_assignattr(self, node): |
94 |
"""return an astroid.AssAttr node as string"""
|
95 |
return self.visit_attribute(node) |
96 |
|
97 |
def visit_assert(self, node): |
98 |
"""return an astroid.Assert node as string"""
|
99 |
if node.fail:
|
100 |
return 'assert %s, %s' % (node.test.accept(self), |
101 |
node.fail.accept(self))
|
102 |
return 'assert %s' % node.test.accept(self) |
103 |
|
104 |
def visit_assignname(self, node): |
105 |
"""return an astroid.AssName node as string"""
|
106 |
return node.name
|
107 |
|
108 |
def visit_assign(self, node): |
109 |
"""return an astroid.Assign node as string"""
|
110 |
lhs = ' = '.join([n.accept(self) for n in node.targets]) |
111 |
return '%s = %s' % (lhs, node.value.accept(self)) |
112 |
|
113 |
def visit_augassign(self, node): |
114 |
"""return an astroid.AugAssign node as string"""
|
115 |
return '%s %s %s' % (node.target.accept(self), node.op, node.value.accept(self)) |
116 |
|
117 |
def visit_repr(self, node): |
118 |
"""return an astroid.Repr node as string"""
|
119 |
return '`%s`' % node.value.accept(self) |
120 |
|
121 |
def visit_binop(self, node): |
122 |
"""return an astroid.BinOp node as string"""
|
123 |
return '(%s) %s (%s)' % (node.left.accept(self), node.op, node.right.accept(self)) |
124 |
|
125 |
def visit_boolop(self, node): |
126 |
"""return an astroid.BoolOp node as string"""
|
127 |
return (' %s ' % node.op).join(['(%s)' % n.accept(self) |
128 |
for n in node.values]) |
129 |
|
130 |
def visit_break(self, node): |
131 |
"""return an astroid.Break node as string"""
|
132 |
return 'break' |
133 |
|
134 |
def visit_call(self, node): |
135 |
"""return an astroid.Call node as string"""
|
136 |
expr_str = node.func.accept(self)
|
137 |
args = [arg.accept(self) for arg in node.args] |
138 |
if node.keywords:
|
139 |
keywords = [kwarg.accept(self) for kwarg in node.keywords] |
140 |
else:
|
141 |
keywords = [] |
142 |
|
143 |
args.extend(keywords) |
144 |
return '%s(%s)' % (expr_str, ', '.join(args)) |
145 |
|
146 |
def visit_classdef(self, node): |
147 |
"""return an astroid.ClassDef node as string"""
|
148 |
decorate = node.decorators and node.decorators.accept(self) or '' |
149 |
bases = ', '.join([n.accept(self) for n in node.bases]) |
150 |
if sys.version_info[0] == 2: |
151 |
bases = bases and '(%s)' % bases or '' |
152 |
else:
|
153 |
metaclass = node.metaclass() |
154 |
if metaclass and not node.has_metaclass_hack(): |
155 |
if bases:
|
156 |
bases = '(%s, metaclass=%s)' % (bases, metaclass.name)
|
157 |
else:
|
158 |
bases = '(metaclass=%s)' % metaclass.name
|
159 |
else:
|
160 |
bases = bases and '(%s)' % bases or '' |
161 |
docs = node.doc and '\n%s"""%s"""' % (INDENT, node.doc) or '' |
162 |
return '\n\n%sclass %s%s:%s\n%s\n' % (decorate, node.name, bases, docs, |
163 |
self._stmt_list(node.body))
|
164 |
|
165 |
def visit_compare(self, node): |
166 |
"""return an astroid.Compare node as string"""
|
167 |
rhs_str = ' '.join(['%s %s' % (op, expr.accept(self)) |
168 |
for op, expr in node.ops]) |
169 |
return '%s %s' % (node.left.accept(self), rhs_str) |
170 |
|
171 |
def visit_comprehension(self, node): |
172 |
"""return an astroid.Comprehension node as string"""
|
173 |
ifs = ''.join([' if %s' % n.accept(self) for n in node.ifs]) |
174 |
return 'for %s in %s%s' % (node.target.accept(self), |
175 |
node.iter.accept(self), ifs)
|
176 |
|
177 |
def visit_const(self, node): |
178 |
"""return an astroid.Const node as string"""
|
179 |
return repr(node.value) |
180 |
|
181 |
def visit_continue(self, node): |
182 |
"""return an astroid.Continue node as string"""
|
183 |
return 'continue' |
184 |
|
185 |
def visit_delete(self, node): # XXX check if correct |
186 |
"""return an astroid.Delete node as string"""
|
187 |
return 'del %s' % ', '.join([child.accept(self) |
188 |
for child in node.targets]) |
189 |
|
190 |
def visit_delattr(self, node): |
191 |
"""return an astroid.DelAttr node as string"""
|
192 |
return self.visit_attribute(node) |
193 |
|
194 |
def visit_delname(self, node): |
195 |
"""return an astroid.DelName node as string"""
|
196 |
return node.name
|
197 |
|
198 |
def visit_decorators(self, node): |
199 |
"""return an astroid.Decorators node as string"""
|
200 |
return '@%s\n' % '\n@'.join([item.accept(self) for item in node.nodes]) |
201 |
|
202 |
def visit_dict(self, node): |
203 |
"""return an astroid.Dict node as string"""
|
204 |
return '{%s}' % ', '.join(self._visit_dict(node)) |
205 |
|
206 |
def _visit_dict(self, node): |
207 |
for key, value in node.items: |
208 |
key = key.accept(self)
|
209 |
value = value.accept(self)
|
210 |
if key == '**': |
211 |
# It can only be a DictUnpack node.
|
212 |
yield key + value
|
213 |
else:
|
214 |
yield '%s: %s' % (key, value) |
215 |
|
216 |
def visit_dictunpack(self, node): |
217 |
return '**' |
218 |
|
219 |
def visit_dictcomp(self, node): |
220 |
"""return an astroid.DictComp node as string"""
|
221 |
return '{%s: %s %s}' % (node.key.accept(self), node.value.accept(self), |
222 |
' '.join([n.accept(self) for n in node.generators])) |
223 |
|
224 |
def visit_expr(self, node): |
225 |
"""return an astroid.Discard node as string"""
|
226 |
return node.value.accept(self) |
227 |
|
228 |
def visit_emptynode(self, node): |
229 |
"""dummy method for visiting an Empty node"""
|
230 |
return '' |
231 |
|
232 |
def visit_excepthandler(self, node): |
233 |
if node.type:
|
234 |
if node.name:
|
235 |
excs = 'except %s, %s' % (node.type.accept(self), |
236 |
node.name.accept(self))
|
237 |
else:
|
238 |
excs = 'except %s' % node.type.accept(self) |
239 |
else:
|
240 |
excs = 'except'
|
241 |
return '%s:\n%s' % (excs, self._stmt_list(node.body)) |
242 |
|
243 |
def visit_ellipsis(self, node): |
244 |
"""return an astroid.Ellipsis node as string"""
|
245 |
return '...' |
246 |
|
247 |
def visit_empty(self, node): |
248 |
"""return an Empty node as string"""
|
249 |
return '' |
250 |
|
251 |
def visit_exec(self, node): |
252 |
"""return an astroid.Exec node as string"""
|
253 |
if node.locals:
|
254 |
return 'exec %s in %s, %s' % (node.expr.accept(self), |
255 |
node.locals.accept(self),
|
256 |
node.globals.accept(self))
|
257 |
if node.globals:
|
258 |
return 'exec %s in %s' % (node.expr.accept(self), |
259 |
node.globals.accept(self))
|
260 |
return 'exec %s' % node.expr.accept(self) |
261 |
|
262 |
def visit_extslice(self, node): |
263 |
"""return an astroid.ExtSlice node as string"""
|
264 |
return ','.join([dim.accept(self) for dim in node.dims]) |
265 |
|
266 |
def visit_for(self, node): |
267 |
"""return an astroid.For node as string"""
|
268 |
fors = 'for %s in %s:\n%s' % (node.target.accept(self), |
269 |
node.iter.accept(self),
|
270 |
self._stmt_list(node.body))
|
271 |
if node.orelse:
|
272 |
fors = '%s\nelse:\n%s' % (fors, self._stmt_list(node.orelse)) |
273 |
return fors
|
274 |
|
275 |
def visit_importfrom(self, node): |
276 |
"""return an astroid.ImportFrom node as string"""
|
277 |
return 'from %s import %s' % ('.' * (node.level or 0) + node.modname, |
278 |
_import_string(node.names)) |
279 |
|
280 |
def visit_functiondef(self, node): |
281 |
"""return an astroid.Function node as string"""
|
282 |
decorate = node.decorators and node.decorators.accept(self) or '' |
283 |
docs = node.doc and '\n%s"""%s"""' % (INDENT, node.doc) or '' |
284 |
return_annotation = ''
|
285 |
if six.PY3 and node.returns: |
286 |
return_annotation = '->' + node.returns.as_string()
|
287 |
trailer = return_annotation + ":"
|
288 |
else:
|
289 |
trailer = ":"
|
290 |
def_format = "\n%sdef %s(%s)%s%s\n%s"
|
291 |
return def_format % (decorate, node.name,
|
292 |
node.args.accept(self),
|
293 |
trailer, docs, |
294 |
self._stmt_list(node.body))
|
295 |
|
296 |
def visit_generatorexp(self, node): |
297 |
"""return an astroid.GeneratorExp node as string"""
|
298 |
return '(%s %s)' % (node.elt.accept(self), |
299 |
' '.join([n.accept(self) for n in node.generators])) |
300 |
|
301 |
def visit_attribute(self, node): |
302 |
"""return an astroid.Getattr node as string"""
|
303 |
return '%s.%s' % (node.expr.accept(self), node.attrname) |
304 |
|
305 |
def visit_global(self, node): |
306 |
"""return an astroid.Global node as string"""
|
307 |
return 'global %s' % ', '.join(node.names) |
308 |
|
309 |
def visit_if(self, node): |
310 |
"""return an astroid.If node as string"""
|
311 |
ifs = ['if %s:\n%s' % (node.test.accept(self), self._stmt_list(node.body))] |
312 |
if node.orelse:# XXX use elif ??? |
313 |
ifs.append('else:\n%s' % self._stmt_list(node.orelse)) |
314 |
return '\n'.join(ifs) |
315 |
|
316 |
def visit_ifexp(self, node): |
317 |
"""return an astroid.IfExp node as string"""
|
318 |
return '%s if %s else %s' % (node.body.accept(self), |
319 |
node.test.accept(self),
|
320 |
node.orelse.accept(self))
|
321 |
|
322 |
def visit_import(self, node): |
323 |
"""return an astroid.Import node as string"""
|
324 |
return 'import %s' % _import_string(node.names) |
325 |
|
326 |
def visit_keyword(self, node): |
327 |
"""return an astroid.Keyword node as string"""
|
328 |
if node.arg is None: |
329 |
return '**%s' % node.value.accept(self) |
330 |
return '%s=%s' % (node.arg, node.value.accept(self)) |
331 |
|
332 |
def visit_lambda(self, node): |
333 |
"""return an astroid.Lambda node as string"""
|
334 |
return 'lambda %s: %s' % (node.args.accept(self), |
335 |
node.body.accept(self))
|
336 |
|
337 |
def visit_list(self, node): |
338 |
"""return an astroid.List node as string"""
|
339 |
return '[%s]' % ', '.join([child.accept(self) for child in node.elts]) |
340 |
|
341 |
def visit_listcomp(self, node): |
342 |
"""return an astroid.ListComp node as string"""
|
343 |
return '[%s %s]' % (node.elt.accept(self), |
344 |
' '.join([n.accept(self) for n in node.generators])) |
345 |
|
346 |
def visit_module(self, node): |
347 |
"""return an astroid.Module node as string"""
|
348 |
docs = node.doc and '"""%s"""\n\n' % node.doc or '' |
349 |
return docs + '\n'.join([n.accept(self) for n in node.body]) + '\n\n' |
350 |
|
351 |
def visit_name(self, node): |
352 |
"""return an astroid.Name node as string"""
|
353 |
return node.name
|
354 |
|
355 |
def visit_pass(self, node): |
356 |
"""return an astroid.Pass node as string"""
|
357 |
return 'pass' |
358 |
|
359 |
def visit_print(self, node): |
360 |
"""return an astroid.Print node as string"""
|
361 |
nodes = ', '.join([n.accept(self) for n in node.values]) |
362 |
if not node.nl: |
363 |
nodes = '%s,' % nodes
|
364 |
if node.dest:
|
365 |
return 'print >> %s, %s' % (node.dest.accept(self), nodes) |
366 |
return 'print %s' % nodes |
367 |
|
368 |
def visit_raise(self, node): |
369 |
"""return an astroid.Raise node as string"""
|
370 |
if node.exc:
|
371 |
if node.inst:
|
372 |
if node.tback:
|
373 |
return 'raise %s, %s, %s' % (node.exc.accept(self), |
374 |
node.inst.accept(self),
|
375 |
node.tback.accept(self))
|
376 |
return 'raise %s, %s' % (node.exc.accept(self), |
377 |
node.inst.accept(self))
|
378 |
return 'raise %s' % node.exc.accept(self) |
379 |
return 'raise' |
380 |
|
381 |
def visit_return(self, node): |
382 |
"""return an astroid.Return node as string"""
|
383 |
if node.value:
|
384 |
return 'return %s' % node.value.accept(self) |
385 |
else:
|
386 |
return 'return' |
387 |
|
388 |
def visit_index(self, node): |
389 |
"""return a astroid.Index node as string"""
|
390 |
return node.value.accept(self) |
391 |
|
392 |
def visit_set(self, node): |
393 |
"""return an astroid.Set node as string"""
|
394 |
return '{%s}' % ', '.join([child.accept(self) for child in node.elts]) |
395 |
|
396 |
def visit_setcomp(self, node): |
397 |
"""return an astroid.SetComp node as string"""
|
398 |
return '{%s %s}' % (node.elt.accept(self), |
399 |
' '.join([n.accept(self) for n in node.generators])) |
400 |
|
401 |
def visit_slice(self, node): |
402 |
"""return a astroid.Slice node as string"""
|
403 |
lower = node.lower and node.lower.accept(self) or '' |
404 |
upper = node.upper and node.upper.accept(self) or '' |
405 |
step = node.step and node.step.accept(self) or '' |
406 |
if step:
|
407 |
return '%s:%s:%s' % (lower, upper, step) |
408 |
return '%s:%s' % (lower, upper) |
409 |
|
410 |
def visit_subscript(self, node): |
411 |
"""return an astroid.Subscript node as string"""
|
412 |
return '%s[%s]' % (node.value.accept(self), node.slice.accept(self)) |
413 |
|
414 |
def visit_tryexcept(self, node): |
415 |
"""return an astroid.TryExcept node as string"""
|
416 |
trys = ['try:\n%s' % self._stmt_list(node.body)] |
417 |
for handler in node.handlers: |
418 |
trys.append(handler.accept(self))
|
419 |
if node.orelse:
|
420 |
trys.append('else:\n%s' % self._stmt_list(node.orelse)) |
421 |
return '\n'.join(trys) |
422 |
|
423 |
def visit_tryfinally(self, node): |
424 |
"""return an astroid.TryFinally node as string"""
|
425 |
return 'try:\n%s\nfinally:\n%s' % (self._stmt_list(node.body), |
426 |
self._stmt_list(node.finalbody))
|
427 |
|
428 |
def visit_tuple(self, node): |
429 |
"""return an astroid.Tuple node as string"""
|
430 |
if len(node.elts) == 1: |
431 |
return '(%s, )' % node.elts[0].accept(self) |
432 |
return '(%s)' % ', '.join([child.accept(self) for child in node.elts]) |
433 |
|
434 |
def visit_unaryop(self, node): |
435 |
"""return an astroid.UnaryOp node as string"""
|
436 |
if node.op == 'not': |
437 |
operator = 'not '
|
438 |
else:
|
439 |
operator = node.op |
440 |
return '%s%s' % (operator, node.operand.accept(self)) |
441 |
|
442 |
def visit_while(self, node): |
443 |
"""return an astroid.While node as string"""
|
444 |
whiles = 'while %s:\n%s' % (node.test.accept(self), |
445 |
self._stmt_list(node.body))
|
446 |
if node.orelse:
|
447 |
whiles = '%s\nelse:\n%s' % (whiles, self._stmt_list(node.orelse)) |
448 |
return whiles
|
449 |
|
450 |
def visit_with(self, node): # 'with' without 'as' is possible |
451 |
"""return an astroid.With node as string"""
|
452 |
items = ', '.join(('(%s)' % expr.accept(self)) + |
453 |
(vars and ' as (%s)' % (vars.accept(self)) or '') |
454 |
for expr, vars in node.items) |
455 |
return 'with %s:\n%s' % (items, self._stmt_list(node.body)) |
456 |
|
457 |
def visit_yield(self, node): |
458 |
"""yield an ast.Yield node as string"""
|
459 |
yi_val = node.value and (" " + node.value.accept(self)) or "" |
460 |
expr = 'yield' + yi_val
|
461 |
if node.parent.is_statement:
|
462 |
return expr
|
463 |
else:
|
464 |
return "(%s)" % (expr,) |
465 |
|
466 |
def visit_starred(self, node): |
467 |
"""return Starred node as string"""
|
468 |
return "*" + node.value.accept(self) |
469 |
|
470 |
|
471 |
# These aren't for real AST nodes, but for inference objects.
|
472 |
|
473 |
def visit_frozenset(self, node): |
474 |
return node.parent.accept(self) |
475 |
|
476 |
def visit_super(self, node): |
477 |
return node.parent.accept(self) |
478 |
|
479 |
def visit_yes(self, node): |
480 |
return "Uninferable" |
481 |
|
482 |
|
483 |
class AsStringVisitor3k(AsStringVisitor): |
484 |
"""AsStringVisitor3k overwrites some AsStringVisitor methods"""
|
485 |
|
486 |
def visit_excepthandler(self, node): |
487 |
if node.type:
|
488 |
if node.name:
|
489 |
excs = 'except %s as %s' % (node.type.accept(self), |
490 |
node.name.accept(self))
|
491 |
else:
|
492 |
excs = 'except %s' % node.type.accept(self) |
493 |
else:
|
494 |
excs = 'except'
|
495 |
return '%s:\n%s' % (excs, self._stmt_list(node.body)) |
496 |
|
497 |
def visit_nonlocal(self, node): |
498 |
"""return an astroid.Nonlocal node as string"""
|
499 |
return 'nonlocal %s' % ', '.join(node.names) |
500 |
|
501 |
def visit_raise(self, node): |
502 |
"""return an astroid.Raise node as string"""
|
503 |
if node.exc:
|
504 |
if node.cause:
|
505 |
return 'raise %s from %s' % (node.exc.accept(self), |
506 |
node.cause.accept(self))
|
507 |
return 'raise %s' % node.exc.accept(self) |
508 |
return 'raise' |
509 |
|
510 |
def visit_yieldfrom(self, node): |
511 |
""" Return an astroid.YieldFrom node as string. """
|
512 |
yi_val = node.value and (" " + node.value.accept(self)) or "" |
513 |
expr = 'yield from' + yi_val
|
514 |
if node.parent.is_statement:
|
515 |
return expr
|
516 |
else:
|
517 |
return "(%s)" % (expr,) |
518 |
|
519 |
def visit_asyncfunctiondef(self, node): |
520 |
function = super(AsStringVisitor3k, self).visit_functiondef(node) |
521 |
return 'async ' + function.strip() |
522 |
|
523 |
def visit_await(self, node): |
524 |
return 'await %s' % node.value.accept(self) |
525 |
|
526 |
def visit_asyncwith(self, node): |
527 |
return 'async %s' % self.visit_with(node) |
528 |
|
529 |
def visit_asyncfor(self, node): |
530 |
return 'async %s' % self.visit_for(node) |
531 |
|
532 |
|
533 |
def _import_string(names): |
534 |
"""return a list of (name, asname) formatted as a string"""
|
535 |
_names = [] |
536 |
for name, asname in names: |
537 |
if asname is not None: |
538 |
_names.append('%s as %s' % (name, asname))
|
539 |
else:
|
540 |
_names.append(name) |
541 |
return ', '.join(_names) |
542 |
|
543 |
|
544 |
if sys.version_info >= (3, 0): |
545 |
AsStringVisitor = AsStringVisitor3k |
546 |
|
547 |
# this visitor is stateless, thus it can be reused
|
548 |
to_code = AsStringVisitor() |