From 0349d10bc756a390b735b016241c582d6abb5998 Mon Sep 17 00:00:00 2001 From: Alex Jurkiewicz Date: Mon, 17 Oct 2016 12:40:50 +1100 Subject: [PATCH 1/5] Allow tuples as second argument to namedtuple --- mypy/semanal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index ea195b5fe5ca..7910a7429b08 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -1634,14 +1634,14 @@ def parse_namedtuple_args(self, call: CallExpr, "namedtuple() expects a string literal as the first argument", call) types = [] # type: List[Type] ok = True - if not isinstance(args[1], ListExpr): + if not isinstance(args[1], (ListExpr, TupleExpr)): if (fullname == 'collections.namedtuple' and isinstance(args[1], (StrExpr, BytesExpr, UnicodeExpr))): str_expr = cast(StrExpr, args[1]) items = str_expr.value.replace(',', ' ').split() else: return self.fail_namedtuple_arg( - "List literal expected as the second argument to namedtuple()", call) + "List or tuple literal expected as the second argument to namedtuple()", call) else: listexpr = args[1] if fullname == 'collections.namedtuple': From 62eb227e5f57023bc923bda3012a081f03676147 Mon Sep 17 00:00:00 2001 From: Alex Jurkiewicz Date: Mon, 17 Oct 2016 14:57:30 +1100 Subject: [PATCH 2/5] correct existing test --- test-data/unit/semanal-namedtuple.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/semanal-namedtuple.test b/test-data/unit/semanal-namedtuple.test index 9ff9f6af6e8a..7daf84723eab 100644 --- a/test-data/unit/semanal-namedtuple.test +++ b/test-data/unit/semanal-namedtuple.test @@ -121,7 +121,7 @@ N = namedtuple(1, ['x']) # E: namedtuple() expects a string literal as the first [case testNamedTupleWithInvalidItems] from collections import namedtuple -N = namedtuple('N', 1) # E: List literal expected as the second argument to namedtuple() +N = namedtuple('N', 1) # E: List or Tuple literal expected as the second argument to namedtuple() [case testNamedTupleWithInvalidItems2] from collections import namedtuple From 889b45a16657a4d9e13e0675086bf2536e19a19d Mon Sep 17 00:00:00 2001 From: Alex Jurkiewicz Date: Mon, 17 Oct 2016 14:57:35 +1100 Subject: [PATCH 3/5] Add a new test --- test-data/unit/semanal-namedtuple.test | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test-data/unit/semanal-namedtuple.test b/test-data/unit/semanal-namedtuple.test index 7daf84723eab..2d306fc40a4b 100644 --- a/test-data/unit/semanal-namedtuple.test +++ b/test-data/unit/semanal-namedtuple.test @@ -32,6 +32,22 @@ MypyFile:1( Block:3( PassStmt:3()))) +[case testTwoItemNamedtupleWithTupleFieldNames] +from collections import namedtuple +N = namedtuple('N', ('a', 'xyz')) +def f() -> N: pass +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[Any, Any])) + FuncDef:3( + f + def () -> Tuple[Any, Any, fallback=__main__.N] + Block:3( + PassStmt:3()))) + [case testTwoItemNamedtupleWithShorthandSyntax] from collections import namedtuple N = namedtuple('N', ' a xyz ') From 0c1740174fa8b382fdd1cf79d6467d13cc022877 Mon Sep 17 00:00:00 2001 From: Alex Jurkiewicz Date: Mon, 17 Oct 2016 15:03:40 +1100 Subject: [PATCH 4/5] typo --- test-data/unit/semanal-namedtuple.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/semanal-namedtuple.test b/test-data/unit/semanal-namedtuple.test index 2d306fc40a4b..4ceb085857a1 100644 --- a/test-data/unit/semanal-namedtuple.test +++ b/test-data/unit/semanal-namedtuple.test @@ -137,7 +137,7 @@ N = namedtuple(1, ['x']) # E: namedtuple() expects a string literal as the first [case testNamedTupleWithInvalidItems] from collections import namedtuple -N = namedtuple('N', 1) # E: List or Tuple literal expected as the second argument to namedtuple() +N = namedtuple('N', 1) # E: List or tuple literal expected as the second argument to namedtuple() [case testNamedTupleWithInvalidItems2] from collections import namedtuple From 31c39d546d1c5ff9fdea484d27668b4e0804e480 Mon Sep 17 00:00:00 2001 From: Alex Jurkiewicz Date: Tue, 18 Oct 2016 08:54:46 +1100 Subject: [PATCH 5/5] Add higher level tests and also check typing.NamedTuple --- test-data/unit/check-namedtuple.test | 24 ++++++++++++++++++++++++ test-data/unit/semanal-namedtuple.test | 11 +++++++++++ 2 files changed, 35 insertions(+) diff --git a/test-data/unit/check-namedtuple.test b/test-data/unit/check-namedtuple.test index d8beaf62604e..c41cc5a916fd 100644 --- a/test-data/unit/check-namedtuple.test +++ b/test-data/unit/check-namedtuple.test @@ -9,6 +9,17 @@ a = x[1] a, b, c = x # E: Need more than 2 values to unpack (3 expected) x[2] # E: Tuple index out of range +[case testNamedTupleWithTupleFieldNamesUsedAsTuple] +from collections import namedtuple + +X = namedtuple('X', ('x', 'y')) +x = None # type: X +a, b = x +b = x[0] +a = x[1] +a, b, c = x # E: Need more than 2 values to unpack (3 expected) +x[2] # E: Tuple index out of range + [case testNamedTupleNoUnderscoreFields] from collections import namedtuple @@ -82,6 +93,19 @@ x, y = n x = y # E: Incompatible types in assignment (expression has type "str", variable has type "int") +[case testNamedTupleWithTupleFieldNamesWithItemTypes] +from typing import NamedTuple +N = NamedTuple('N', (('a', int), + ('b', str))) +n = N(1, 'x') +s = n.a # type: str # E: Incompatible types in assignment (expression has type "int", \ + variable has type "str") +i = n.b # type: int # E: Incompatible types in assignment (expression has type "str", \ + variable has type "int") +x, y = n +x = y # E: Incompatible types in assignment (expression has type "str", variable has type "int") + + [case testNamedTupleConstructorArgumentTypes] from typing import NamedTuple N = NamedTuple('N', [('a', int), diff --git a/test-data/unit/semanal-namedtuple.test b/test-data/unit/semanal-namedtuple.test index 4ceb085857a1..bb2592004908 100644 --- a/test-data/unit/semanal-namedtuple.test +++ b/test-data/unit/semanal-namedtuple.test @@ -75,6 +75,17 @@ MypyFile:1( NameExpr(N* [__main__.N]) NamedTupleExpr:2(N, Tuple[builtins.int, builtins.str]))) +[case testNamedTupleWithTupleFieldNamesWithItemTypes] +from typing import NamedTuple +N = NamedTuple('N', (('a', int), + ('b', str))) +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[builtins.int, builtins.str]))) + [case testNamedTupleBaseClass] from collections import namedtuple N = namedtuple('N', ['x'])