Syntax restrictions for lazy imports

This commit is contained in:
Pablo Galindo 2025-09-25 17:33:12 +01:00 committed by Dino Viehland
parent 07a633f1f4
commit 20b14d9ca4
3 changed files with 175 additions and 0 deletions

View file

@ -1747,6 +1747,13 @@ symtable_enter_type_param_block(struct symtable *st, identifier name,
#define LEAVE_CONDITIONAL_BLOCK(ST) \
(ST)->st_cur->ste_in_conditional_block = in_conditional_block;
#define ENTER_TRY_BLOCK(ST) \
int in_try_block = (ST)->st_cur->ste_in_try_block; \
(ST)->st_cur->ste_in_try_block = 1;
#define LEAVE_TRY_BLOCK(ST) \
(ST)->st_cur->ste_in_try_block = in_try_block;
#define ENTER_RECURSIVE() \
if (Py_EnterRecursiveCall(" during compilation")) { \
return 0; \
@ -1808,6 +1815,36 @@ check_import_from(struct symtable *st, stmt_ty s)
return 1;
}
static int
check_lazy_import_context(struct symtable *st, stmt_ty s, const char* import_type)
{
/* Check if inside try/except block */
if (st->st_cur->ste_in_try_block) {
PyErr_Format(PyExc_SyntaxError,
"lazy %s not allowed inside try/except 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,
"lazy %s not allowed inside functions", import_type);
SET_ERROR_LOCATION(st->st_filename, LOCATION(s));
return 0;
}
/* Check if inside class scope */
if (st->st_cur->ste_type == ClassBlock) {
PyErr_Format(PyExc_SyntaxError,
"lazy %s not allowed inside classes", import_type);
SET_ERROR_LOCATION(st->st_filename, LOCATION(s));
return 0;
}
return 1;
}
static bool
allows_top_level_await(struct symtable *st)
{
@ -2076,19 +2113,23 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
break;
case Try_kind: {
ENTER_CONDITIONAL_BLOCK(st);
ENTER_TRY_BLOCK(st);
VISIT_SEQ(st, stmt, s->v.Try.body);
VISIT_SEQ(st, excepthandler, s->v.Try.handlers);
VISIT_SEQ(st, stmt, s->v.Try.orelse);
VISIT_SEQ(st, stmt, s->v.Try.finalbody);
LEAVE_TRY_BLOCK(st);
LEAVE_CONDITIONAL_BLOCK(st);
break;
}
case TryStar_kind: {
ENTER_CONDITIONAL_BLOCK(st);
ENTER_TRY_BLOCK(st);
VISIT_SEQ(st, stmt, s->v.TryStar.body);
VISIT_SEQ(st, excepthandler, s->v.TryStar.handlers);
VISIT_SEQ(st, stmt, s->v.TryStar.orelse);
VISIT_SEQ(st, stmt, s->v.TryStar.finalbody);
LEAVE_TRY_BLOCK(st);
LEAVE_CONDITIONAL_BLOCK(st);
break;
}
@ -2098,9 +2139,29 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
VISIT(st, expr, s->v.Assert.msg);
break;
case Import_kind:
if (s->v.Import.is_lazy) {
if (!check_lazy_import_context(st, s, "import")) {
return 0;
}
}
VISIT_SEQ(st, alias, s->v.Import.names);
break;
case ImportFrom_kind:
if (s->v.ImportFrom.is_lazy) {
if (!check_lazy_import_context(st, s, "from ... import")) {
return 0;
}
/* Check for import * */
for (Py_ssize_t i = 0; i < asdl_seq_LEN(s->v.ImportFrom.names); i++) {
alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i);
if (alias->name && _PyUnicode_EqualToASCIIString(alias->name, "*")) {
PyErr_SetString(PyExc_SyntaxError, "lazy from ... import * is not allowed");
SET_ERROR_LOCATION(st->st_filename, LOCATION(s));
return 0;
}
}
}
VISIT_SEQ(st, alias, s->v.ImportFrom.names);
if (!check_import_from(st, s)) {
return 0;