Statistics
| Revision:

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()