Permalink
Browse files

postpone evaluation of for iter part to prevent infinite recursion

  • Loading branch information...
1 parent fe20d7b commit fb3f88d29a40c8c7507088ead583520da04a3d7a @baverman committed Jul 30, 2011
Showing with 32 additions and 5 deletions.
  1. +17 −2 supplement/names.py
  2. +3 −2 supplement/scope.py
  3. +2 −1 supplement/tree.py
  4. +2 −0 tests/test_calls.py
  5. +8 −0 tests/test_evaluator.py
View
19 supplement/names.py
@@ -106,6 +106,21 @@ def get_location(self):
return self.lineno, self.filename
+class PostponedName(GetObjectDelegate):
+ def __init__(self, owner, *node):
+ self.owner = owner
+ self.node = node
+
+ def get_object(self):
+ try:
+ return self._object
+ except AttributeError:
+ pass
+
+ obj = self._object = create_name(self.node, self.owner)
+ return obj
+
+
class RecursiveCallException(Exception):
def __init__(self, obj):
self.object = obj
@@ -368,7 +383,7 @@ def get_indexes_for_target(self, target, result, idx):
return result
def visit_For(self, node):
- value = create_object_from_seq_item(self.scope, node.iter)
+ value = PostponedName(self.scope, create_object_from_seq_item, self.scope, node.iter)
for n, idx in self.get_indexes_for_target(node.target, [], []):
self.add_name(n.id, (AssignedName, idx, value, n.lineno), node.lineno)
@@ -386,7 +401,7 @@ def visit_Assign(self, node):
if isinstance(n, ast.Name):
self.add_name(n.id, (AssignedName, idx, value, n.lineno), n.lineno)
if isinstance(n, ast.Subscript):
- self.subscript_assignments.append((n.value, n.slice, node.value))
+ self.subscript_assignments.append((n.value, n.slice, idx, value, n.lineno))
def visit_arguments(self, node):
for i, n in enumerate(node.args):
View
5 supplement/scope.py
@@ -111,16 +111,17 @@ def get_names(self, lineno=None):
try:
self._names
except AttributeError:
+ from supplement.names import AssignedName
self._names, starred_imports, sassigns = NameExtractor().process(self.node, self)
for m, line in starred_imports:
for name in self.project.get_module(m, self.filename).get_names():
self._names.setdefault(name, []).append((line, (ImportedName, m, name)))
self._names[name].sort(reverse=True)
- for target, idx, value in sassigns:
+ for target, idx, vidx, value, line in sassigns:
t = self.eval(target, False)
if t:
- t.op_setitem(self.eval(idx, False), self.eval(value, False))
+ t.op_setitem(self.eval(idx, False), AssignedName(vidx, value, line))
else:
logging.getLogger(__name__).error(
"Can't eval target on subscript assign %s %s", self.filename, vars(target))
View
3 supplement/tree.py
@@ -93,7 +93,8 @@ def process(self, node):
return self.result
def visit_Return(self, node):
- self.result.append(node)
+ if node.value:
+ self.result.append(node)
class TreeDumper(ast.NodeVisitor):
View
2 tests/test_calls.py
@@ -10,6 +10,8 @@
def pytest_generate_tests(metafunc):
if 'fname' in metafunc.funcargnames:
+ #metafunc.addcall(funcargs={'fname':'supplement/hooks/pygtk/docbook.py'})
+ #return
for top, dirs, files in os.walk('supplement'):
if top.endswith('override/modules'):
continue
View
8 tests/test_evaluator.py
@@ -302,3 +302,11 @@ def test_compare_expression(scope):
def test_generator_expression(project):
pass
+
+def test_empty_return(project):
+ scope = project.create_scope('''
+ def foo():
+ return
+ ''')
+ obj = infer('foo()', scope, 100)
+ assert isinstance(obj, UnknownObject)

0 comments on commit fb3f88d

Please sign in to comment.