Annotate sync/async code via Generic | generic TypeVar / Type aliases in Generic
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.8k
- Forks
- 302
- Avg merge
- 23h
- Merged PRs (30d)
- 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.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the Python examples in this issue and the typing constructs they exercise: Generic, TypeVar, type aliases, Annotated, Awaitable, and Coroutine. Determine the intended relationship between the client type and get_items()'s return type, then document a supported typing design and its expected revealed types.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- developer-experience
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100