Repository: python/mypy

Issue:
Cannot find exec_module for _importlib_modulespec.exec_module with incremental
Still trying to get a test case, but here's the traceback:

```
ryan@DevPC-LX ~/blaze-py master $ mypy blaze
Traceback (most recent call last):
  File "/media/ryan/stuff/anaconda/bin/mypy", line 6, in <module>
    exec(compile(open(__file__).read(), __file__, 'exec'))
  File "/media/ryan/stuff/mypy/scripts/mypy", line 6, in <module>
    main(__file__)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/main.py", line 41, in main
    res = type_check_only(sources, bin_dir, options)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/main.py", line 86, in type_check_only
    options=options)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 183, in build
    dispatch(sources, manager)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1512, in dispatch
    process_graph(graph, manager)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1685, in process_graph
    process_fresh_scc(graph, prev_scc)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1754, in process_fresh_scc
    graph[id].fix_cross_refs()
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1300, in fix_cross_refs
    fixup_module_pass_one(self.tree, self.manager.modules)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 17, in fixup_module_pass_one
    node_fixer.visit_symbol_table(tree.names)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 82, in visit_symbol_table
    self.visit_type_info(value.node)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 51, in visit_type_info
    self.visit_symbol_table(info.names)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 75, in visit_symbol_table
    stnode = lookup_qualified_stnode(self.modules, cross_ref)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 244, in lookup_qualified_stnode
    assert key in names, "Cannot find %s for %s" % (key, name)
AssertionError: Cannot find exec_module for _importlib_modulespec.exec_module
ryan@DevPC-LX ~/blaze-py master $ 
```
Cannot find exec_module for _importlib_modulespec.exec_module with incremental
Still trying to get a test case, but here's the traceback:

```
ryan@DevPC-LX ~/blaze-py master $ mypy blaze
Traceback (most recent call last):
  File "/media/ryan/stuff/anaconda/bin/mypy", line 6, in <module>
    exec(compile(open(__file__).read(), __file__, 'exec'))
  File "/media/ryan/stuff/mypy/scripts/mypy", line 6, in <module>
    main(__file__)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/main.py", line 41, in main
    res = type_check_only(sources, bin_dir, options)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/main.py", line 86, in type_check_only
    options=options)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 183, in build
    dispatch(sources, manager)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1512, in dispatch
    process_graph(graph, manager)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1685, in process_graph
    process_fresh_scc(graph, prev_scc)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1754, in process_fresh_scc
    graph[id].fix_cross_refs()
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1300, in fix_cross_refs
    fixup_module_pass_one(self.tree, self.manager.modules)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 17, in fixup_module_pass_one
    node_fixer.visit_symbol_table(tree.names)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 82, in visit_symbol_table
    self.visit_type_info(value.node)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 51, in visit_type_info
    self.visit_symbol_table(info.names)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 75, in visit_symbol_table
    stnode = lookup_qualified_stnode(self.modules, cross_ref)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 244, in lookup_qualified_stnode
    assert key in names, "Cannot find %s for %s" % (key, name)
AssertionError: Cannot find exec_module for _importlib_modulespec.exec_module
ryan@DevPC-LX ~/blaze-py master $ 
```


Discussion:
Test case:

``` python
class A: pass
class B: pass
class C: pass

class X:
    attr: A
class Y:
    attr: B
class Z(X, Y):
    attr: C
```

Example:

```
ryan@DevPC-LX ~/blaze-mypy2 master $ mypy --fast-parser --python-version 3.6 -i x.py
x.py: note: In class "Z":
x.py:9: error: Definition of "attr" in base class "X" is incompatible with definition in base class "Y"
ryan@DevPC-LX ~/blaze-mypy2 master $ mypy --fast-parser --python-version 3.6 -i x.py
Traceback (most recent call last):
  File "/media/ryan/stuff/anaconda/bin/mypy", line 6, in <module>
    exec(compile(open(__file__).read(), __file__, 'exec'))
  File "/media/ryan/stuff/mypy/scripts/mypy", line 6, in <module>
    main(__file__)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/main.py", line 41, in main
    res = type_check_only(sources, bin_dir, options)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/main.py", line 86, in type_check_only
    options=options)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 183, in build
    dispatch(sources, manager)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1512, in dispatch
    process_graph(graph, manager)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1685, in process_graph
    process_fresh_scc(graph, prev_scc)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1754, in process_fresh_scc
    graph[id].fix_cross_refs()
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1300, in fix_cross_refs
    fixup_module_pass_one(self.tree, self.manager.modules)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 17, in fixup_module_pass_one
    node_fixer.visit_symbol_table(tree.names)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 82, in visit_symbol_table
    self.visit_type_info(value.node)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 51, in visit_type_info
    self.visit_symbol_table(info.names)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 75, in visit_symbol_table
    stnode = lookup_qualified_stnode(self.modules, cross_ref)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 244, in lookup_qualified_stnode
    assert key in names, "Cannot find %s for %s" % (key, name)
AssertionError: Cannot find module_repr for _importlib_modulespec.module_repr
ryan@DevPC-LX ~/blaze-mypy2 master $ 
```

