What are the subtyping rules for tuple[T, ...]?

Another place where you find heterogeneously-typed tuples of statically-unknown size is in the “data frame” libraries Pandas and Polars.

As a concrete example, pandas.DataFrame.itertuples dynamically constructs a namedtuple and returns an iterator of those dynamically-constructed namedtuples:

Currently Pandas annotates the result as tuple[Any, ...].

I stumbled into this issue because I, as the programmer, happen to know exactly what to expect from that named tuple, so I wrote something like this:

import typing
import pandas as pd

if typing.TYPE_CHECKING:
    class WidgetRow(typing.NamedTuple):
        size: float
        color: str
        quantity: int

widgets = pd.read_parquet("widgets.parquet")

widget: WidgetRow
for widget in widgets.itertuples():
    typing.assert_type(widget.quantity, int)

And I was surprised to find that Mypy didn’t like it:

error: Incompatible types in assignment (expression has type "tuple[Any, ...]", variable has type "WidgetRow")  [assignment]
Found 1 error in 1 file (checked 1 source file)

So consider this a vote from a “regular user” that Python ought to provide some way to express this concept in type annotations, whatever that might be.