ruff/crates/ty_python_semantic/resources/mdtest/named_tuple.md
2025-05-03 19:49:15 +02:00

2.5 KiB

NamedTuple

NamedTuple is a type-safe way to define named tuples — a tuple where each field can be accessed by name, and not just by its numeric position within the tuple:

typing.NamedTuple

Basics

from typing import NamedTuple

class Person(NamedTuple):
    id: int
    name: str
    age: int | None = None

alice = Person(1, "Alice", 42)
alice = Person(id=1, name="Alice", age=42)
bob = Person(2, "Bob")
bob = Person(id=2, name="Bob")

reveal_type(alice.id)  # revealed: int
reveal_type(alice.name)  # revealed: str
reveal_type(alice.age)  # revealed: int | None

# TODO: These should reveal the types of the fields
reveal_type(alice[0])  # revealed: Unknown
reveal_type(alice[1])  # revealed: Unknown
reveal_type(alice[2])  # revealed: Unknown

# error: [missing-argument]
Person(3)

# error: [too-many-positional-arguments]
Person(3, "Eve", 99, "extra")

# error: [invalid-argument-type]
Person(id="3", name="Eve")

Alternative functional syntax:

Person2 = NamedTuple("Person", [("id", int), ("name", str)])
alice2 = Person2(1, "Alice")

# TODO: should be an error
Person2(1)

reveal_type(alice2.id)  # revealed: @Todo(GenericAlias instance)
reveal_type(alice2.name)  # revealed: @Todo(GenericAlias instance)

Multiple Inheritance

Multiple inheritance is not supported for NamedTuple classes:

from typing import NamedTuple

# This should ideally emit a diagnostic
class C(NamedTuple, object):
    id: int
    name: str

Inheriting from a NamedTuple

Inheriting from a NamedTuple is supported, but new fields on the subclass will not be part of the synthesized __new__ signature:

from typing import NamedTuple

class User(NamedTuple):
    id: int
    name: str

class SuperUser(User):
    level: int

# This is fine:
alice = SuperUser(1, "Alice")
reveal_type(alice.level)  # revealed: int

# This is an error because `level` is not part of the signature:
# error: [too-many-positional-arguments]
alice = SuperUser(1, "Alice", 3)

Generic named tuples

[environment]
python-version = "3.12"
from typing import NamedTuple

class Property[T](NamedTuple):
    name: str
    value: T

# TODO: this should be supported (no error, revealed type of `Property[float]`)
# error: [invalid-argument-type]
reveal_type(Property("height", 3.4))  # revealed: Property[Unknown]

collections.namedtuple

from collections import namedtuple

Person = namedtuple("Person", ["id", "name", "age"], defaults=[None])

alice = Person(1, "Alice", 42)
bob = Person(2, "Bob")