Mypy: Crash with global type aliasing

Created on 18 May 2018  路  9Comments  路  Source: python/mypy

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
crash priority-0-high

Most helpful comment

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

All 9 comments

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.

Was this page helpful?
0 / 5 - 0 ratings