Import statements
Import Statements
Loader Side Effects
An import statement instructs the Python import loader to perform several operations. For example, the statement from a.b import Foo as Bar
causes the following steps to be performed at runtime:
1. Load and execute module a
if it hasn’t previously been loaded. Cache a reference to a.
2. Load and execute submodule b
if it hasn’t previously been loaded.
3. Store a reference to submodule b
to the variable b
within module a
’s namespace.
4. Look up attribute Foo
within module b
.
5. Assign the value of attribute Foo
to a local variable called Bar
.
If another source file were to subsequently execute the statement import a
, it would observe b
in the namespace of a
as a side effect of step 3 in the the earlier import operation. Relying on such side effects leads to fragile code because a change in execution ordering or a modification to one module can break code in another module. Reliance on such side effects is therefore considered a bug by Pyright, which intentionally does not attempt to model such side effects.
Implicit Module Loads
Pyright models two loader side effects that are considered safe and are commonly used in Python code.
-
If an import statement targets a multi-part module name and does not use an alias, all modules within the multi-part module name are assumed to be loaded. For example, the statement
import a.b.c
is treated as though it is three back-to-back import statements:import a
,import a.b
andimport a.b.c
. This allows for subsequent use of all symbols ina
,a.b
, anda.b.c
. If an alias is used (e.g.import a.b.c as abc
), this is assumed to load only modulec
. A subsequentimport a
would not provide access toa.b
ora.b.c
. -
If an
__init__.py
file includes an import statement of the formfrom .a import b
, the local variablea
is assigned a reference to submodulea
. This statement form is treated as though it is two back-to-back import statements:from . import a
followed byfrom .a import b
.
Unsupported Loader Side Effects
All other module loader side effects are intentionally not modeled by Pyright and should not be relied upon in code. Examples include:
-
If one module contains the statement
import a.b
and a second module includesimport a
, the second module should not rely on the fact thata.b
is now accessible as a side effect of the first module’s import. -
If a module contains the statement
import a.b
in the global scope and a function that includes the statementimport a
orimport a.c
, the function should not assume that it can accessa.b
. This assumption might or might not be safe depending on execution order. -
If a module contains the statements
import a.b as foo
andimport a
, code within that module should not assume that it can accessa.b
. Such an assumption might be safe depending on the relative order of the statements and the order in which they are executed, but it leads to fragile code.