From 4affc8a459940050e45c981486572278890dd648 Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Mon, 16 Mar 2020 16:54:34 -0700 Subject: [PATCH 1/2] Fix invalid type causing namedtuple errors in wrong files Fixes #8511. This is a workaround of #4987, where UnboundTypes can leak. --- mypy/semanal_namedtuple.py | 6 +++++- test-data/unit/check-namedtuple.test | 14 ++++++++++++++ test-data/unit/fine-grained.test | 4 ++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/mypy/semanal_namedtuple.py b/mypy/semanal_namedtuple.py index 14b85b04daded..17ca2114a8616 100644 --- a/mypy/semanal_namedtuple.py +++ b/mypy/semanal_namedtuple.py @@ -8,7 +8,8 @@ from typing_extensions import Final from mypy.types import ( - Type, TupleType, AnyType, TypeOfAny, TypeVarDef, CallableType, TypeType, TypeVarType + Type, TupleType, AnyType, TypeOfAny, TypeVarDef, CallableType, TypeType, TypeVarType, + UnboundType, ) from mypy.semanal_shared import ( SemanticAnalyzerInterface, set_callable_name, calculate_tuple_fallback, PRIORITY_FALLBACKS @@ -334,6 +335,9 @@ def parse_namedtuple_fields_with_types(self, nodes: List[Expression], context: C except TypeTranslationError: return self.fail_namedtuple_arg('Invalid field type', type_node) analyzed = self.api.anal_type(type) + # Workaround #4987 and avoid introducing a bogus UnboundType + if isinstance(analyzed, UnboundType): + analyzed = AnyType(TypeOfAny.from_error) # These should be all known, otherwise we would defer in visit_assignment_stmt(). if analyzed is None: return None diff --git a/test-data/unit/check-namedtuple.test b/test-data/unit/check-namedtuple.test index 41dd49cd76268..dfa9ddc4de425 100644 --- a/test-data/unit/check-namedtuple.test +++ b/test-data/unit/check-namedtuple.test @@ -948,3 +948,17 @@ class A: reveal_type(A().b) # N: Revealed type is 'Any' [builtins fixtures/tuple.pyi] + +[case testNamedTupleWrongfile] +from typing import NamedTuple +from b import Type1 +Type2 = NamedTuple('Type2', [('x', Type1)]) +[file b.py] +from typing import NamedTuple + +def foo(): + pass + +Type1 = NamedTuple('Type1', [('foo', foo)]) # type: ignore + +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test index f0e7a64380e7b..3ea6b31f379aa 100644 --- a/test-data/unit/fine-grained.test +++ b/test-data/unit/fine-grained.test @@ -8477,8 +8477,8 @@ m.py:4: note: See https://mypy.readthedocs.io/en/latest/common_issues.html#varia == m.py:4: error: Variable "a.A" is not valid as a type m.py:4: note: See https://mypy.readthedocs.io/en/latest/common_issues.html#variables-vs-type-aliases -m.py:5: note: Revealed type is 'A?' -m.py:7: note: Revealed type is 'A?' +m.py:5: note: Revealed type is 'Any' +m.py:7: note: Revealed type is 'Any' [case testAliasForwardFunctionDirect] # flags: --ignore-missing-imports From a9ddc47e7ccb5d0a77a8f509ef0db31280d7fd4b Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Tue, 17 Mar 2020 10:32:59 -0700 Subject: [PATCH 2/2] test better --- test-data/unit/check-namedtuple.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-namedtuple.test b/test-data/unit/check-namedtuple.test index dfa9ddc4de425..48d4bc3df3556 100644 --- a/test-data/unit/check-namedtuple.test +++ b/test-data/unit/check-namedtuple.test @@ -959,6 +959,6 @@ from typing import NamedTuple def foo(): pass -Type1 = NamedTuple('Type1', [('foo', foo)]) # type: ignore +Type1 = NamedTuple('Type1', [('foo', foo)]) # E: Function "b.foo" is not valid as a type # N: Perhaps you need "Callable[...]" or a callback protocol? [builtins fixtures/tuple.pyi]