Skip to content

Commit 48f305f

Browse files
bpo-41979: Accept star-unpacking on with-item targets (GH-22611)
Co-authored-by: Pablo Galindo <[email protected]>
1 parent 666f583 commit 48f305f

File tree

4 files changed

+18
-8
lines changed

4 files changed

+18
-8
lines changed

Grammar/python.gram

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ with_stmt[stmt_ty]:
182182
| ASYNC 'with' a[asdl_withitem_seq*]=','.with_item+ ':' tc=[TYPE_COMMENT] b=block {
183183
CHECK_VERSION(5, "Async with statements are", _Py_AsyncWith(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA)) }
184184
with_item[withitem_ty]:
185-
| e=expression 'as' t=target &(',' | ')' | ':') { _Py_withitem(e, t, p->arena) }
185+
| e=expression 'as' t=star_target &(',' | ')' | ':') { _Py_withitem(e, t, p->arena) }
186186
| invalid_with_item
187187
| e=expression { _Py_withitem(e, NULL, p->arena) }
188188

Lib/test/test_with.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import sys
88
import unittest
99
from collections import deque
10-
from contextlib import _GeneratorContextManager, contextmanager
10+
from contextlib import _GeneratorContextManager, contextmanager, nullcontext
1111

1212

1313
class MockContextManager(_GeneratorContextManager):
@@ -641,6 +641,12 @@ class B: pass
641641
self.assertEqual(blah.two, 2)
642642
self.assertEqual(blah.three, 3)
643643

644+
def testWithExtendedTargets(self):
645+
with nullcontext(range(1, 5)) as (a, *b, c):
646+
self.assertEqual(a, 1)
647+
self.assertEqual(b, [2, 3])
648+
self.assertEqual(c, 4)
649+
644650

645651
class ExitSwallowsExceptionTestCase(unittest.TestCase):
646652

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Star-unpacking is now allowed for with item's targets in the PEG parser.

Parser/parser.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4290,7 +4290,10 @@ with_stmt_rule(Parser *p)
42904290
return _res;
42914291
}
42924292

4293-
// with_item: expression 'as' target &(',' | ')' | ':') | invalid_with_item | expression
4293+
// with_item:
4294+
// | expression 'as' star_target &(',' | ')' | ':')
4295+
// | invalid_with_item
4296+
// | expression
42944297
static withitem_ty
42954298
with_item_rule(Parser *p)
42964299
{
@@ -4301,12 +4304,12 @@ with_item_rule(Parser *p)
43014304
}
43024305
withitem_ty _res = NULL;
43034306
int _mark = p->mark;
4304-
{ // expression 'as' target &(',' | ')' | ':')
4307+
{ // expression 'as' star_target &(',' | ')' | ':')
43054308
if (p->error_indicator) {
43064309
D(p->level--);
43074310
return NULL;
43084311
}
4309-
D(fprintf(stderr, "%*c> with_item[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression 'as' target &(',' | ')' | ':')"));
4312+
D(fprintf(stderr, "%*c> with_item[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')"));
43104313
Token * _keyword;
43114314
expr_ty e;
43124315
expr_ty t;
@@ -4315,12 +4318,12 @@ with_item_rule(Parser *p)
43154318
&&
43164319
(_keyword = _PyPegen_expect_token(p, 520)) // token='as'
43174320
&&
4318-
(t = target_rule(p)) // target
4321+
(t = star_target_rule(p)) // star_target
43194322
&&
43204323
_PyPegen_lookahead(1, _tmp_47_rule, p)
43214324
)
43224325
{
4323-
D(fprintf(stderr, "%*c+ with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' target &(',' | ')' | ':')"));
4326+
D(fprintf(stderr, "%*c+ with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')"));
43244327
_res = _Py_withitem ( e , t , p -> arena );
43254328
if (_res == NULL && PyErr_Occurred()) {
43264329
p->error_indicator = 1;
@@ -4331,7 +4334,7 @@ with_item_rule(Parser *p)
43314334
}
43324335
p->mark = _mark;
43334336
D(fprintf(stderr, "%*c%s with_item[%d-%d]: %s failed!\n", p->level, ' ',
4334-
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression 'as' target &(',' | ')' | ':')"));
4337+
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')"));
43354338
}
43364339
{ // invalid_with_item
43374340
if (p->error_indicator) {

0 commit comments

Comments
 (0)