Skip to content

Commit e4d99c6

Browse files
srittauilevkivskyi
authored andcommitted
Support NamedTuple class syntax in all stubs (#7646)
Previously, it was not supported in stubs when checking in Python 2.7 or 3.5 mode. Closes: #3464
1 parent cef7a63 commit e4d99c6

File tree

3 files changed

+28
-6
lines changed

3 files changed

+28
-6
lines changed

mypy/semanal.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,8 @@ def analyze_namedtuple_classdef(self, defn: ClassDef) -> bool:
11091109
# in the named tuple class body.
11101110
is_named_tuple, info = True, defn.info # type: bool, Optional[TypeInfo]
11111111
else:
1112-
is_named_tuple, info = self.named_tuple_analyzer.analyze_namedtuple_classdef(defn)
1112+
is_named_tuple, info = self.named_tuple_analyzer.analyze_namedtuple_classdef(
1113+
defn, self.is_stub_file)
11131114
if is_named_tuple:
11141115
if info is None:
11151116
self.mark_incomplete(defn.name, defn)

mypy/semanal_namedtuple.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ def __init__(self, options: Options, api: SemanticAnalyzerInterface) -> None:
4141
self.options = options
4242
self.api = api
4343

44-
def analyze_namedtuple_classdef(self, defn: ClassDef) -> Tuple[bool, Optional[TypeInfo]]:
44+
def analyze_namedtuple_classdef(self, defn: ClassDef, is_stub_file: bool
45+
) -> Tuple[bool, Optional[TypeInfo]]:
4546
"""Analyze if given class definition can be a named tuple definition.
4647
4748
Return a tuple where first item indicates whether this can possibly be a named tuple,
@@ -52,7 +53,7 @@ def analyze_namedtuple_classdef(self, defn: ClassDef) -> Tuple[bool, Optional[Ty
5253
if isinstance(base_expr, RefExpr):
5354
self.api.accept(base_expr)
5455
if base_expr.fullname == 'typing.NamedTuple':
55-
result = self.check_namedtuple_classdef(defn)
56+
result = self.check_namedtuple_classdef(defn, is_stub_file)
5657
if result is None:
5758
# This is a valid named tuple, but some types are incomplete.
5859
return True, None
@@ -68,8 +69,10 @@ def analyze_namedtuple_classdef(self, defn: ClassDef) -> Tuple[bool, Optional[Ty
6869
# This can't be a valid named tuple.
6970
return False, None
7071

71-
def check_namedtuple_classdef(
72-
self, defn: ClassDef) -> Optional[Tuple[List[str], List[Type], Dict[str, Expression]]]:
72+
def check_namedtuple_classdef(self, defn: ClassDef, is_stub_file: bool
73+
) -> Optional[Tuple[List[str],
74+
List[Type],
75+
Dict[str, Expression]]]:
7376
"""Parse and validate fields in named tuple class definition.
7477
7578
Return a three tuple:
@@ -78,7 +81,7 @@ def check_namedtuple_classdef(
7881
* field default values
7982
or None, if any of the types are not ready.
8083
"""
81-
if self.options.python_version < (3, 6):
84+
if self.options.python_version < (3, 6) and not is_stub_file:
8285
self.fail('NamedTuple class syntax is only supported in Python 3.6', defn)
8386
return [], [], {}
8487
if len(defn.base_type_exprs) > 1:

test-data/unit/check-namedtuple.test

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,24 @@ x.x
4444
x.y
4545
x.z # E: "X" has no attribute "z"
4646

47+
[case testNamedTupleClassPython35]
48+
# flags: --python-version 3.5
49+
from typing import NamedTuple
50+
51+
class A(NamedTuple):
52+
x = 3 # type: int
53+
[out]
54+
main:4: error: NamedTuple class syntax is only supported in Python 3.6
55+
56+
[case testNamedTupleClassInStubPython35]
57+
# flags: --python-version 3.5
58+
import foo
59+
60+
[file foo.pyi]
61+
from typing import NamedTuple
62+
63+
class A(NamedTuple):
64+
x: int
4765

4866
[case testNamedTupleAttributesAreReadOnly]
4967
from collections import namedtuple

0 commit comments

Comments
 (0)