A Hacker Schooler hit an interesting bug today: her program would sometimes emit the message SyntaxWarning: import * only allowed at module level
. I had never seen a SyntaxWarning
before, so I decided to dig in.
The wording of the warning is strange: it says that star-import is only allowed at the module level, but it’s not a syntax error, just a warning. In fact, you can use a star-import in a scope that isn’t a module (in Python 2):
1 2 3 4 5 6 7 |
|
The Python spec gives some more details:
The from form with * may only occur in a module scope. If the wild card form of import — import * — is used in a function and the function contains or is a nested block with free variables, the compiler will raise a SyntaxError.
Just having import *
in a function isn’t enough to raise a syntax error – we also need free variables. The Python execution model refers to three kinds of variables, ‘local,’ ‘global,’ and ‘free’, defined as follows:
If a name is bound in a block, it is a local variable of that block. If a name is bound at the module level, it is a global variable. (The variables of the module code block are local and global.) If a variable is used in a code block but not defined there, it is a free variable.
Now we can see how to trigger a syntax error from our syntax warning:
1 2 3 4 5 6 7 8 9 |
|
and similarly,
1 2 3 4 5 6 7 8 9 |
|
As Python programmers, we’re used to our lovely dynamic language, and it’s unusual to hit compile-time constraints. As Amy Hanlon points out, it’s particularly weird to hit a compile-time error for code that wouldn’t raise a NameError when it ran – randint
would indeed be in one
’s namespace if the import-star had executed.
But we can’t run code that doesn’t compile, and in this case the compiler doesn’t have enough information to determine what bytecode to emit. There are different opcodes for loading and storing each of global, free, and local variables. A variable’s status as global, free, or local must be determined at compile time and then stored in the symbol table.
To investigate this, let’s look at minor variations on this code snippet and disassemble them.
1 2 3 4 5 6 7 8 9 10 11 |
|
First, when x
is local, the compiler emits STORE_FAST
in the assignment statement and LOAD_FAST
to load it, marked with arrows below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
When x
is global, the compiler emits LOAD_GLOBAL
to load it. I think the assignment is STORE_FAST
again, but it’s not pictured here because the assignment is outside the function and thus not disassembled.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Finally, when x
is nonlocal, the compiler notices that we’ll need a closure, and emits the opcodes LOAD_CLOSURE
, MAKE_CLOSURE
, and later LOAD_DEREF
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Let’s now return to a case that throws a syntax error.
1 2 3 4 5 6 7 8 9 |
|
I’d love to show what the disassembled bytecode for this one looks like, but we can’t do that because there is no bytecode! We got a compile-time error, so there’s nothing here.
Further reading
Everything I know about symbol tables I learned from Eli Bendersky’s blog. I’ve skipped some complexity in the implementation that Eli covers.
ack
ing through the source code of CPython for the text of the error message leads us right to symtable.c
, which is exactly where we’d expect this message to be emitted. The function check_unoptimized
shows where the syntax error gets thrown (and shows another illegal construct, too – but we’ll leave that one as an exercise for the reader).
p.s. In Python 3, import *
anywhere other than a module is just an unqualified syntax error – none of this messing around with the symbol table.