-- Semantic analysis of named tuples

[case testSimpleNamedtuple]
from collections import namedtuple
N = namedtuple('N', ['a'])
def f() -> N: pass
[out]
MypyFile:1(
  ImportFrom:1(collections, [namedtuple])
  AssignmentStmt:2(
    NameExpr(N* [__main__.N])
    NamedTupleExpr:2(N, Tuple[Any]))
  FuncDef:3(
    f
    def () -> Tuple[Any, fallback=__main__.N]
    Block:3(
      PassStmt:3())))

[case testTwoItemNamedtuple]
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 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 ')
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 testNamedTupleWithItemTypes]
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 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'])
class A(N): pass
[out]
MypyFile:1(
  ImportFrom:1(collections, [namedtuple])
  AssignmentStmt:2(
    NameExpr(N* [__main__.N])
    NamedTupleExpr:2(N, Tuple[Any]))
  ClassDef:3(
    A
    TupleType(
      Tuple[Any, fallback=__main__.N])
    BaseType(
      __main__.N)
    PassStmt:3()))

[case testNamedTupleBaseClass2]
from collections import namedtuple
class A(namedtuple('N', ['x'])): pass
[out]
MypyFile:1(
  ImportFrom:1(collections, [namedtuple])
  ClassDef:2(
    A
    TupleType(
      Tuple[Any, fallback=__main__.N@2])
    BaseType(
      __main__.N@2)
    PassStmt:2()))

[case testNamedTupleBaseClassWithItemTypes]
from typing import NamedTuple
class A(NamedTuple('N', [('x', int)])): pass
[out]
MypyFile:1(
  ImportFrom:1(typing, [NamedTuple])
  ClassDef:2(
    A
    TupleType(
      Tuple[builtins.int, fallback=__main__.N@2])
    BaseType(
      __main__.N@2)
    PassStmt:2()))

-- Errors

[case testNamedTupleWithTooFewArguments]
from collections import namedtuple
N = namedtuple('N') # E: Too few arguments for namedtuple()

[case testNamedTupleWithInvalidName]
from collections import namedtuple
N = namedtuple(1, ['x']) # E: namedtuple() expects a string literal as the first argument

[case testNamedTupleWithInvalidItems]
from collections import namedtuple
N = namedtuple('N', 1) # E: List or tuple literal expected as the second argument to namedtuple()

[case testNamedTupleWithInvalidItems2]
from collections import namedtuple
N = namedtuple('N', ['x', 1]) # E: String literal expected as namedtuple() item

[case testNamedTupleWithUnderscoreItemName]
from collections import namedtuple
N = namedtuple('N', ['_fallback']) # E: namedtuple() field names cannot start with an underscore: _fallback

-- NOTE: The following code works at runtime but is not yet supported by mypy.
--       Keyword arguments may potentially be supported in the future.
[case testNamedTupleWithNonpositionalArgs]
from collections import namedtuple
N = namedtuple(typename='N', field_names=['x']) # E: Unexpected arguments to namedtuple()

[case testInvalidNamedTupleBaseClass]
from typing import NamedTuple
class A(NamedTuple('N', [1])): pass # E: Tuple expected as NamedTuple() field
class B(A): pass

[case testInvalidNamedTupleBaseClass2]
class A(NamedTuple('N', [1])): pass
class B(A): pass
[out]
main:1: error: Name 'NamedTuple' is not defined
main:1: error: Invalid base class
