This was originally discovered through the connection package in cpython, but I have a more minimal repro here:
def foo():
global myglobal
from typing import Any # can be any type, as long as the next line is a type alias
myglobal = Any
It seems that when we look it up, it is in the global declarations, but not not found in the globals.
Traceback:
test.py:4: error: INTERNAL ERROR -- please report a bug at https://github.com/python/mypy/issues version: 0.600+dev-36b036bd966896f9c8ab9773f89763766e485792
Traceback (most recent call last):
File "C:\Python36\lib\runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "C:\Python36\lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Users\ethanhs\Documents\mypy\mypy\__main__.py", line 11, in <module>
main(None)
File "C:\Users\ethanhs\Documents\mypy\mypy\main.py", line 91, in main
res = type_check_only(sources, bin_dir, options, flush_errors, fscache) # noqa
File "C:\Users\ethanhs\Documents\mypy\mypy\main.py", line 148, in type_check_only
fscache=fscache)
File "C:\Users\ethanhs\Documents\mypy\mypy\build.py", line 185, in build
flush_errors, fscache)
File "C:\Users\ethanhs\Documents\mypy\mypy\build.py", line 285, in _build
graph = dispatch(sources, manager)
File "C:\Users\ethanhs\Documents\mypy\mypy\build.py", line 2420, in dispatch
process_graph(graph, manager)
File "C:\Users\ethanhs\Documents\mypy\mypy\build.py", line 2713, in process_graph
process_stale_scc(graph, scc, manager)
File "C:\Users\ethanhs\Documents\mypy\mypy\build.py", line 2823, in process_stale_scc
graph[id].semantic_analysis()
File "C:\Users\ethanhs\Documents\mypy\mypy\build.py", line 2038, in semantic_analysis
self.manager.semantic_analyzer.visit_file(self.tree, self.xpath, self.options, patches)
File "C:\Users\ethanhs\Documents\mypy\mypy\semanal.py", line 297, in visit_file
self.accept(d)
File "C:\Users\ethanhs\Documents\mypy\mypy\semanal.py", line 3235, in accept
node.accept(self)
File "C:\Users\ethanhs\Documents\mypy\mypy\nodes.py", line 583, in accept
return visitor.visit_func_def(self)
File "C:\Users\ethanhs\Documents\mypy\mypy\semanal.py", line 366, in visit_func_def
self._visit_func_def(defn)
File "C:\Users\ethanhs\Documents\mypy\mypy\semanal.py", line 427, in _visit_func_def
self.analyze_function(defn)
File "C:\Users\ethanhs\Documents\mypy\mypy\semanal.py", line 652, in analyze_function
defn.body.accept(self)
File "C:\Users\ethanhs\Documents\mypy\mypy\nodes.py", line 865, in accept
return visitor.visit_block(self)
File "C:\Users\ethanhs\Documents\mypy\mypy\semanal.py", line 1537, in visit_block
self.accept(s)
File "C:\Users\ethanhs\Documents\mypy\mypy\semanal.py", line 3235, in accept
node.accept(self)
File "C:\Users\ethanhs\Documents\mypy\mypy\nodes.py", line 913, in accept
return visitor.visit_assignment_stmt(self)
File "C:\Users\ethanhs\Documents\mypy\mypy\semanal.py", line 1616, in visit_assignment_stmt
self.check_and_set_up_type_alias(s)
File "C:\Users\ethanhs\Documents\mypy\mypy\semanal.py", line 1737, in check_and_set_up_type_alias
assert node is not None
AssertionError:
test.py:4: : note: use --pdb to drop into pdb
According to your example, should myglobal an alias of Any from the start of the file, or after the first call to foo?
Well, I think the global statement wouldn't be executed until foo is called, so I would say the name gets added to the global namespace after the first call to foo. But I could be wrong.
I'd say what happens at runtime is irrelevant. I think mypy should most likely not ever consider this as a definition of an alias (global or otherwise); it should perhaps flag this as an error (though arguably it should just leave it alone); and it should definitely not crash.
So I think that we (actually not we, the lead developers) should agree on a
decision, and then this crash can be fixed according to that decision.
By the way, I agree with @gvanrossum. It should be ignored. It should cause
neither an error nor a crash.
OK, so extending the example:
def foo():
global myglobal
from typing import Any # can be any type, as long as the next line is a type alias
myglobal = Any # NO ERROR HERE
x: myglobal # THIS WOULD BE AN ERROR
y: myglobal # THIS WOULD ALSO BE AN ERROR
I can live with that. It's somewhat similar to this example (which passes without errors):
class C:
x: object
C.x = Any
I think that we should do the same with nonlocal.
I think #5732 is related to this issue.
Since #5732, @gvanrossum's example actually turns into this:
def foo():
global myglobal
from typing import Any # can be any type, as long as the next line is a type alias
myglobal = Any # THIS WOULD BE AN ERROR TOO
x: myglobal # THIS WOULD BE AN ERROR
y: myglobal # THIS WOULD ALSO BE AN ERROR
How should we proceed? Fixing the other issue before this, or fixing this with accepting the behaviour mentioned in the other one?
This seems to work now. It may have been fixed by the new semantic analyzer.
Most helpful comment
OK, so extending the example:
I can live with that. It's somewhat similar to this example (which passes without errors):