Looks like this is new since 0.4.5. Perhaps you can bisect?

@gvanrossum First bad commit was https://github.com/python/mypy/commit/075a8da690aaa32e5f00e24bb763d92710646538, from #2304.

Also, here's a slightly smaller test case:

``` python
class A: pass
class B: pass

class X:
    attr: A
class Y:
    attr: B
class Z(X, Y): pass
```

The core bug seems to be when two different base classes define an attribute to be of different types.

I've been doing some research. This apparently has something to do with functions defined inside of conditionals inside classes, like:

``` python
class X:
    if sys.version_info >= (1, 2, 3):
        def f(self): pass
    else:
        def f(self): pass
```

Previously, only global functions went through the first pass of semantic analysis. Now, because of the changes in #2304, methods are also analyzed. Immediately returning from `FirstPass.visit_if_stmt` will work around the issue.

AAAAND THE BUG IS...this innocent line:

```
         func._fullname = sem.qualified_name(func.name())
```

Now methods are being evaluated, BUT `qualified_name` always returns a module-level name. Kind of anti-climatic...

Test case:

``` python
class A: pass
class B: pass
class C: pass

class X:
    attr: A
class Y:
    attr: B
class Z(X, Y):
    attr: C
```

Example:

```
ryan@DevPC-LX ~/blaze-mypy2 master $ mypy --fast-parser --python-version 3.6 -i x.py
x.py: note: In class "Z":
x.py:9: error: Definition of "attr" in base class "X" is incompatible with definition in base class "Y"
ryan@DevPC-LX ~/blaze-mypy2 master $ mypy --fast-parser --python-version 3.6 -i x.py
Traceback (most recent call last):
  File "/media/ryan/stuff/anaconda/bin/mypy", line 6, in <module>
    exec(compile(open(__file__).read(), __file__, 'exec'))
  File "/media/ryan/stuff/mypy/scripts/mypy", line 6, in <module>
    main(__file__)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/main.py", line 41, in main
    res = type_check_only(sources, bin_dir, options)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/main.py", line 86, in type_check_only
    options=options)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 183, in build
    dispatch(sources, manager)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1512, in dispatch
    process_graph(graph, manager)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1685, in process_graph
    process_fresh_scc(graph, prev_scc)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1754, in process_fresh_scc
    graph[id].fix_cross_refs()
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/build.py", line 1300, in fix_cross_refs
    fixup_module_pass_one(self.tree, self.manager.modules)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 17, in fixup_module_pass_one
    node_fixer.visit_symbol_table(tree.names)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 82, in visit_symbol_table
    self.visit_type_info(value.node)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 51, in visit_type_info
    self.visit_symbol_table(info.names)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 75, in visit_symbol_table
    stnode = lookup_qualified_stnode(self.modules, cross_ref)
  File "/media/stuff/anaconda/lib/python3.4/site-packages/mypy/fixup.py", line 244, in lookup_qualified_stnode
    assert key in names, "Cannot find %s for %s" % (key, name)
AssertionError: Cannot find module_repr for _importlib_modulespec.module_repr
ryan@DevPC-LX ~/blaze-mypy2 master $ 
```

Looks like this is new since 0.4.5. Perhaps you can bisect?

@gvanrossum First bad commit was https://github.com/python/mypy/commit/075a8da690aaa32e5f00e24bb763d92710646538, from #2304.

Also, here's a slightly smaller test case:

