Skip to content

Clarify the valid use locations of typing.Concatenate#2140

@johnslavik

Description

@johnslavik

In python/cpython#142965, it was reported that the documentation of typing.Concatenate is "incorrect" (documentation that originates back to python/cpython#24000).

@A5rocks, in your example, Concatenate[int, P_2] somewhat finally lands as a first argument to Callable, just indirectly.
This snippet previously defined:

P_2=ParamSpec("P_2") classX(Generic[T, P]): f: Callable[P, int] x: T

Similar example is included in the typing spec:

https://typing.python.org/en/latest/spec/generics.html#user-defined-generic-classes

classX[T, **P]: f: Callable[P, int] x: T# (...)defaccept_concatenate[**P](x: X[int, Concatenate[int, P]]) ->str: ... # Accepted

However, it seems that the current situation (confirmed with mypy, pyright and ty) is that you can use Concatenate in all valid locations of ParamSpec except directly in a Concatenate. I.e., you can't do Concatenate[int, Concatenate[str, P]]), but you can (besides passing Concatenate form as the first argument to Callable):

  1. Accumulate Concatenates as ParamSpecs
fromcollections.abcimportCallablefromtypingimportConcatenate type Y[**P] =Callable[Concatenate[int, P], None] type X[**P] =Y[Concatenate[int, P]] deffoo(f: X[str]) ->None: reveal_type(f) # mypy: def (builtins.int, builtins.int, builtins.str)# pyright: (int, int, str) -> None# ty: (...) -> None
  1. Bind Concatenates to user-defined generics as ParamSpecs
classX[T, **P]: f: Callable[P, int] x: Tdefaccept_concatenate[**P](x: X[int, Concatenate[int, P]]) ->str: ...
  1. Use Concatenate as a type argument to tuple -- is this correct?
fromtypingimportConcatenatedefc(t: tuple[Concatenate[int, ...]]) ->None: reveal_type(c) # mypy: def (t: tuple[[builtins.int, *Any, **Any]])# pyright: (t: tuple[Concatenate[int, ...]]) -> None# ty: def c(t: tuple[@Todo]) -> None

I've found this mostly by poking around -- I haven't analyzed the actual implementations (yet).
I'll continue to investigate this from these searches.

I think that the valid use locations of Concatenate should be clarified in the typing spec and then in the CPython docs.

Is there anything else I overlooked? CC @JelleZijlstra@AlexWaygood

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions