Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4638c64

Browse files
authored
bpo-40334: Error message for invalid default args in function call (GH-19973)
When parsing something like `f(g()=2)`, where the name of a default arg is not a NAME, but an arbitrary expression, a specialised error message is emitted.
1 parent 2f37c35 commit 4638c64

File tree

4 files changed

+222
-159
lines changed

4 files changed

+222
-159
lines changed

Grammar/python.gram

+4
Original file line numberDiff line numberDiff line change
@@ -548,10 +548,12 @@ kwarg_or_starred[KeywordOrStarred*]:
548548
| a=NAME '=' b=expression {
549549
_PyPegen_keyword_or_starred(p, CHECK(_Py_keyword(a->v.Name.id, b, EXTRA)), 1) }
550550
| a=starred_expression { _PyPegen_keyword_or_starred(p, a, 0) }
551+
| invalid_kwarg
551552
kwarg_or_double_starred[KeywordOrStarred*]:
552553
| a=NAME '=' b=expression {
553554
_PyPegen_keyword_or_starred(p, CHECK(_Py_keyword(a->v.Name.id, b, EXTRA)), 1) }
554555
| '**' a=expression { _PyPegen_keyword_or_starred(p, CHECK(_Py_keyword(NULL, a, EXTRA)), 1) }
556+
| invalid_kwarg
555557

556558
# NOTE: star_targets may contain *bitwise_or, targets may not.
557559
star_targets[expr_ty]:
@@ -620,6 +622,8 @@ incorrect_arguments:
620622
| expression for_if_clauses ',' [args | expression for_if_clauses] {
621623
RAISE_SYNTAX_ERROR("Generator expression must be parenthesized") }
622624
| a=args ',' args { _PyPegen_arguments_parsing_error(p, a) }
625+
invalid_kwarg:
626+
| expression '=' { RAISE_SYNTAX_ERROR("expression cannot contain assignment, perhaps you meant \"==\"?") }
623627
invalid_named_expression:
624628
| a=expression ':=' expression {
625629
RAISE_SYNTAX_ERROR("cannot use assignment expressions with %s", _PyPegen_get_expr_name(a)) }

Lib/test/test_exceptions.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -242,16 +242,16 @@ def baz():
242242
check('from __future__ import doesnt_exist', 1, 1)
243243
check('from __future__ import braces', 1, 1)
244244
check('x=1\nfrom __future__ import division', 2, 1)
245+
check('(yield i) = 2', 1, 1)
245246
check('def f(*):\n pass', 1, 7 if support.use_old_parser() else 8)
247+
check('foo(1=2)', 1, 5 if support.use_old_parser() else 6)
246248

247249
@support.skip_if_new_parser("Pegen column offsets might be different")
248250
def testSyntaxErrorOffsetCustom(self):
249251
self.check('for 1 in []: pass', 1, 5)
250252
self.check('[*x for x in xs]', 1, 2)
251253
self.check('def f():\n x, y: int', 2, 3)
252-
self.check('(yield i) = 2', 1, 1)
253254
self.check('foo(x for x in range(10), 100)', 1, 5)
254-
self.check('foo(1=2)', 1, 5)
255255

256256
@cpython_only
257257
def testSettingException(self):

Lib/test/test_peg_parser.py

+3
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,9 @@ def f():
609609
("lambda *: pass", "named arguments must follow bare *"),
610610
("lambda *,: pass", "named arguments must follow bare *"),
611611
("lambda *, **a: pass", "named arguments must follow bare *"),
612+
("f(g()=2", "expression cannot contain assignment, perhaps you meant \"==\"?"),
613+
("f(a, b, *c, d.e=2", "expression cannot contain assignment, perhaps you meant \"==\"?"),
614+
("f(*a, **b, c=0, d[1]=3)", "expression cannot contain assignment, perhaps you meant \"==\"?"),
612615
]
613616

614617
GOOD_BUT_FAIL_TEST_CASES = [

0 commit comments

Comments
 (0)