python / python/typing

Clarify the valid use locations of `typing.Concatenate`

Offen
#2,140 2 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

topic: documentation
Vorherrschende Sprache
Python
Sterne
1.8k
Forks
302
Ø Merge
23 Std.
Gemergte PRs (30 T.)
8

Beschreibung

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")

class X(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

class X[T, **P]:
    f: Callable[P, int]
    x: T

# (...)
def accept_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
from collections.abc import Callable
from typing import Concatenate

type Y[**P] = Callable[Concatenate[int, P], None]
type X[**P] = Y[Concatenate[int, P]]

def foo(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
class X[T, **P]:
    f: Callable[P, int]
    x: T

def accept_concatenate[**P](x: X[int, Concatenate[int, P]]) -> str: ...
  1. Use Concatenate as a type argument to tuple -- is this correct?
from typing import Concatenate

def c(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

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit dem Abschnitt zu benutzerdefinierten generischen Klassen in der typing-Spezifikation und der CPython-Dokumentation zu typing.Concatenate; vergleiche anschließend die Beispiele und das gemeldete Verhalten von mypy, pyright und ty. Prüfe die verknüpften Concatenate-Suchnotizen und ermittle, welche Verwendungsstellen gültig sind; abgeschlossen ist die Aufgabe, wenn die typing-Spezifikation und die CPython-Dokumentation die unterstützten Formen und die Einschränkung für verschachteltes Concatenate eindeutig beschreiben.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
documentation
Issue-Typ
Dokumentation
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
38/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.