diff --git a/parso/python/normalizer.py b/parso/python/normalizer.py index 64d6c35..9da1687 100644 --- a/parso/python/normalizer.py +++ b/parso/python/normalizer.py @@ -3,6 +3,7 @@ from contextlib import contextmanager from parso.normalizer import Normalizer, NormalizerConfig, Issue _BLOCK_STMTS = ('if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt') +_ASYNC_FUNC_TYPES = 'async_funcdef', 'async_stmt' # This is the maximal block size given by python. _MAX_BLOCK_SIZE = 20 @@ -22,6 +23,7 @@ class Context(object): def __init__(self, node, parent_context=None): self.node = node self.blocks = [] + self.parent_context = parent_context @contextmanager def add_block(self, node): @@ -130,8 +132,13 @@ class ErrorFinder(Normalizer): self._add_syntax_error("'%s' outside function" % leaf.value, leaf) elif leaf.value == 'await': if self._context.node.type != 'funcdef' \ - or self._context.node.parent.type != 'async_funcdef': + or self._context.node.parent.type not in _ASYNC_FUNC_TYPES: self._add_syntax_error("'await' outside async function", leaf) + elif leaf.value == 'from' and leaf.parent.type == 'yield_arg' \ + and self._context.node.type == 'funcdef' \ + and self._context.node.parent.type in _ASYNC_FUNC_TYPES: + yield_ = leaf.parent.parent + self._add_syntax_error("'yield from' inside async function", yield_) return '' def _add_indentation_error(self, message, spacing): diff --git a/test/normalizer_issue_files/allowed_syntax_python3.5.py b/test/normalizer_issue_files/allowed_syntax_python3.5.py new file mode 100644 index 0000000..511d118 --- /dev/null +++ b/test/normalizer_issue_files/allowed_syntax_python3.5.py @@ -0,0 +1,19 @@ +""" +Mostly allowed syntax in Python 3.5. +""" + + +async def foo(): + yield 1 + await bar() + #: E901 + yield from [] + + +# With decorator it's a different statement. +@bla +async def foo(): + yield 1 + await bar() + #: E901 + yield from [] diff --git a/test/test_python_errors.py b/test/test_python_errors.py index 3549a47..157caab 100644 --- a/test/test_python_errors.py +++ b/test/test_python_errors.py @@ -59,8 +59,9 @@ def test_indentation_errors(code, positions): @pytest.mark.parametrize( 'code', [ # SyntaxError - pytest.mark.skipif('sys.version_info < (2, 6)', '1 +'), - pytest.mark.skipif('sys.version_info < (2, 6)', '?'), + # Python 2.6 has a bit different error messages here, so skip it. + pytest.mark.skipif('sys.version_info <= (2, 6)', '1 +'), + pytest.mark.skipif('sys.version_info <= (2, 6)', '?'), dedent('''\ for a in [1]: try: @@ -97,6 +98,7 @@ def test_python_exception_matches(code): # SyntaxError ('async def bla():\n def x(): await bla()', '3.5'), ('yield from []', '3.5'), + ('async def foo(): yield from []', '3.5'), ] ) def test_python_exception_matches_version(code, version):