gh-111420: Allow type comments in parenthesized `with` statements (#111468)

This commit is contained in:
Tomas R 2023-10-31 22:02:42 +01:00 committed by GitHub
parent faa5f6053d
commit 453e96e302
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 32 additions and 8 deletions

View File

@ -391,8 +391,8 @@ for_stmt[stmt_ty]:
with_stmt[stmt_ty]: with_stmt[stmt_ty]:
| invalid_with_stmt_indent | invalid_with_stmt_indent
| 'with' '(' a[asdl_withitem_seq*]=','.with_item+ ','? ')' ':' b=block { | 'with' '(' a[asdl_withitem_seq*]=','.with_item+ ','? ')' ':' tc=[TYPE_COMMENT] b=block {
CHECK_VERSION(stmt_ty, 9, "Parenthesized context managers are", _PyAST_With(a, b, NULL, EXTRA)) } CHECK_VERSION(stmt_ty, 9, "Parenthesized context managers are", _PyAST_With(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA)) }
| 'with' a[asdl_withitem_seq*]=','.with_item+ ':' tc=[TYPE_COMMENT] b=block { | 'with' a[asdl_withitem_seq*]=','.with_item+ ':' tc=[TYPE_COMMENT] b=block {
_PyAST_With(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) } _PyAST_With(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) }
| 'async' 'with' '(' a[asdl_withitem_seq*]=','.with_item+ ','? ')' ':' b=block { | 'async' 'with' '(' a[asdl_withitem_seq*]=','.with_item+ ','? ')' ':' b=block {

View File

@ -100,6 +100,8 @@ exec_tests = [
# With # With
"with x as y: pass", "with x as y: pass",
"with x as y, z as q: pass", "with x as y, z as q: pass",
"with (x as y): pass",
"with (x, y): pass",
# Raise # Raise
"raise Exception('string')", "raise Exception('string')",
# TryExcept # TryExcept
@ -3015,6 +3017,8 @@ exec_results = [
('Module', [('If', (1, 0, 6, 6), ('Name', (1, 3, 1, 4), 'a', ('Load',)), [('Pass', (2, 2, 2, 6))], [('If', (3, 0, 6, 6), ('Name', (3, 5, 3, 6), 'b', ('Load',)), [('Pass', (4, 2, 4, 6))], [('Pass', (6, 2, 6, 6))])])], []), ('Module', [('If', (1, 0, 6, 6), ('Name', (1, 3, 1, 4), 'a', ('Load',)), [('Pass', (2, 2, 2, 6))], [('If', (3, 0, 6, 6), ('Name', (3, 5, 3, 6), 'b', ('Load',)), [('Pass', (4, 2, 4, 6))], [('Pass', (6, 2, 6, 6))])])], []),
('Module', [('With', (1, 0, 1, 17), [('withitem', ('Name', (1, 5, 1, 6), 'x', ('Load',)), ('Name', (1, 10, 1, 11), 'y', ('Store',)))], [('Pass', (1, 13, 1, 17))], None)], []), ('Module', [('With', (1, 0, 1, 17), [('withitem', ('Name', (1, 5, 1, 6), 'x', ('Load',)), ('Name', (1, 10, 1, 11), 'y', ('Store',)))], [('Pass', (1, 13, 1, 17))], None)], []),
('Module', [('With', (1, 0, 1, 25), [('withitem', ('Name', (1, 5, 1, 6), 'x', ('Load',)), ('Name', (1, 10, 1, 11), 'y', ('Store',))), ('withitem', ('Name', (1, 13, 1, 14), 'z', ('Load',)), ('Name', (1, 18, 1, 19), 'q', ('Store',)))], [('Pass', (1, 21, 1, 25))], None)], []), ('Module', [('With', (1, 0, 1, 25), [('withitem', ('Name', (1, 5, 1, 6), 'x', ('Load',)), ('Name', (1, 10, 1, 11), 'y', ('Store',))), ('withitem', ('Name', (1, 13, 1, 14), 'z', ('Load',)), ('Name', (1, 18, 1, 19), 'q', ('Store',)))], [('Pass', (1, 21, 1, 25))], None)], []),
('Module', [('With', (1, 0, 1, 19), [('withitem', ('Name', (1, 6, 1, 7), 'x', ('Load',)), ('Name', (1, 11, 1, 12), 'y', ('Store',)))], [('Pass', (1, 15, 1, 19))], None)], []),
('Module', [('With', (1, 0, 1, 17), [('withitem', ('Name', (1, 6, 1, 7), 'x', ('Load',)), None), ('withitem', ('Name', (1, 9, 1, 10), 'y', ('Load',)), None)], [('Pass', (1, 13, 1, 17))], None)], []),
('Module', [('Raise', (1, 0, 1, 25), ('Call', (1, 6, 1, 25), ('Name', (1, 6, 1, 15), 'Exception', ('Load',)), [('Constant', (1, 16, 1, 24), 'string', None)], []), None)], []), ('Module', [('Raise', (1, 0, 1, 25), ('Call', (1, 6, 1, 25), ('Name', (1, 6, 1, 15), 'Exception', ('Load',)), [('Constant', (1, 16, 1, 24), 'string', None)], []), None)], []),
('Module', [('Try', (1, 0, 4, 6), [('Pass', (2, 2, 2, 6))], [('ExceptHandler', (3, 0, 4, 6), ('Name', (3, 7, 3, 16), 'Exception', ('Load',)), None, [('Pass', (4, 2, 4, 6))])], [], [])], []), ('Module', [('Try', (1, 0, 4, 6), [('Pass', (2, 2, 2, 6))], [('ExceptHandler', (3, 0, 4, 6), ('Name', (3, 7, 3, 16), 'Exception', ('Load',)), None, [('Pass', (4, 2, 4, 6))])], [], [])], []),
('Module', [('Try', (1, 0, 4, 6), [('Pass', (2, 2, 2, 6))], [], [], [('Pass', (4, 2, 4, 6))])], []), ('Module', [('Try', (1, 0, 4, 6), [('Pass', (2, 2, 2, 6))], [], [], [('Pass', (4, 2, 4, 6))])], []),

View File

@ -66,6 +66,14 @@ with context() as a: # type: int
pass pass
""" """
parenthesized_withstmt = """\
with (a as b): # type: int
pass
with (a, b): # type: int
pass
"""
vardecl = """\ vardecl = """\
a = 0 # type: int a = 0 # type: int
""" """
@ -300,6 +308,14 @@ class TypeCommentTests(unittest.TestCase):
tree = self.classic_parse(withstmt) tree = self.classic_parse(withstmt)
self.assertEqual(tree.body[0].type_comment, None) self.assertEqual(tree.body[0].type_comment, None)
def test_parenthesized_withstmt(self):
for tree in self.parse_all(parenthesized_withstmt, minver=9):
self.assertEqual(tree.body[0].type_comment, "int")
self.assertEqual(tree.body[1].type_comment, "int")
tree = self.classic_parse(parenthesized_withstmt)
self.assertEqual(tree.body[0].type_comment, None)
self.assertEqual(tree.body[1].type_comment, None)
def test_vardecl(self): def test_vardecl(self):
for tree in self.parse_all(vardecl): for tree in self.parse_all(vardecl):
self.assertEqual(tree.body[0].type_comment, "int") self.assertEqual(tree.body[0].type_comment, "int")

View File

@ -0,0 +1 @@
Allow type comments in parenthesized ``with`` statements

15
Parser/parser.c generated
View File

@ -6483,7 +6483,7 @@ for_stmt_rule(Parser *p)
// with_stmt: // with_stmt:
// | invalid_with_stmt_indent // | invalid_with_stmt_indent
// | 'with' '(' ','.with_item+ ','? ')' ':' block // | 'with' '(' ','.with_item+ ','? ')' ':' TYPE_COMMENT? block
// | 'with' ','.with_item+ ':' TYPE_COMMENT? block // | 'with' ','.with_item+ ':' TYPE_COMMENT? block
// | 'async' 'with' '(' ','.with_item+ ','? ')' ':' block // | 'async' 'with' '(' ','.with_item+ ','? ')' ':' block
// | 'async' 'with' ','.with_item+ ':' TYPE_COMMENT? block // | 'async' 'with' ','.with_item+ ':' TYPE_COMMENT? block
@ -6528,12 +6528,12 @@ with_stmt_rule(Parser *p)
D(fprintf(stderr, "%*c%s with_stmt[%d-%d]: %s failed!\n", p->level, ' ', D(fprintf(stderr, "%*c%s with_stmt[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_with_stmt_indent")); p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_with_stmt_indent"));
} }
{ // 'with' '(' ','.with_item+ ','? ')' ':' block { // 'with' '(' ','.with_item+ ','? ')' ':' TYPE_COMMENT? block
if (p->error_indicator) { if (p->error_indicator) {
p->level--; p->level--;
return NULL; return NULL;
} }
D(fprintf(stderr, "%*c> with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'with' '(' ','.with_item+ ','? ')' ':' block")); D(fprintf(stderr, "%*c> with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'with' '(' ','.with_item+ ','? ')' ':' TYPE_COMMENT? block"));
Token * _keyword; Token * _keyword;
Token * _literal; Token * _literal;
Token * _literal_1; Token * _literal_1;
@ -6542,6 +6542,7 @@ with_stmt_rule(Parser *p)
UNUSED(_opt_var); // Silence compiler warnings UNUSED(_opt_var); // Silence compiler warnings
asdl_withitem_seq* a; asdl_withitem_seq* a;
asdl_stmt_seq* b; asdl_stmt_seq* b;
void *tc;
if ( if (
(_keyword = _PyPegen_expect_token(p, 629)) // token='with' (_keyword = _PyPegen_expect_token(p, 629)) // token='with'
&& &&
@ -6555,10 +6556,12 @@ with_stmt_rule(Parser *p)
&& &&
(_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':'
&& &&
(tc = _PyPegen_expect_token(p, TYPE_COMMENT), !p->error_indicator) // TYPE_COMMENT?
&&
(b = block_rule(p)) // block (b = block_rule(p)) // block
) )
{ {
D(fprintf(stderr, "%*c+ with_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'with' '(' ','.with_item+ ','? ')' ':' block")); D(fprintf(stderr, "%*c+ with_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'with' '(' ','.with_item+ ','? ')' ':' TYPE_COMMENT? block"));
Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p);
if (_token == NULL) { if (_token == NULL) {
p->level--; p->level--;
@ -6568,7 +6571,7 @@ with_stmt_rule(Parser *p)
UNUSED(_end_lineno); // Only used by EXTRA macro UNUSED(_end_lineno); // Only used by EXTRA macro
int _end_col_offset = _token->end_col_offset; int _end_col_offset = _token->end_col_offset;
UNUSED(_end_col_offset); // Only used by EXTRA macro UNUSED(_end_col_offset); // Only used by EXTRA macro
_res = CHECK_VERSION ( stmt_ty , 9 , "Parenthesized context managers are" , _PyAST_With ( a , b , NULL , EXTRA ) ); _res = CHECK_VERSION ( stmt_ty , 9 , "Parenthesized context managers are" , _PyAST_With ( a , b , NEW_TYPE_COMMENT ( p , tc ) , EXTRA ) );
if (_res == NULL && PyErr_Occurred()) { if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1; p->error_indicator = 1;
p->level--; p->level--;
@ -6578,7 +6581,7 @@ with_stmt_rule(Parser *p)
} }
p->mark = _mark; p->mark = _mark;
D(fprintf(stderr, "%*c%s with_stmt[%d-%d]: %s failed!\n", p->level, ' ', D(fprintf(stderr, "%*c%s with_stmt[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'with' '(' ','.with_item+ ','? ')' ':' block")); p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'with' '(' ','.with_item+ ','? ')' ':' TYPE_COMMENT? block"));
} }
{ // 'with' ','.with_item+ ':' TYPE_COMMENT? block { // 'with' ','.with_item+ ':' TYPE_COMMENT? block
if (p->error_indicator) { if (p->error_indicator) {