From 8f46481aafd39cfc2f283008b1beb02165ceefef Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 22 May 2020 19:52:22 +0300 Subject: [PATCH 1/2] Raise violation on starred expressions where the child is a boolean/none --- parso/python/errors.py | 39 ++++++++++++------- test/normalizer_issue_files/allowed_syntax.py | 7 ---- test/test_python_errors.py | 23 +++++++++++ 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/parso/python/errors.py b/parso/python/errors.py index b0cc29a..0c8c976 100644 --- a/parso/python/errors.py +++ b/parso/python/errors.py @@ -5,7 +5,7 @@ import re from contextlib import contextmanager from parso.normalizer import Normalizer, NormalizerConfig, Issue, Rule -from parso.python.tree import search_ancestor +from parso.python.tree import Keyword, search_ancestor _BLOCK_STMTS = ('if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt') _STAR_EXPR_PARENTS = ('testlist_star_expr', 'testlist_comp', 'exprlist') @@ -643,6 +643,9 @@ class _StarExprRule(SyntaxRule): message = "starred assignment target must be in a list or tuple" message_iterable_unpacking = "iterable unpacking cannot be used in comprehension" message_assignment = "can use starred expression only as assignment target" + message_cannot_assign = "cannot assign to {target}" + + _FORBIDDEN = frozenset(("True", "False", "None")) def is_issue(self, node): if node.parent.type not in _STAR_EXPR_PARENTS: @@ -651,19 +654,29 @@ class _StarExprRule(SyntaxRule): # [*[] for a in [1]] if node.parent.children[1].type in _COMP_FOR_TYPES: self.add_issue(node, message=self.message_iterable_unpacking) - if self._normalizer.version <= (3, 4): - n = search_ancestor(node, 'for_stmt', 'expr_stmt') - found_definition = False - if n is not None: - if n.type == 'expr_stmt': - exprs = _get_expr_stmt_definition_exprs(n) - else: - exprs = _get_for_stmt_definition_exprs(n) - if node in exprs: - found_definition = True - if not found_definition: - self.add_issue(node, message=self.message_assignment) + assignment_ancestor = search_ancestor(node, 'for_stmt', 'expr_stmt') + found_definition = False + if assignment_ancestor is not None: + if assignment_ancestor.type == 'expr_stmt': + exprs = _get_expr_stmt_definition_exprs(assignment_ancestor) + else: + exprs = _get_for_stmt_definition_exprs(assignment_ancestor) + if node in exprs: + found_definition = True + + if found_definition: + for child in node.children: + if isinstance(child, Keyword) and child.value in self._FORBIDDEN: + self.add_issue( + node, + message=self.message_cannot_assign.format( + target=child.value + ), + ) + + if self._normalizer.version <= (3, 4) and not found_definition: + self.add_issue(node, message=self.message_assignment) @ErrorFinder.register_rule(types=_STAR_EXPR_PARENTS) diff --git a/test/normalizer_issue_files/allowed_syntax.py b/test/normalizer_issue_files/allowed_syntax.py index 9ac0a6d..a73b84c 100644 --- a/test/normalizer_issue_files/allowed_syntax.py +++ b/test/normalizer_issue_files/allowed_syntax.py @@ -12,13 +12,6 @@ from .__future__ import absolute_import ''r''u'' b'' BR'' -for x in [1]: - try: - continue # Only the other continue and pass is an error. - finally: - #: E901 - continue - for x in [1]: break diff --git a/test/test_python_errors.py b/test/test_python_errors.py index bf00d57..26d9e6e 100644 --- a/test/test_python_errors.py +++ b/test/test_python_errors.py @@ -339,3 +339,26 @@ def test_continue_in_finally(): assert _get_error_list(code, version="3.7") +@pytest.mark.parametrize( + 'template', [ + "a, b, {target}, c = d", + "a, b, *{target}, c = d", + "(a, *{target}), c = d", + "for x, {target} in y: pass", + "for x, q, {target} in y: pass", + "for x, q, *{target} in y: pass", + "for (x, *{target}), q in y: pass", + ] +) +@pytest.mark.parametrize( + 'target', [ + "True", + "False", + "None", + "__debug__" + ] +) +def test_forbidden_name(template, target): + assert _get_error_list(template.format(target=target), version="3")[0].message + + From 342e308f574df97bc3121cf0b442174d6bb25555 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Sat, 23 May 2020 01:18:23 +0300 Subject: [PATCH 2/2] Move checking to the _CheckAssignmentRule --- parso/python/errors.py | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/parso/python/errors.py b/parso/python/errors.py index 0c8c976..6fb7f67 100644 --- a/parso/python/errors.py +++ b/parso/python/errors.py @@ -5,7 +5,7 @@ import re from contextlib import contextmanager from parso.normalizer import Normalizer, NormalizerConfig, Issue, Rule -from parso.python.tree import Keyword, search_ancestor +from parso.python.tree import search_ancestor _BLOCK_STMTS = ('if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt') _STAR_EXPR_PARENTS = ('testlist_star_expr', 'testlist_comp', 'exprlist') @@ -643,9 +643,6 @@ class _StarExprRule(SyntaxRule): message = "starred assignment target must be in a list or tuple" message_iterable_unpacking = "iterable unpacking cannot be used in comprehension" message_assignment = "can use starred expression only as assignment target" - message_cannot_assign = "cannot assign to {target}" - - _FORBIDDEN = frozenset(("True", "False", "None")) def is_issue(self, node): if node.parent.type not in _STAR_EXPR_PARENTS: @@ -654,29 +651,19 @@ class _StarExprRule(SyntaxRule): # [*[] for a in [1]] if node.parent.children[1].type in _COMP_FOR_TYPES: self.add_issue(node, message=self.message_iterable_unpacking) + if self._normalizer.version <= (3, 4): + n = search_ancestor(node, 'for_stmt', 'expr_stmt') + found_definition = False + if n is not None: + if n.type == 'expr_stmt': + exprs = _get_expr_stmt_definition_exprs(n) + else: + exprs = _get_for_stmt_definition_exprs(n) + if node in exprs: + found_definition = True - assignment_ancestor = search_ancestor(node, 'for_stmt', 'expr_stmt') - found_definition = False - if assignment_ancestor is not None: - if assignment_ancestor.type == 'expr_stmt': - exprs = _get_expr_stmt_definition_exprs(assignment_ancestor) - else: - exprs = _get_for_stmt_definition_exprs(assignment_ancestor) - if node in exprs: - found_definition = True - - if found_definition: - for child in node.children: - if isinstance(child, Keyword) and child.value in self._FORBIDDEN: - self.add_issue( - node, - message=self.message_cannot_assign.format( - target=child.value - ), - ) - - if self._normalizer.version <= (3, 4) and not found_definition: - self.add_issue(node, message=self.message_assignment) + if not found_definition: + self.add_issue(node, message=self.message_assignment) @ErrorFinder.register_rule(types=_STAR_EXPR_PARENTS) @@ -994,6 +981,8 @@ class _CheckAssignmentRule(SyntaxRule): or '_test' in type_ or type_ in ('term', 'factor')): error = 'operator' + elif type_ == "star_expr": + self._check_assignment(node.children[1]) if error is not None: if is_namedexpr: