Description
Feature
If a global variable is created solely via an assignment in a class or function to a name declared as global, then treat that name as though that assignment was at module level.
Currently, importing of such a name reports an error.
As a related matter, if the name is annotated at the module level, but there is no assignment, treat that name as missing from the module.
Pitch
This will reflect the runtime behavior.
Mypy will have to assume that the assignment might or might not occur, just like if an assignment at module level is located in a conditional block. In the latter case, the type may be inferred from the first assignment that is seen, and later assignments can check for compatible types.
I propose that mypy treat all assignments to global variables be treated like at module level, for purpose of establishing the existence and types of module level variables. The order that the assignments are analyzed should be in a breadth-first traversal of class and function defs (i.e. process an entire body excluding nested bodies, then process these bodies).
You may want to label this as a bug?.
I am working on writing such breadth-first module traverser which will identify all names in all scopes in a file and where they are first assigned. It will handle assigns to variables declared global just as though they appeared at module level. So that will take care of this proposed feature, as well as other issues with local names that are referenced before they are assigned.
Here's an example:
X.py:
from Y import y1, y2, y3, y4
Y.py:
global y0
y0: float
y2: str
def f():
global y1, y2
y1 = 1
class C:
global y3, y4
y3 = 3
Output from mypy:
X.py:3:1: error: Module "Y" has no attribute "y1"
X.py:3:1: error: Module "Y" has no attribute "y3"
X.py:3:1: error: Module "Y" has no attribute "y4"
The imports of y1
and y3
should succeed. The imports of y0
, y2
and y4
should fail because no assignment appears anywhere. mypy is correct for y4
but incorrect for the others.