We could use an existing valid form (arguably without meaning currently) for this. tuple[*Ts]
(without a corresponding use of typevar tuple). It’s marking it as an indeterminate length. You wouldn’t be correlating what goes in with what goes out, but all the normal checks that work with typevar tuples that haven’t been bound to a type should be run for checking the body of the function and the return independently.
My preference hasn’t changed towards 2a at all, discussing it further has actually solidified my thoughts on why it shouldn’t be. (Consider that Sequence[T] does not impose assumptions about length that prevent indexing or unpacking to a specific number of elements)
2b and 2c are each more useful at the boundary between typable and untypable code than 2a. There have been many projects that have run into issues at this boundary, whether because the code predates python’s type system and needs to remain compatible for users, or it truly is too dynamic to be expressed in python’s type system. I don’t want to be telling people to rewrite the world to fit an ever-evolving view of typing, breaking their users in the process. (a recent case of historical code that the type system just doesn’t bother trying to understand right now came up recently with stripe’s python library) or having to tell them their code can’t be typed. I agree with something @Daverball presented as part of another alternative and think it applies to 2b: If we keep the gradual nature, this should apply to any composition of tuple[GradualType, ...]
not just Any
.
A tuple of unknown (ed: partially unknown, len >=2) length whose first and last members are known to be int
s I don’t think this case presents anything novel compared to tuple[int, *Ts: Any, int]
(which may be another point towards saying typevartuple should be how this is spelled out by users)