mirror of
https://github.com/davidhalter/parso.git
synced 2026-03-02 05:17:10 +08:00
Merge pull request #135 from isidentical/starred-expr
Improve handling of starred expression on different contexts
This commit is contained in:
@@ -713,13 +713,10 @@ class _FutureImportRule(SyntaxRule):
|
|||||||
|
|
||||||
@ErrorFinder.register_rule(type='star_expr')
|
@ErrorFinder.register_rule(type='star_expr')
|
||||||
class _StarExprRule(SyntaxRule):
|
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_iterable_unpacking = "iterable unpacking cannot be used in comprehension"
|
||||||
message_assignment = "can use starred expression only as assignment target"
|
message_assignment = "can use starred expression only as assignment target"
|
||||||
|
|
||||||
def is_issue(self, node):
|
def is_issue(self, node):
|
||||||
if node.parent.type not in _STAR_EXPR_PARENTS:
|
|
||||||
return True
|
|
||||||
if node.parent.type == 'testlist_comp':
|
if node.parent.type == 'testlist_comp':
|
||||||
# [*[] for a in [1]]
|
# [*[] for a in [1]]
|
||||||
if node.parent.children[1].type in _COMP_FOR_TYPES:
|
if node.parent.children[1].type in _COMP_FOR_TYPES:
|
||||||
@@ -982,7 +979,7 @@ class _FStringRule(SyntaxRule):
|
|||||||
|
|
||||||
|
|
||||||
class _CheckAssignmentRule(SyntaxRule):
|
class _CheckAssignmentRule(SyntaxRule):
|
||||||
def _check_assignment(self, node, is_deletion=False, is_namedexpr=False):
|
def _check_assignment(self, node, is_deletion=False, is_namedexpr=False, is_aug_assign=False):
|
||||||
error = None
|
error = None
|
||||||
type_ = node.type
|
type_ = node.type
|
||||||
if type_ == 'lambdef':
|
if type_ == 'lambdef':
|
||||||
@@ -1024,9 +1021,9 @@ class _CheckAssignmentRule(SyntaxRule):
|
|||||||
# This is not a comprehension, they were handled
|
# This is not a comprehension, they were handled
|
||||||
# further above.
|
# further above.
|
||||||
for child in second.children[::2]:
|
for child in second.children[::2]:
|
||||||
self._check_assignment(child, is_deletion, is_namedexpr)
|
self._check_assignment(child, is_deletion, is_namedexpr, is_aug_assign)
|
||||||
else: # Everything handled, must be useless brackets.
|
else: # Everything handled, must be useless brackets.
|
||||||
self._check_assignment(second, is_deletion, is_namedexpr)
|
self._check_assignment(second, is_deletion, is_namedexpr, is_aug_assign)
|
||||||
elif type_ == 'keyword':
|
elif type_ == 'keyword':
|
||||||
if node.value == "yield":
|
if node.value == "yield":
|
||||||
error = "yield expression"
|
error = "yield expression"
|
||||||
@@ -1069,12 +1066,15 @@ class _CheckAssignmentRule(SyntaxRule):
|
|||||||
error = "f-string expression"
|
error = "f-string expression"
|
||||||
elif type_ in ('testlist_star_expr', 'exprlist', 'testlist'):
|
elif type_ in ('testlist_star_expr', 'exprlist', 'testlist'):
|
||||||
for child in node.children[::2]:
|
for child in node.children[::2]:
|
||||||
self._check_assignment(child, is_deletion, is_namedexpr)
|
self._check_assignment(child, is_deletion, is_namedexpr, is_aug_assign)
|
||||||
elif ('expr' in type_ and type_ != 'star_expr' # is a substring
|
elif ('expr' in type_ and type_ != 'star_expr' # is a substring
|
||||||
or '_test' in type_
|
or '_test' in type_
|
||||||
or type_ in ('term', 'factor')):
|
or type_ in ('term', 'factor')):
|
||||||
error = 'operator'
|
error = 'operator'
|
||||||
elif type_ == "star_expr":
|
elif type_ == "star_expr":
|
||||||
|
if not search_ancestor(node, *_STAR_EXPR_PARENTS) and not is_aug_assign:
|
||||||
|
self.add_issue(node, message="starred assignment target must be in a list or tuple")
|
||||||
|
|
||||||
self._check_assignment(node.children[1])
|
self._check_assignment(node.children[1])
|
||||||
|
|
||||||
if error is not None:
|
if error is not None:
|
||||||
@@ -1109,7 +1109,7 @@ class _ExprStmtRule(_CheckAssignmentRule):
|
|||||||
|
|
||||||
if self._normalizer.version <= (3, 8) or not is_aug_assign:
|
if self._normalizer.version <= (3, 8) or not is_aug_assign:
|
||||||
for before_equal in node.children[:-2:2]:
|
for before_equal in node.children[:-2:2]:
|
||||||
self._check_assignment(before_equal)
|
self._check_assignment(before_equal, is_aug_assign=is_aug_assign)
|
||||||
|
|
||||||
if is_aug_assign:
|
if is_aug_assign:
|
||||||
target = _remove_parens(node.children[0])
|
target = _remove_parens(node.children[0])
|
||||||
|
|||||||
@@ -391,3 +391,26 @@ def test_repeated_kwarg():
|
|||||||
)
|
)
|
||||||
def test_unparenthesized_genexp(source, no_errors):
|
def test_unparenthesized_genexp(source, no_errors):
|
||||||
assert bool(_get_error_list(source)) ^ no_errors
|
assert bool(_get_error_list(source)) ^ no_errors
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
('source', 'no_errors'), [
|
||||||
|
('*x = 2', False),
|
||||||
|
('(*y) = 1', False),
|
||||||
|
('((*z)) = 1', False),
|
||||||
|
('a, *b = 1', True),
|
||||||
|
('a, *b, c = 1', True),
|
||||||
|
('a, (*b), c = 1', True),
|
||||||
|
('a, ((*b)), c = 1', True),
|
||||||
|
('a, (*b, c), d = 1', True),
|
||||||
|
('[*(1,2,3)]', True),
|
||||||
|
('{*(1,2,3)}', True),
|
||||||
|
('[*(1,2,3),]', True),
|
||||||
|
('[*(1,2,3), *(4,5,6)]', True),
|
||||||
|
('[0, *(1,2,3)]', True),
|
||||||
|
('{*(1,2,3),}', True),
|
||||||
|
('{*(1,2,3), *(4,5,6)}', True),
|
||||||
|
('{0, *(4,5,6)}', True)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_starred_expr(source, no_errors):
|
||||||
|
assert bool(_get_error_list(source, version="3")) ^ no_errors
|
||||||
|
|||||||
Reference in New Issue
Block a user