Skip to content

Commit 5166d39

Browse files
committed
Allow try/except in with block
1 parent 34ea0a5 commit 5166d39

File tree

8 files changed

+46
-25
lines changed

8 files changed

+46
-25
lines changed

Include/internal/pycore_compile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ int _PyCompile_PushFBlock(struct _PyCompiler *c, _Py_SourceLocation loc,
127127
void _PyCompile_PopFBlock(struct _PyCompiler *c, enum _PyCompile_FBlockType t,
128128
_PyJumpTargetLabel block_label);
129129
_PyCompile_FBlockInfo *_PyCompile_TopFBlock(struct _PyCompiler *c);
130+
bool _PyCompile_InExceptionHandler(struct _PyCompiler *c);
130131

131132
int _PyCompile_EnterScope(struct _PyCompiler *c, identifier name, int scope_type,
132133
void *key, int lineno, PyObject *private,

Include/internal/pycore_symtable.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ typedef struct _symtable_entry {
127127
unsigned ste_has_conditional_annotations : 1; /* true if block has conditionally executed annotations */
128128
unsigned ste_in_conditional_block : 1; /* set while we are inside a conditionally executed block */
129129
unsigned ste_in_try_block : 1; /* set while we are inside a try/except block */
130-
unsigned ste_in_with_block : 1; /* set while we are inside a with block */
131130
unsigned ste_in_unevaluated_annotation : 1; /* set while we are processing an annotation that will not be evaluated */
132131
int ste_comp_iter_expr; /* non-zero if visiting a comprehension range expression */
133132
_Py_SourceLocation ste_loc; /* source location of block */

Lib/test/test_import/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2756,6 +2756,22 @@ def test_try_except_eager_from(self):
27562756

27572757
self.assertTrue("test.test_import.data.lazy_imports.basic2" in sys.modules)
27582758

2759+
def test_lazy_with(self):
2760+
try:
2761+
import test.test_import.data.lazy_imports.lazy_with
2762+
except ImportError as e:
2763+
self.fail('lazy import failed')
2764+
2765+
self.assertFalse("test.test_import.data.lazy_imports.basic2" in sys.modules)
2766+
2767+
def test_lazy_with_from(self):
2768+
try:
2769+
import test.test_import.data.lazy_imports.lazy_with_from
2770+
except ImportError as e:
2771+
self.fail('lazy import failed')
2772+
2773+
self.assertFalse("test.test_import.data.lazy_imports.basic2" in sys.modules)
2774+
27592775
def test_lazy_import_func(self):
27602776
with self.assertRaises(SyntaxError):
27612777
import test.test_import.data.lazy_imports.lazy_import_func
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import contextlib
2+
with contextlib.nullcontext():
3+
lazy import test.test_import.data.lazy_imports.basic2
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import contextlib
2+
with contextlib.nullcontext():
3+
lazy import test.test_import.data.lazy_imports.basic2 as basic2

Python/codegen.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2857,8 +2857,6 @@ codegen_validate_lazy_import(compiler *c, location loc)
28572857
{
28582858
if (_PyCompile_ScopeType(c) != COMPILE_SCOPE_MODULE) {
28592859
return _PyCompile_Error(c, loc, "lazy imports only allowed in module scope");
2860-
} else if (_PyCompile_TopFBlock(c)) {
2861-
return _PyCompile_Error(c, loc, "cannot lazy import in a nested scope");
28622860
}
28632861

28642862
return SUCCESS;
@@ -2888,7 +2886,7 @@ codegen_import(compiler *c, stmt_ty s)
28882886
RETURN_IF_ERROR(codegen_validate_lazy_import(c, loc));
28892887
ADDOP_NAME_CUSTOM(c, loc, IMPORT_NAME, alias->name, names, 2, 1);
28902888
} else {
2891-
if (_PyCompile_TopFBlock(c) || _PyCompile_ScopeType(c) != COMPILE_SCOPE_MODULE) {
2889+
if (_PyCompile_InExceptionHandler(c) || _PyCompile_ScopeType(c) != COMPILE_SCOPE_MODULE) {
28922890
// force eager import in try/except block
28932891
ADDOP_NAME_CUSTOM(c, loc, IMPORT_NAME, alias->name, names, 2, 2);
28942892
} else {
@@ -2953,7 +2951,8 @@ codegen_from_import(compiler *c, stmt_ty s)
29532951
ADDOP_NAME_CUSTOM(c, LOC(s), IMPORT_NAME, from, names, 2, 1);
29542952
} else {
29552953
alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, 0);
2956-
if (_PyCompile_TopFBlock(c) || _PyCompile_ScopeType(c) != COMPILE_SCOPE_MODULE ||
2954+
if (_PyCompile_InExceptionHandler(c) ||
2955+
_PyCompile_ScopeType(c) != COMPILE_SCOPE_MODULE ||
29572956
PyUnicode_READ_CHAR(alias->name, 0) == '*') {
29582957
// forced non-lazy import due to try/except or import *
29592958
ADDOP_NAME_CUSTOM(c, LOC(s), IMPORT_NAME, from, names, 2, 2);

Python/compile.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,26 @@ _PyCompile_TopFBlock(compiler *c)
787787
return &c->u->u_fblock[c->u->u_nfblocks - 1];
788788
}
789789

790+
bool
791+
_PyCompile_InExceptionHandler(compiler *c)
792+
{
793+
for (Py_ssize_t i = c->u->u_nfblocks; i < c->u->u_nfblocks; i++) {
794+
fblockinfo *block = &c->u->u_fblock[i];
795+
switch (block->fb_type) {
796+
case COMPILE_FBLOCK_TRY_EXCEPT:
797+
case COMPILE_FBLOCK_FINALLY_TRY:
798+
case COMPILE_FBLOCK_FINALLY_END:
799+
case COMPILE_FBLOCK_EXCEPTION_HANDLER:
800+
case COMPILE_FBLOCK_EXCEPTION_GROUP_HANDLER:
801+
case COMPILE_FBLOCK_HANDLER_CLEANUP:
802+
return true;
803+
default:
804+
break;
805+
}
806+
}
807+
return false;
808+
}
809+
790810
void
791811
_PyCompile_DeferredAnnotations(compiler *c,
792812
PyObject **deferred_annotations,

Python/symtable.c

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,6 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
142142
ste->ste_has_conditional_annotations = 0;
143143
ste->ste_in_conditional_block = 0;
144144
ste->ste_in_try_block = 0;
145-
ste->ste_in_with_block = 0;
146145
ste->ste_in_unevaluated_annotation = 0;
147146
ste->ste_annotation_block = NULL;
148147

@@ -1756,13 +1755,6 @@ symtable_enter_type_param_block(struct symtable *st, identifier name,
17561755
#define LEAVE_TRY_BLOCK(ST) \
17571756
(ST)->st_cur->ste_in_try_block = in_try_block;
17581757

1759-
#define ENTER_WITH_BLOCK(ST) \
1760-
int in_with_block = (ST)->st_cur->ste_in_with_block; \
1761-
(ST)->st_cur->ste_in_with_block = 1;
1762-
1763-
#define LEAVE_WITH_BLOCK(ST) \
1764-
(ST)->st_cur->ste_in_with_block = in_with_block;
1765-
17661758
#define ENTER_RECURSIVE() \
17671759
if (Py_EnterRecursiveCall(" during compilation")) { \
17681760
return 0; \
@@ -1835,14 +1827,6 @@ check_lazy_import_context(struct symtable *st, stmt_ty s, const char* import_typ
18351827
return 0;
18361828
}
18371829

1838-
/* Check if inside with block */
1839-
if (st->st_cur->ste_in_with_block) {
1840-
PyErr_Format(PyExc_SyntaxError,
1841-
"lazy %s not allowed inside with blocks", import_type);
1842-
SET_ERROR_LOCATION(st->st_filename, LOCATION(s));
1843-
return 0;
1844-
}
1845-
18461830
/* Check if inside function scope */
18471831
if (st->st_cur->ste_type == FunctionBlock) {
18481832
PyErr_Format(PyExc_SyntaxError,
@@ -2258,10 +2242,8 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
22582242
break;
22592243
case With_kind: {
22602244
ENTER_CONDITIONAL_BLOCK(st);
2261-
ENTER_WITH_BLOCK(st);
22622245
VISIT_SEQ(st, withitem, s->v.With.items);
22632246
VISIT_SEQ(st, stmt, s->v.With.body);
2264-
LEAVE_WITH_BLOCK(st);
22652247
LEAVE_CONDITIONAL_BLOCK(st);
22662248
break;
22672249
}
@@ -2326,10 +2308,8 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
23262308
return 0;
23272309
}
23282310
ENTER_CONDITIONAL_BLOCK(st);
2329-
ENTER_WITH_BLOCK(st);
23302311
VISIT_SEQ(st, withitem, s->v.AsyncWith.items);
23312312
VISIT_SEQ(st, stmt, s->v.AsyncWith.body);
2332-
LEAVE_WITH_BLOCK(st);
23332313
LEAVE_CONDITIONAL_BLOCK(st);
23342314
break;
23352315
}

0 commit comments

Comments
 (0)