``` python
class A: pass
class B: pass

class X:
    attr: A
class Y:
    attr: B
class Z(X, Y): pass
```

The core bug seems to be when two different base classes define an attribute to be of different types.

I've been doing some research. This apparently has something to do with functions defined inside of conditionals inside classes, like:

``` python
class X:
    if sys.version_info >= (1, 2, 3):
        def f(self): pass
    else:
        def f(self): pass
```

Previously, only global functions went through the first pass of semantic analysis. Now, because of the changes in #2304, methods are also analyzed. Immediately returning from `FirstPass.visit_if_stmt` will work around the issue.

AAAAND THE BUG IS...this innocent line:

```
         func._fullname = sem.qualified_name(func.name())
```

Now methods are being evaluated, BUT `qualified_name` always returns a module-level name. Kind of anti-climatic...


Resolving patch:
diff --git a/mypy/semanal.py b/mypy/semanal.py
--- a/mypy/semanal.py
+++ b/mypy/semanal.py
@@ -2640,7 +2640,11 @@ def lookup_fully_qualified_or_none(self, name: str) -> Optional[SymbolTableNode]
         return n.names.get(parts[-1])
 
     def qualified_name(self, n: str) -> str:
-        return self.cur_mod_id + '.' + n
+        if self.type is not None:
+            base = self.type._fullname
+        else:
+            base = self.cur_mod_id
+        return base + '.' + n
 
     def enter(self) -> None:
         self.locals.append(SymbolTable())


Test patch:
diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test
--- a/test-data/unit/check-incremental.test
+++ b/test-data/unit/check-incremental.test
@@ -376,7 +376,7 @@ a = produce()
 accept_int(a.foo())
 
 [file mod2/__init__.py]
-from mod2.mod3 import CustomType 
+from mod2.mod3 import CustomType
 
 [file mod2/mod3/__init__.py]
 from mod2.mod3.mod4 import CustomType
@@ -407,13 +407,13 @@ tmp/mod1.py:6: error: Argument 1 to "accept_int" has incompatible type "str"; ex
 import mod1, mod2.mod3.mod5
 
 [file mod1.py]
-from mod2 import produce 
+from mod2 import produce
 def accept_int(x: int) -> None: pass
 a = produce()
 accept_int(a.foo())
 
 [file mod2/__init__.py]
-from mod2.mod3 import produce 
+from mod2.mod3 import produce
 
 [file mod2/mod3/__init__.py]
 from mod2.mod3.mod4 import CustomType
@@ -548,7 +548,7 @@ def func2() -> str:
 [out2]
 
 [case testIncrementalWithComplexDictExpression]
-import mod1 
+import mod1
 
 [file mod1.py]
 import mod1_private
@@ -570,7 +570,7 @@ my_dict = {
 [builtins fixtures/dict.pyi]
 
 [case testIncrementalWithComplexConstantExpressionNoAnnotation]
-import mod1 
+import mod1
 
 [file mod1.py]
 import mod1_private
@@ -1178,7 +1178,7 @@ def foo(a: str) -> None: pass
 
 [file client.py]
 import good
-import bad 
+import bad
 from good import foo
 foo(3)
 
@@ -1537,12 +1537,12 @@ tmp/foo.py:3: error: Argument 1 to "accept_int" has incompatible type "str"; exp
 import foo
 
 [file foo.py]
-from mid import Outer 
+from mid import Outer
 def accept_int(x: int) -> None: pass
 accept_int(Outer.MyTuple(1, "b", "c").a)
 
 [file mid.py]
-from bar import Outer 
+from bar import Outer
 
 [file bar.py]
 from typing import NamedTuple
@@ -1634,3 +1634,20 @@ a = None  # type: R
 from . import m
 R = m.R
 a = None  # type: R
+
+[case testIncrementalBaseClassAttributeConflict]
+class A: pass
+class B: pass
+
+class X:
+    attr = None  # type: A
+class Y:
+    attr = None  # type: B
+class Z(X, Y): pass
+[stale]
+[out]
+main: note: In class "Z":
+main:8: error: Definition of "attr" in base class "X" is incompatible with definition in base class "Y"
+[out2]
+main: note: In class "Z":
+main:8: error: Definition of "attr" in base class "X" is incompatible with definition in base class "Y"