Closed
Description
from typing import NamedTuple, Union
class Person(NamedTuple):
name: Union[str, "NamePair"]
class NamePair(NamedTuple):
first: str
last: str
print(Person(name=NamePair(first="John", last="Doe")))
# Person(name=NamePair(first='John', last='Doe'))
Works fine in Python 3.6, but in mypy:
mypy_breaks.py:10: error: INTERNAL ERROR -- please report a bug at https://github.com/python/mypy/issues version: 0.521
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.6/bin/mypy", line 11, in <module>
sys.exit(console_entry())
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/__main__.py", line 7, in console_entry
main(None)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/main.py", line 50, in main
res = type_check_only(sources, bin_dir, options)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/main.py", line 97, in type_check_only
options=options)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/build.py", line 196, in build
graph = dispatch(sources, manager)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/build.py", line 1801, in dispatch
process_graph(graph, manager)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/build.py", line 2044, in process_graph
process_stale_scc(graph, scc, manager)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/build.py", line 2147, in process_stale_scc
graph[id].type_check_first_pass()
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/build.py", line 1716, in type_check_first_pass
self.type_checker.check_first_pass()
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checker.py", line 185, in check_first_pass
self.accept(d)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checker.py", line 273, in accept
stmt.accept(self)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/nodes.py", line 829, in accept
return visitor.visit_expression_stmt(self)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checker.py", line 1883, in visit_expression_stmt
self.expr_checker.accept(s.expr, allow_none_return=True, always_allow_any=True)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkexpr.py", line 2209, in accept
typ = self.visit_call_expr(node, allow_none_return=True)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkexpr.py", line 247, in visit_call_expr
ret_type = self.check_call_expr_with_callee_type(callee_type, e, fullname, object_type)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkexpr.py", line 459, in check_call_expr_with_callee_type
object_type=object_type)[0]
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkexpr.py", line 519, in check_call
callee, args, arg_kinds, formal_to_actual)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkexpr.py", line 675, in infer_arg_types_in_context2
res[ai] = self.accept(args[ai], callee.arg_types[i])
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkexpr.py", line 2213, in accept
typ = node.accept(self)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/nodes.py", line 1307, in accept
return visitor.visit_call_expr(self)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkexpr.py", line 215, in visit_call_expr
callee_type = self.accept(e.callee, always_allow_any=True)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkexpr.py", line 2213, in accept
typ = node.accept(self)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/nodes.py", line 1219, in accept
return visitor.visit_name_expr(self)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkexpr.py", line 128, in visit_name_expr
result = self.analyze_ref_expr(e)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkexpr.py", line 156, in analyze_ref_expr
result = type_object_type(node, self.named_type)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkmember.py", line 525, in type_object_type
return type_object_type_from_function(init_method, info, fallback)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkmember.py", line 530, in type_object_type_from_function
signature = bind_self(function_type(init_or_new, fallback))
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkmember.py", line 664, in bind_self
arg_types = [expand(x) for x in func.arg_types[1:]]
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkmember.py", line 664, in <listcomp>
arg_types = [expand(x) for x in func.arg_types[1:]]
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/checkmember.py", line 662, in expand
return expand_type(target, {func.variables[0].id: typearg})
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/expandtype.py", line 16, in expand_type
return typ.accept(ExpandTypeVisitor(env))
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/types.py", line 1114, in accept
return visitor.visit_union_type(self)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/expandtype.py", line 117, in visit_union_type
return UnionType.make_simplified_union(self.expand_types(t.items), t.line, t.column)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/types.py", line 1096, in make_simplified_union
if (i != j and is_proper_subtype(tj, ti)):
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/subtypes.py", line 569, in is_proper_subtype
return left.accept(ProperSubtypeVisitor(right))
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/types.py", line 435, in accept
return visitor.visit_instance(self)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mypy/subtypes.py", line 605, in visit_instance
for base in left.type.mro:
TypeError: 'NoneType' object is not iterable
Interestingly not an issue if I break the forward-reference
from typing import NamedTuple, Union
class NamePair(NamedTuple):
first: str
last: str
class Person(NamedTuple):
name: Union[str, "NamePair"]
print(Person(name=NamePair(first="John", last="Doe"))) # mypy works fine
or if I switch to using classes
from typing import NamedTuple, Union
class Person(NamedTuple):
name: Union[str, "NamePair"]
class NamePair:
def __init__(self, first: str, last: str) -> None:
self.first = first
self.last = last
print(Person(name=NamePair(first="John", last="Doe"))) # mypy works fine
or if I drop the union typing
from typing import NamedTuple, Union
class Person(NamedTuple):
name: "NamePair"
class NamePair(NamedTuple):
first: str
last: str
print(Person(name=NamePair(first="John", last="Doe"))) # mypy works fine
including by using Optional
from typing import NamedTuple, Optional
class Person(NamedTuple):
name: Optional["NamePair"]
class NamePair(NamedTuple):
first: str
last: str
print(Person(name=NamePair(first="John", last="Doe"))) # mypy works fine