Allow try/except in with block

This commit is contained in:
Dino Viehland 2025-10-23 10:06:18 -07:00
parent 34ea0a5b1d
commit 5166d39584
8 changed files with 46 additions and 25 deletions

View file

@ -2857,8 +2857,6 @@ codegen_validate_lazy_import(compiler *c, location loc)
{
if (_PyCompile_ScopeType(c) != COMPILE_SCOPE_MODULE) {
return _PyCompile_Error(c, loc, "lazy imports only allowed in module scope");
} else if (_PyCompile_TopFBlock(c)) {
return _PyCompile_Error(c, loc, "cannot lazy import in a nested scope");
}
return SUCCESS;
@ -2888,7 +2886,7 @@ codegen_import(compiler *c, stmt_ty s)
RETURN_IF_ERROR(codegen_validate_lazy_import(c, loc));
ADDOP_NAME_CUSTOM(c, loc, IMPORT_NAME, alias->name, names, 2, 1);
} else {
if (_PyCompile_TopFBlock(c) || _PyCompile_ScopeType(c) != COMPILE_SCOPE_MODULE) {
if (_PyCompile_InExceptionHandler(c) || _PyCompile_ScopeType(c) != COMPILE_SCOPE_MODULE) {
// force eager import in try/except block
ADDOP_NAME_CUSTOM(c, loc, IMPORT_NAME, alias->name, names, 2, 2);
} else {
@ -2953,7 +2951,8 @@ codegen_from_import(compiler *c, stmt_ty s)
ADDOP_NAME_CUSTOM(c, LOC(s), IMPORT_NAME, from, names, 2, 1);
} else {
alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, 0);
if (_PyCompile_TopFBlock(c) || _PyCompile_ScopeType(c) != COMPILE_SCOPE_MODULE ||
if (_PyCompile_InExceptionHandler(c) ||
_PyCompile_ScopeType(c) != COMPILE_SCOPE_MODULE ||
PyUnicode_READ_CHAR(alias->name, 0) == '*') {
// forced non-lazy import due to try/except or import *
ADDOP_NAME_CUSTOM(c, LOC(s), IMPORT_NAME, from, names, 2, 2);

View file

@ -787,6 +787,26 @@ _PyCompile_TopFBlock(compiler *c)
return &c->u->u_fblock[c->u->u_nfblocks - 1];
}
bool
_PyCompile_InExceptionHandler(compiler *c)
{
for (Py_ssize_t i = c->u->u_nfblocks; i < c->u->u_nfblocks; i++) {
fblockinfo *block = &c->u->u_fblock[i];
switch (block->fb_type) {
case COMPILE_FBLOCK_TRY_EXCEPT:
case COMPILE_FBLOCK_FINALLY_TRY:
case COMPILE_FBLOCK_FINALLY_END:
case COMPILE_FBLOCK_EXCEPTION_HANDLER:
case COMPILE_FBLOCK_EXCEPTION_GROUP_HANDLER:
case COMPILE_FBLOCK_HANDLER_CLEANUP:
return true;
default:
break;
}
}
return false;
}
void
_PyCompile_DeferredAnnotations(compiler *c,
PyObject **deferred_annotations,

View file

@ -142,7 +142,6 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
ste->ste_has_conditional_annotations = 0;
ste->ste_in_conditional_block = 0;
ste->ste_in_try_block = 0;
ste->ste_in_with_block = 0;
ste->ste_in_unevaluated_annotation = 0;
ste->ste_annotation_block = NULL;
@ -1756,13 +1755,6 @@ symtable_enter_type_param_block(struct symtable *st, identifier name,
#define LEAVE_TRY_BLOCK(ST) \
(ST)->st_cur->ste_in_try_block = in_try_block;
#define ENTER_WITH_BLOCK(ST) \
int in_with_block = (ST)->st_cur->ste_in_with_block; \
(ST)->st_cur->ste_in_with_block = 1;
#define LEAVE_WITH_BLOCK(ST) \
(ST)->st_cur->ste_in_with_block = in_with_block;
#define ENTER_RECURSIVE() \
if (Py_EnterRecursiveCall(" during compilation")) { \
return 0; \
@ -1835,14 +1827,6 @@ check_lazy_import_context(struct symtable *st, stmt_ty s, const char* import_typ
return 0;
}
/* Check if inside with block */
if (st->st_cur->ste_in_with_block) {
PyErr_Format(PyExc_SyntaxError,
"lazy %s not allowed inside with blocks", import_type);
SET_ERROR_LOCATION(st->st_filename, LOCATION(s));
return 0;
}
/* Check if inside function scope */
if (st->st_cur->ste_type == FunctionBlock) {
PyErr_Format(PyExc_SyntaxError,
@ -2258,10 +2242,8 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
break;
case With_kind: {
ENTER_CONDITIONAL_BLOCK(st);
ENTER_WITH_BLOCK(st);
VISIT_SEQ(st, withitem, s->v.With.items);
VISIT_SEQ(st, stmt, s->v.With.body);
LEAVE_WITH_BLOCK(st);
LEAVE_CONDITIONAL_BLOCK(st);
break;
}
@ -2326,10 +2308,8 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
return 0;
}
ENTER_CONDITIONAL_BLOCK(st);
ENTER_WITH_BLOCK(st);
VISIT_SEQ(st, withitem, s->v.AsyncWith.items);
VISIT_SEQ(st, stmt, s->v.AsyncWith.body);
LEAVE_WITH_BLOCK(st);
LEAVE_CONDITIONAL_BLOCK(st);
break;
}