summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcpopa <devnull@localhost>2014-03-04 09:29:46 +0200
committercpopa <devnull@localhost>2014-03-04 09:29:46 +0200
commit305b7d3192971ad881430719fd063521067a0de3 (patch)
tree24b9778412c90f68f018b0e592586aafa81c3d18
parent33d7e72938705808199d64370c85e4ac8bb45af5 (diff)
downloadastroid-305b7d3192971ad881430719fd063521067a0de3.tar.gz
Drop yield_from API, add a new YieldFrom node instead.
-rw-r--r--ChangeLog4
-rw-r--r--as_string.py15
-rw-r--r--node_classes.py7
-rw-r--r--nodes.py4
-rw-r--r--rebuilder.py20
-rw-r--r--scoped_nodes.py5
-rw-r--r--test/unittest_python3.py36
7 files changed, 55 insertions, 36 deletions
diff --git a/ChangeLog b/ChangeLog
index f065913..6881c7e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -15,9 +15,7 @@ Change log for the astroid package (used to be astng)
* Don't crash when inferring nodes from `with` clauses
with multiple context managers. Closes #18.
- * Add `yield_from` property to `Yield` nodes, in order
- to differentiate between the classic `yield` and `yield from`.
-
+ * Add a new YieldFrom node.
2013-10-18 -- 1.0.1
* fix py3k/windows installation issue (issue #4)
diff --git a/as_string.py b/as_string.py
index 1863b93..ace1c4e 100644
--- a/as_string.py
+++ b/as_string.py
@@ -429,11 +429,7 @@ class AsStringVisitor(object):
def visit_yield(self, node):
"""yield an ast.Yield node as string"""
yi_val = node.value and (" " + node.value.accept(self)) or ""
- if node.yield_from:
- yield_ = 'yield from'
- else:
- yield_ = 'yield'
- expr = yield_ + yi_val
+ expr = 'yield' + yi_val
if node.parent.is_statement:
return expr
else:
@@ -471,6 +467,15 @@ class AsStringVisitor3k(AsStringVisitor):
"""return Starred node as string"""
return "*" + node.value.accept(self)
+ def visit_yieldfrom(self, node):
+ """ Return an astroid.YieldFrom node as string. """
+ yi_val = node.value and (" " + node.value.accept(self)) or ""
+ expr = 'yield from' + yi_val
+ if node.parent.is_statement:
+ return expr
+ else:
+ return "(%s)" % (expr,)
+
def _import_string(names):
"""return a list of (name, asname) formatted as a string"""
diff --git a/node_classes.py b/node_classes.py
index 3873127..01dc8d9 100644
--- a/node_classes.py
+++ b/node_classes.py
@@ -886,11 +886,10 @@ class With(BlockRangeMixIn, AssignTypeMixin, Statement):
class Yield(NodeNG):
"""class representing a Yield node"""
_astroid_fields = ('value',)
- value = _from = None
+ value = None
- @property
- def yield_from(self):
- return self._from
+class YieldFrom(Yield):
+ """ Class representing a YieldFrom node. """
# constants ##############################################################
diff --git a/nodes.py b/nodes.py
index 9fdc67e..263ab47 100644
--- a/nodes.py
+++ b/nodes.py
@@ -43,7 +43,7 @@ from astroid.node_classes import Arguments, AssAttr, Assert, Assign, \
Dict, Discard, Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice, For, \
From, Getattr, Global, If, IfExp, Import, Index, Keyword, \
List, Name, Nonlocal, Pass, Print, Raise, Return, Set, Slice, Starred, Subscript, \
- TryExcept, TryFinally, Tuple, UnaryOp, While, With, Yield, \
+ TryExcept, TryFinally, Tuple, UnaryOp, While, With, Yield, YieldFrom, \
const_factory
from astroid.scoped_nodes import Module, GenExpr, Lambda, DictComp, \
ListComp, SetComp, Function, Class
@@ -68,6 +68,6 @@ ALL_NODE_CLASSES = (
TryExcept, TryFinally, Tuple,
UnaryOp,
While, With,
- Yield,
+ Yield, YieldFrom
)
diff --git a/rebuilder.py b/rebuilder.py
index 24ce802..f6fae7b 100644
--- a/rebuilder.py
+++ b/rebuilder.py
@@ -122,6 +122,14 @@ def _infer_metaclass(node):
elif isinstance(node, Attribute):
return node.attr
+def _create_yield_node(node, parent, rebuilder, factory):
+ newnode = factory()
+ _lineno_parent(node, newnode, parent)
+ if node.value is not None:
+ newnode.value = rebuilder.visit(node.value, newnode)
+ newnode.set_line_info(newnode.last_child())
+ return newnode
+
class TreeRebuilder(object):
"""Rebuilds the _ast tree to become an Astroid tree"""
@@ -837,13 +845,7 @@ class TreeRebuilder(object):
def visit_yield(self, node, parent):
"""visit a Yield node by returning a fresh instance of it"""
- newnode = new.Yield()
- _lineno_parent(node, newnode, parent)
- if node.value is not None:
- newnode.value = self.visit(node.value, newnode)
- newnode.set_line_info(newnode.last_child())
- return newnode
-
+ return _create_yield_node(node, parent, self, new.Yield)
class TreeRebuilder3k(TreeRebuilder):
"""extend and overwrite TreeRebuilder for python3k"""
@@ -954,9 +956,7 @@ class TreeRebuilder3k(TreeRebuilder):
return newnode
def visit_yieldfrom(self, node, parent):
- newnode = self.visit_yield(node, parent)
- newnode._from = True
- return newnode
+ return _create_yield_node(node, parent, self, new.YieldFrom)
def visit_class(self, node, parent):
newnode = super(TreeRebuilder3k, self).visit_class(node, parent)
diff --git a/scoped_nodes.py b/scoped_nodes.py
index a7f6ee8..d579913 100644
--- a/scoped_nodes.py
+++ b/scoped_nodes.py
@@ -32,7 +32,7 @@ from logilab.common.decorators import cached
from astroid.exceptions import NotFoundError, \
AstroidBuildingException, InferenceError
from astroid.node_classes import Const, DelName, DelAttr, \
- Dict, From, List, Pass, Raise, Return, Tuple, Yield, \
+ Dict, From, List, Pass, Raise, Return, Tuple, Yield, YieldFrom, \
LookupMixIn, const_factory as cf, unpack_infer
from astroid.bases import NodeNG, InferenceContext, Instance,\
YES, Generator, UnboundMethod, BoundMethod, _infer_stmts, copy_context, \
@@ -620,7 +620,8 @@ class Function(Statement, Lambda):
"""return true if this is a generator function"""
# XXX should be flagged, not computed
try:
- return self.nodes_of_class(Yield, skip_klass=(Function, Lambda)).next()
+ return self.nodes_of_class((Yield, YieldFrom),
+ skip_klass=(Function, Lambda)).next()
except StopIteration:
return False
diff --git a/test/unittest_python3.py b/test/unittest_python3.py
index e04be83..1390df0 100644
--- a/test/unittest_python3.py
+++ b/test/unittest_python3.py
@@ -46,22 +46,38 @@ class Python3TC(TestCase):
body = dedent("""
def func():
yield from iter([1, 2])
- yield 1
""")
astroid = self.builder.string_build(body)
func = astroid.body[0]
self.assertIsInstance(func, Function)
- yield_from = func.body[0]
- yield_ = func.body[1]
- self.assertIsInstance(yield_from, Discard)
- self.assertIsInstance(yield_from.value, Yield)
- self.assertTrue(yield_from.value.yield_from)
- self.assertEqual(yield_from.as_string(),
+ yieldfrom_stmt = func.body[0]
+
+ self.assertIsInstance(yieldfrom_stmt, Discard)
+ self.assertIsInstance(yieldfrom_stmt.value, YieldFrom)
+ self.assertEqual(yieldfrom_stmt.as_string(),
'yield from iter([1, 2])')
- self.assertIsInstance(yield_, Discard)
- self.assertIsInstance(yield_.value, Yield)
- self.assertFalse(yield_.value.yield_from)
+ @require_version('3.3')
+ def test_yield_from_is_generator(self):
+ body = dedent("""
+ def func():
+ yield from iter([1, 2])
+ """)
+ astroid = self.builder.string_build(body)
+ func = astroid.body[0]
+ self.assertIsInstance(func, Function)
+ self.assertTrue(func.is_generator())
+
+ @require_version('3.3')
+ def test_yield_from_as_string(self):
+ body = dedent("""
+ def func():
+ yield from iter([1, 2])
+ value = yield from other()
+ """)
+ astroid = self.builder.string_build(body)
+ func = astroid.body[0]
+ self.assertEqual(func.as_string(), body.strip())
# metaclass tests