summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSylvain Thénault <sylvain.thenault@logilab.fr>2013-04-11 12:31:46 +0200
committerSylvain Thénault <sylvain.thenault@logilab.fr>2013-04-11 12:31:46 +0200
commit30b7c4eb775c1b325ec8e588cbbfa76119436547 (patch)
treecaac086569ab1114c0d65966fc9ab7b78a425c6b
parente241e9ef7ab03ef2531f96260d26205a280453c8 (diff)
downloadastroid-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.py76
-rw-r--r--bases.py49
-rw-r--r--test/unittest_builder.py4
-rw-r--r--test/unittest_nodes.py18
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()
diff --git a/bases.py b/bases.py
index b4357ef8..33fa0e89 100644
--- a/bases.py
+++ b/bases.py
@@ -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):