diff options
| author | Sylvain Thénault <sylvain.thenault@logilab.fr> | 2013-04-11 12:31:46 +0200 |
|---|---|---|
| committer | Sylvain Thénault <sylvain.thenault@logilab.fr> | 2013-04-11 12:31:46 +0200 |
| commit | 30b7c4eb775c1b325ec8e588cbbfa76119436547 (patch) | |
| tree | caac086569ab1114c0d65966fc9ab7b78a425c6b | |
| parent | e241e9ef7ab03ef2531f96260d26205a280453c8 (diff) | |
| download | astroid-git-30b7c4eb775c1b325ec8e588cbbfa76119436547.tar.gz | |
as_string/repr_tree code cleanup: enhance the doc a bit + regroup code
- move _repr_tree from bases.py to as_string.py
- rename as_string function to to_code, though public API Node.as_string
is left unchanged for now
--HG--
branch : stable
| -rw-r--r-- | as_string.py | 76 | ||||
| -rw-r--r-- | bases.py | 49 | ||||
| -rw-r--r-- | test/unittest_builder.py | 4 | ||||
| -rw-r--r-- | test/unittest_nodes.py | 18 |
4 files changed, 76 insertions, 71 deletions
diff --git a/as_string.py b/as_string.py index d3478610..c21144e5 100644 --- a/as_string.py +++ b/as_string.py @@ -1,7 +1,5 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# copyright 2003-2010 Sylvain Thenault, all rights reserved. -# contact mailto:thenault@gmail.com # # This file is part of logilab-astng. # @@ -17,29 +15,63 @@ # # You should have received a copy of the GNU Lesser General Public License along # with logilab-astng. If not, see <http://www.gnu.org/licenses/>. -"""This module renders ASTNG nodes to string representation. +"""This module renders ASTNG nodes as string: -It will probably not work on bare _ast trees. +* :func:`to_code` function return equivalent (hopefuly valid) python string + +* :func:`dump` function return an internal representation of nodes found + in the tree, useful for debugging or understanding the tree structure """ -import sys +import sys INDENT = ' ' # 4 spaces ; keep indentation variable -def _import_string(names): - """return a list of (name, asname) formatted as a string""" - _names = [] - for name, asname in names: - if asname is not None: - _names.append('%s as %s' % (name, asname)) +def dump(node, ids=False): + """print a nice astng tree representation. + + :param ids: if true, we also print the ids (usefull for debugging) + """ + result = [] + _repr_tree(node, result, ids=ids) + return "\n".join(result) + +def _repr_tree(node, result, indent='', _done=None, ids=False): + """built a tree representation of a node as a list of lines""" + if _done is None: + _done = set() + if not hasattr(node, '_astng_fields'): # not a astng node + return + if node in _done: + result.append( indent + 'loop in tree: %s' % node ) + return + _done.add(node) + node_str = str(node) + if ids: + node_str += ' . \t%x' % id(node) + result.append( indent + node_str ) + indent += INDENT + for field in node._astng_fields: + value = getattr(node, field) + if isinstance(value, (list, tuple) ): + result.append( indent + field + " = [" ) + for child in value: + if isinstance(child, (list, tuple) ): + # special case for Dict # FIXME + _repr_tree(child[0], result, indent, _done, ids) + _repr_tree(child[1], result, indent, _done, ids) + result.append(indent + ',') + else: + _repr_tree(child, result, indent, _done, ids) + result.append( indent + "]" ) else: - _names.append(name) - return ', '.join(_names) + result.append( indent + field + " = " ) + _repr_tree(value, result, indent, _done, ids) class AsStringVisitor(object): - """Visitor to render an ASTNG node as string """ + """Visitor to render an ASTNG node as a valid python code string""" def __call__(self, node): """Makes this visitor behave as a simple function""" @@ -423,9 +455,21 @@ class AsStringVisitor3k(AsStringVisitor): """return Starred node as string""" return "*" + node.value.accept(self) + +def _import_string(names): + """return a list of (name, asname) formatted as a string""" + _names = [] + for name, asname in names: + if asname is not None: + _names.append('%s as %s' % (name, asname)) + else: + _names.append(name) + return ', '.join(_names) + + if sys.version_info >= (3, 0): AsStringVisitor = AsStringVisitor3k # this visitor is stateless, thus it can be reused -as_string = AsStringVisitor() +to_code = AsStringVisitor() @@ -26,7 +26,6 @@ from contextlib import contextmanager from logilab.astng.exceptions import (InferenceError, ASTNGError, NotFoundError, UnresolvableName) -from logilab.astng.as_string import as_string if sys.version_info >= (3, 0): @@ -34,6 +33,7 @@ if sys.version_info >= (3, 0): else: BUILTINS = '__builtin__' + class Proxy(object): """a simple proxy object""" @@ -566,15 +566,12 @@ class NodeNG(object): return False def as_string(self): - return as_string(self) + from logilab.astng.as_string import to_code + return to_code(self) def repr_tree(self, ids=False): - """print a nice astng tree representation. - - :param ids: if true, we also print the ids (usefull for debugging)""" - result = [] - _repr_tree(self, result, ids=ids) - return "\n".join(result) + from logilab.astng.as_string import dump + return dump(self) class Statement(NodeNG): @@ -596,39 +593,3 @@ class Statement(NodeNG): index = stmts.index(self) if index >= 1: return stmts[index -1] - -INDENT = " " - -def _repr_tree(node, result, indent='', _done=None, ids=False): - """built a tree representation of a node as a list of lines""" - if _done is None: - _done = set() - if not hasattr(node, '_astng_fields'): # not a astng node - return - if node in _done: - result.append( indent + 'loop in tree: %s' % node ) - return - _done.add(node) - node_str = str(node) - if ids: - node_str += ' . \t%x' % id(node) - result.append( indent + node_str ) - indent += INDENT - for field in node._astng_fields: - value = getattr(node, field) - if isinstance(value, (list, tuple) ): - result.append( indent + field + " = [" ) - for child in value: - if isinstance(child, (list, tuple) ): - # special case for Dict # FIXME - _repr_tree(child[0], result, indent, _done, ids) - _repr_tree(child[1], result, indent, _done, ids) - result.append(indent + ',') - else: - _repr_tree(child, result, indent, _done, ids) - result.append( indent + "]" ) - else: - result.append( indent + field + " = " ) - _repr_tree(value, result, indent, _done, ids) - - diff --git a/test/unittest_builder.py b/test/unittest_builder.py index 6e853d8a..e88376b7 100644 --- a/test/unittest_builder.py +++ b/test/unittest_builder.py @@ -338,13 +338,13 @@ class BuilderTC(TestCase): self.assertEqual(len(infered), 1) infered = infered[0] self.assertEqual(infered.name, 'object') - as_string(infered) + infered.as_string() # no crash test infered = list(builtin_astng.igetattr('type')) self.assertEqual(len(infered), 1) infered = infered[0] self.assertEqual(infered.name, 'type') - as_string(infered) + infered.as_string() # no crash test def test_package_name(self): """test base properties and method of a astng module""" diff --git a/test/unittest_nodes.py b/test/unittest_nodes.py index 818119c0..a47c55f1 100644 --- a/test/unittest_nodes.py +++ b/test/unittest_nodes.py @@ -37,19 +37,19 @@ class AsString(testlib.TestCase): def test_varargs_kwargs_as_string(self): ast = abuilder.string_build( 'raise_string(*args, **kwargs)').body[0] - self.assertEqual(as_string(ast), 'raise_string(*args, **kwargs)') + self.assertEqual(ast.as_string(), 'raise_string(*args, **kwargs)') def test_module_as_string(self): """check as_string on a whole module prepared to be returned identically """ data = open(join(DATA, 'module.py')).read() - self.assertMultiLineEqual(as_string(MODULE), data) + self.assertMultiLineEqual(MODULE.as_string(), data) def test_module2_as_string(self): """check as_string on a whole module prepared to be returned identically """ data = open(join(DATA, 'module2.py')).read() - self.assertMultiLineEqual(as_string(MODULE2), data) + self.assertMultiLineEqual(MODULE2.as_string(), data) @testlib.require_version('2.7') def test_2_7_as_string(self): @@ -58,7 +58,7 @@ class AsString(testlib.TestCase): b = {v: k for (k, v) in enumerate('string')} cdd = {k for k in b}\n\n''' ast = abuilder.string_build(code) - self.assertMultiLineEqual(as_string(ast), code) + self.assertMultiLineEqual(ast.as_string(), code) @testlib.require_version('3.0') def test_3k_as_string(self): @@ -82,7 +82,7 @@ class Language(metaclass=Natural): """natural language""" ''' ast = abuilder.string_build(code) - self.assertEqual(as_string(ast), code) + self.assertEqual(ast.as_string(), code) class _NodeTC(testlib.TestCase): @@ -255,11 +255,11 @@ class ImportNodeTC(testlib.TestCase): def test_as_string(self): ast = MODULE['modutils'] - self.assertEqual(as_string(ast), "from logilab.common import modutils") + self.assertEqual(ast.as_string(), "from logilab.common import modutils") ast = MODULE['spawn'] - self.assertEqual(as_string(ast), "from logilab.common.shellutils import Execute as spawn") + self.assertEqual(ast.as_string(), "from logilab.common.shellutils import Execute as spawn") ast = MODULE['os'] - self.assertEqual(as_string(ast), "import os.path") + self.assertEqual(ast.as_string(), "import os.path") code = """from . import here from .. import door from .store import bread @@ -307,7 +307,7 @@ except PickleError: class CmpNodeTC(testlib.TestCase): def test_as_string(self): ast = abuilder.string_build("a == 2").body[0] - self.assertEqual(as_string(ast), "a == 2") + self.assertEqual(ast.as_string(), "a == 2") class ConstNodeTC(testlib.TestCase): |
