Repository: python/mypy

Issue:
Unknown NotImplementedError?
Hi guys,

I'm using mypy 0.521 with Python3.5 on Windows.
I have a multi-module project that started throwing the following error:
```
Traceback (most recent call last):
  File "c:\python35\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "c:\python35\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Python35\Scripts\mypy.exe\__main__.py", line 9, in <module>
  File "c:\python35\lib\site-packages\mypy\__main__.py", line 7, in console_entry
    main(None)
  File "c:\python35\lib\site-packages\mypy\main.py", line 50, in main
    res = type_check_only(sources, bin_dir, options)
  File "c:\python35\lib\site-packages\mypy\main.py", line 97, in type_check_only
    options=options)
  File "c:\python35\lib\site-packages\mypy\build.py", line 196, in build
    graph = dispatch(sources, manager)
  File "c:\python35\lib\site-packages\mypy\build.py", line 1801, in dispatch
    process_graph(graph, manager)
  File "c:\python35\lib\site-packages\mypy\build.py", line 2044, in process_graph
    process_stale_scc(graph, scc, manager)
  File "c:\python35\lib\site-packages\mypy\build.py", line 2156, in process_stale_scc
    graph[id].write_cache()
  File "c:\python35\lib\site-packages\mypy\build.py", line 1782, in write_cache
    self.manager)
  File "c:\python35\lib\site-packages\mypy\build.py", line 1061, in write_cache
    data = tree.serialize()
  File "c:\python35\lib\site-packages\mypy\nodes.py", line 284, in serialize
    'names': self.names.serialize(self._fullname),
  File "c:\python35\lib\site-packages\mypy\nodes.py", line 2415, in serialize
    data[key] = value.serialize(fullname, key)
  File "c:\python35\lib\site-packages\mypy\nodes.py", line 2356, in serialize
    data['node'] = self.node.serialize()
  File "c:\python35\lib\site-packages\mypy\nodes.py", line 706, in serialize
    'type': None if self.type is None else self.type.serialize(),
  File "c:\python35\lib\site-packages\mypy\types.py", line 47, in serialize
    raise NotImplementedError('Cannot serialize {} instance'.format(self.__class__.__name__))
NotImplementedError: Cannot serialize PartialType instance
```
I have no idea what was added that started throwing this error.
Any ideas?


Discussion:
We'd like to see the source code that triggers this. Was there a filename and line number mentioned before/after the traceback?
Hey @gvanrossum ,
The above pasted error is the entire message, there are no files/line numbers mentioned.
Give me a little time and I'll find the difference and post it.
Hey @gvanrossum , finally got a small example that reproduces the error:

module **main.py**:
```python
# main.py
import external_module_1

def main() -> None:
    print(external_module_1.external_list[1])

if __name__ == "__main__":
    main()
```
module **external_module_0.py**:
```python
# external_module_0.py
import typing
import external_module_1

my_global_dict = {}

def external_func_0(reader: typing.Any) -> typing.Any:
    global my_global_dict
    
    print(external_module_1.external_list[1])
    
    my_global_dict[12] = 0
```
and module **external_module_1.py**:
```python
# external_module_0.py
import external_module_0

external_list = 2000 * [0]
```
Run with ```mypy main.py```.
By annotating either the global variable ```my_global_dict``` in module ```external_module_0.py``` or the global variable ```external_list``` in module ```external_module_1.py```, the error goes away.

Thanks! I will investigate this repro and report back.

OK, confirmed on master (and great job whittling it down to this simple repro!).

I further simplified the test case slightly: main.py is unneeded, you can just run `mypy external_module_1.py` to reproduce the same crash. Almost everything else is needed though: a partial involving a global and an import cycle, and a reference to a list in the other module.

The tricky bit of debugging will be to understand why the Partial type lingers under these circumstances.

(Also this *is* related to incremental mode, even though it's not running `mypy -i`: it's happening in serialization.)
I think I have a fix. There was a misindented statement. PR forthcoming (I need to turn the example into a test case.)

Resolving patch:
diff --git a/mypy/checker.py b/mypy/checker.py
--- a/mypy/checker.py
+++ b/mypy/checker.py
@@ -1989,7 +1989,7 @@ def try_infer_partial_type_from_indexed_assignment(
                         if not self.current_node_deferred:
                             var.type = self.named_generic_type('builtins.dict',
                                                                [full_key_type, full_value_type])
-                        del partial_types[var]
+                            del partial_types[var]
 
     def visit_expression_stmt(self, s: ExpressionStmt) -> None:
         self.expr_checker.accept(s.expr, allow_none_return=True, always_allow_any=True)


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
@@ -2951,3 +2951,21 @@ def foo(a: int, b: int) -> str:
 [out1]
 [out2]
 tmp/b.py:2: error: Incompatible return value type (got "int", expected "str")
+
+[case testCrashWithPartialGlobalAndCycle]
+import bar
+
+[file foo.py]
+import bar
+my_global_dict = {}  # type: ignore
+def external_func_0() -> None:
+    global my_global_dict
+    bar.external_list
+    my_global_dict[12] = 0
+
+[file bar.py]
+import foo
+
+external_list = [0]
+
+[builtins fixtures/dict.pyi]