python / python/typing

Annotate sync/async code via Generic | generic TypeVar / Type aliases in Generic

Ouverte
#1,183 6 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

topic: feature
Langage dominant
Python
Étoiles
1.8k
Forks
302
Merge moyen
23 h
PR mergées (30 j)
8

Description

Consider this case:
import asyncio
from typing import Any, Coroutine, Generic, TypeVar

from httpx import AsyncClient, Client, Response

ClientT = TypeVar("ClientT", bound=Client | AsyncClient)



class API(Generic[ClientT]):
    client: ClientT

    def __init__(self, client: ClientT) -> None:
        self.client = client

    def get_items(self) -> Response | Coroutine[Any, Any, Response]:
        return self.client.request('get', 'https://example.com/api/v1/get_items')


response = API[Client](Client()).get_items()
response.json()  # Item "Coroutine[Any, Any, Response]" of "Union[Response, Coroutine[Any, Any, Response]]" has no attribute "json"  [union-attr]

response_coroutine = API[AsyncClient](AsyncClient()).get_items()
asyncio.run(response_coroutine)  # Argument 1 to "run" has incompatible type "Union[Response, Coroutine[Any, Any, Response]]"; expected "Awaitable[Response]"  [arg-type]mypy(error)

How can I express bound between ClientT and return type of API().get_items()?

How it could look like if Generic would support type aliases or TypeVar supported another type variables:

import asyncio
from typing import Annotated, Any, Awaitable, Coroutine, Generic, TypeVar
from typing_extensions import reveal_type

from httpx import AsyncClient, Client, Response

ClientT = TypeVar("ClientT", bound=Client | AsyncClient)
T = TypeVar("T")

# Using Annotated just as generic type that returns its argument as is
Sync = Annotated[T, ...]
MightBeAwaitable = TypeVar("MightBeAwaitable", bound=Awaitable | Sync)
# or MightBeAwaitable = Awaitable | Sync

class API(Generic[ClientT, MightBeAwaitable):
    client: ClientT

    def __init__(self, client: ClientT) -> None:
        self.client = client

    def get_items(self) -> MightBeAwaitable[Response]:  # TypeError: 'TypeVar' object is not subscriptable
        return self.client.request('get', 'https://example.com/api/v1/get_items')


response = API[Client, Sync](Client()).get_items()
reveal_type(response)  # Revealed type is "Response"

response_coroutine = API[AsyncClient, Awaitable](AsyncClient()).get_items()
reveal_type(response_coroutine)  # Revealed type is "typing.Awaitable[Any]"

Sorry if it's the wrong place/type for this issue.

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par les exemples Python de cet issue et les constructions de typage qu’ils mettent en œuvre : Generic, TypeVar, alias de types, Annotated, Awaitable et Coroutine. Déterminez la relation prévue entre le type du client et le type de retour de get_items(), puis documentez une conception de typage prise en charge ainsi que les types révélés attendus.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
developer-experience
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
À clarifier
Accessibilité débutants
20/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.