summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCeridwen <ceridwenv@gmail.com>2016-02-21 16:25:01 -0500
committerCeridwen <ceridwenv@gmail.com>2016-02-21 16:25:01 -0500
commit51bd977f064520f5efe2795e484d2c0728128e08 (patch)
tree236714776386c16d04cb9ea83c0e9148091a2da5
parent54e5ddc279c4281e1612380af67051734ae30064 (diff)
downloadastroid-git-51bd977f064520f5efe2795e484d2c0728128e08.tar.gz
Revise zipper tests for speed and to be more accurate about what is being tested
-rw-r--r--astroid/interpreter/lookup.py13
-rw-r--r--astroid/tests/unittest_zipper.py108
-rw-r--r--astroid/tree/base.py20
3 files changed, 77 insertions, 64 deletions
diff --git a/astroid/interpreter/lookup.py b/astroid/interpreter/lookup.py
index 20fda77a..a2fb88e1 100644
--- a/astroid/interpreter/lookup.py
+++ b/astroid/interpreter/lookup.py
@@ -32,8 +32,7 @@ except ImportError:
from dictproxyhack import dictproxy as MappingProxyType
-class LocalsDictNode(treebase.LookupMixIn,
- treebase.NodeNG):
+class LocalsDictNode(treebase.LookupMixIn, treebase.NodeNG):
"""Provides locals handling common to Module, FunctionDef
and ClassDef nodes, including a dict like interface for direct access
to locals information
@@ -109,11 +108,11 @@ class LocalsDictNode(treebase.LookupMixIn,
"""
return self.locals[item][0]
- def __iter__(self):
- """method from the `dict` interface returning an iterator on
- `self.keys()`
- """
- return iter(self.locals)
+ # def __iter__(self):
+ # """method from the `dict` interface returning an iterator on
+ # `self.keys()`
+ # """
+ # return iter(self.locals)
def keys(self):
"""method from the `dict` interface returning a tuple containing
diff --git a/astroid/tests/unittest_zipper.py b/astroid/tests/unittest_zipper.py
index 7ba57378..578146be 100644
--- a/astroid/tests/unittest_zipper.py
+++ b/astroid/tests/unittest_zipper.py
@@ -1,6 +1,8 @@
-import cProfile
+import collections
import itertools
+import pprint
import os
+import unittest
import hypothesis
from hypothesis import strategies
@@ -9,68 +11,60 @@ import astroid
from astroid.tree import zipper
-# __init__.py screens out the empty init files, testdata because of
-# the deliberately-broken files, and unittests because of #310.
+# This screens out the empty init files.
astroid_file = strategies.sampled_from(os.path.join(p, n) for p, _, ns in os.walk('astroid/') for n in ns if n.endswith('.py') and '__init__.py' not in n)
-def parse_ast(name):
+MapNode = collections.namedtuple('MapNode', 'children parent moves')
+
+def ast_from_file_name(name):
with open(name, 'r') as source_file:
print(name)
- ast = zipper.Zipper(astroid.parse(source_file.read()))
- return (ast.down,)
-
-base_case = strategies.builds(parse_ast, astroid_file)
-
-def possible_moves(path):
- # position = path[-1]()
- # previous_position = path[-1].__self__
- # if not len(previous_position):
- # return ()
- # length = 0
- # # If the zipper produces a position that is not the child of the
- # # previous position, this is a bug and thus should crash.
- # for child in previous_position:
- # length += 1
- # if child == position:
- # index = length
- # break
- # else:
- # print(position)
- # print([repr(c) for c in previous_position])
- # raise astroid.exceptions.AstroidError(
- # 'Invalid AST: {child!r} is not a child of {parent!r}',
- # child=position, parent=previous_position)
- # moves = []
- # if position._self_path:
- # moves.append(position.up)
- # if length > 0:
- # moves.append(position.down)
- # if index < length:
- # moves.append(position.right)
- # if index > 0:
- # moves.append(position.left)
- position = path[-1]()
- return tuple(m for m in (position.down, position.up, position.left, position.right) if m() is not None)
-
-extend = lambda path_strategy: path_strategy.flatmap(lambda path: strategies.sampled_from(possible_moves(path)).map(lambda move: path + (move,)))
-
-walk_ast = strategies.recursive(base_case, extend)
+ root = astroid.parse(source_file.read())
+ to_visit = [(root, None)]
+ ast = {}
+ while to_visit:
+ node, parent = to_visit.pop()
+ children = tuple(iter(node)) if node else ()
+ to_visit.extend((c, node) for c in children)
+ moves = []
+ if children:
+ moves.append(zipper.Zipper.down)
+ if parent:
+ moves.append(zipper.Zipper.up)
+ index = ast[id(parent)].children.index(node)
+ if index > 0:
+ moves.append(zipper.Zipper.left)
+ if index < len(ast[id(parent)].children) - 1:
+ moves.append(zipper.Zipper.right)
+ ast[id(node)] = MapNode(children, parent, tuple(moves))
+ return ast, root
-# print(walk_ast.example())
+ast_strategy = strategies.builds(ast_from_file_name, astroid_file)
-# cProfile.run('print(walk_ast.example())')
+# pprint.pprint(ast_strategy.example())
-@hypothesis.given(walk_ast)
-def test(moves):
- print(moves)
- moves = tuple(reversed(moves))
- visited_positions = {id(moves[0].__self__): moves[0].__self__}
- for move in moves:
- position = move()
- if id(position) in visited_positions:
- assert(position == visited_positions[id(position)])
- visited_positions[id(position)] = position
+class TestZipper(unittest.TestCase):
+ @hypothesis.settings(perform_health_check=False)
+ @hypothesis.given(ast_strategy, strategies.integers(min_value=0, max_value=100), strategies.choices())
+ def test(self, ast_root, length, choice):
+ ast, root = ast_root
+ old_position = zipper.Zipper(root)
+ for _ in range(length):
+ move = choice(ast[id(old_position.__wrapped__)].moves)
+ new_position = move(old_position)
+ if move is zipper.Zipper.down:
+ assert(new_position.__wrapped__ is next(iter(old_position)))
+ if move is zipper.Zipper.up:
+ assert(new_position.__wrapped__ is ast[id(old_position.__wrapped__)].parent)
+ if move is zipper.Zipper.left or move is zipper.Zipper.right:
+ parent = ast[id(old_position.__wrapped__)].parent
+ siblings = ast[id(parent)].children
+ index = siblings.index(old_position.__wrapped__)
+ if move is zipper.Zipper.left:
+ assert(new_position.__wrapped__ is siblings[index - 1])
+ if move is zipper.Zipper.right:
+ assert(new_position.__wrapped__ is siblings[index + 1])
+ old_position = new_position
if __name__ == '__main__':
- test()
- # pass
+ unittest.main()
diff --git a/astroid/tree/base.py b/astroid/tree/base.py
index 58298b8d..dc5119e1 100644
--- a/astroid/tree/base.py
+++ b/astroid/tree/base.py
@@ -61,6 +61,26 @@ class NodeNG(object):
self.lineno = lineno
self.col_offset = col_offset
self.parent = parent
+
+ def __iter__(self):
+ for field in self._astroid_fields:
+ yield getattr(self, field)
+
+ # def __eq__(self, other):
+ # if self.__class__ is other.__class__:
+ # return (all(getattr(self, f) == getattr(other, f)
+ # for f in self._astroid_fields) and
+ # all(getattr(self, f) == getattr(other, f)
+ # for f in self._other_fields))
+ # else:
+ # return False
+
+ # def __ne__(self, other):
+ # return not self == other
+
+ # # Must be defined to retain object.__hash__, see
+ # # https://docs.python.org/3/reference/datamodel.html#object.__hash__
+ # __hash__ = object.__hash__
def infer(self, context=None, **kwargs):
"""main interface to the interface system, return a generator on inferred