Skip to content

Improve test cases for type substitution of a list of types after initial ParamSpec substitution #103054

Closed
@sobolevn

Description

@sobolevn

After merging #102808 I realized that I've missed several important cases.

Right now substitution algorithm has these lines:

cpython/Lib/typing.py

Lines 1477 to 1488 in 2cdc518

if self.__origin__ == collections.abc.Callable and isinstance(new_arg, tuple):
# Consider the following `Callable`.
# C = Callable[[int], str]
# Here, `C.__args__` should be (int, str) - NOT ([int], str).
# That means that if we had something like...
# P = ParamSpec('P')
# T = TypeVar('T')
# C = Callable[P, T]
# D = C[[int, str], float]
# ...we need to be careful; `new_args` should end up as
# `(int, str, float)` rather than `([int, str], float)`.
new_args.extend(new_arg)

It is tested. But, it is never tested for the nested arguments:

cpython/Lib/typing.py

Lines 1500 to 1511 in 2cdc518

elif isinstance(old_arg, tuple):
# Corner case:
# P = ParamSpec('P')
# T = TypeVar('T')
# class Base(Generic[P]): ...
# Can be substituted like this:
# X = Base[[int, T]]
# In this case, `old_arg` will be a tuple:
new_args.append(
tuple(self._make_substitution(old_arg, new_arg_by_param)),
)
else:

I think that Callable is complex and important enought to be covered with as many cases as possible. Furthermore, Callable can be nested deeply in real types and we need to be sure that this use-case works as intended.

I will send a PR with more tests :)

Related #88965

Linked PRs

Metadata

Metadata

Assignees

Labels

testsTests in the Lib/test dirtopic-typingtype-bugAn unexpected behavior, bug, or error

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions