microsoft / microsoft/pyright

Unpacking a NamedTuple leads to unusual results

Open
#10,974 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Python
Stars
15.6k
Forks
1.8k
Avg merge
12h 13m
Merged PRs (30d)
52

Description

Pyright doesn't allow unpacking a namedtuple when it's provided directly after *:

type Foo = tuple[*F]  # Unpack is not allowed in this context

However, pyright seems to support unpacking type parameters with a tuple bound. If a NamedTuple is filled in for the parameter, strange things happen. Code example (pyright 1.1.405):

from typing import reveal_type, NamedTuple

class F(NamedTuple):
    x: int
    y: str

type UnpackThing[Xs: tuple[object, ...]] = tuple[*Xs]
type Foo = UnpackThing[F]

def fn(foo: Foo) -> None:
    reveal_type(foo)     # tuple[*F]
                         # ^technically not wrong, but probably should be tuple[int, str]

    reveal_type(foo[0])  # Type of "foo[0]" is "*F"
                         # (expected: 'Type of "foo[0]" is "int"')

    reveal_type(foo[1])  # info: Type of "foo[1]" is "F"
                         # AND error: Index 1 is out of range for type Foo
                         # (expected: 'Type of "foo[1]" is "str"')

    reveal_type(foo[0].__replace__)  # "(*, x: int = ..., y: str = ...) -> *F"
    # ^maybe pyright thinks that foo is just tuple[F]?


It seems like pyright is assigning an invalid "*F" type as the first and only element in the tuple for the inferred type of foo, similarly to #10637

Here's a different way of producing such a type:

def duplicate[T: tuple[object, ...]](tup: T) -> tuple[*T, *T]:
    ...

foo = duplicate(F(1, "a"))
reveal_type(foo)  # Type of "foo" is "tuple[*F, *F]"

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the issue with the two provided snippets using pyright 1.1.405, focusing on the NamedTuple and tuple type-parameter cases. Trace how the inferred tuple[*F] and tuple[*F, *F] types are represented and indexed; done means the revealed types and index behavior match tuple[int, str] and the expected duplicate expansion.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.