aiohttp icon indicating copy to clipboard operation
aiohttp copied to clipboard

Expose `_RequestOptions` as a public member

Open dpgraham4401 opened this issue 4 months ago • 4 comments

Is your feature request related to a problem?

I'd like to add type annotations for functions that accept keyword arguments that are passed to the ClientSession.request method. aiohttp has a TypedDict for this already, _Requestoptions but it's a protected member of the aiohttp.client module (has a leading underscore and is not declared in __all__).

Describe the solution you'd like

Remove the underscore for _RequestOptions and add it to the __all__ list, or create a version of the typed dict that includes the kwargs that are part of the documented API.

Describe alternatives you've considered

There's probably a good reason why it's private, but I didn't see a GitHub issue that addressed that question. If There's a good reason, document the answer here.

Related component

Client

Additional context

No response

Code of Conduct

  • [x] I agree to follow the aio-libs Code of Conduct

dpgraham4401 avatar Aug 04 '25 15:08 dpgraham4401

This one is private because we want to be able to make changes to it internally without making breaking changes.

bdraco avatar Aug 04 '25 17:08 bdraco

I think in general, if you're wrapping it in some way, you'll typically want to control some of the parameters yourself, at which point the TypedDict wouldn't work for you.

Dreamsorcerer avatar Aug 04 '25 19:08 Dreamsorcerer

This one is private because we want to be able to make changes to it internally without making breaking changes.

I figured, here's a simplified example of our use case. Before every request with the ClientSession we need to acquire a token from our rate limiter.

    async def _request( self, method: str, *, url: str, **kwargs: Unpack[_RequestOptions]) -> ClientResponse:
        await self.rate_limiter.acquire()
        return await self.session.request(method, url=url, **kwargs )

I'm not sure if this would be a big lift, but I believe something like the below would work to keep some internal kwargs private in the _PrivateRequestOptions typed dict, but allow users to use the PublicRequestOptions typed dict for type annotations. This is just an example, I don't know off the top of my head which ones are meant to be internal. But whatever is in the PublicRequestOptions couldn't be changed without breaking the documented .request API and the client module could keep internal kwargs in _PrivateRequestOptions


# aiohttp/client.py
class PublicRequestOptions(TypedDict, total=False):
    """Public request options."""

    params: Query
    data: Any
    json: Any
    cookies: LooseCookies | None
    headers: LooseHeaders | None
    auth: BasicAuth | None
    allow_redirects: bool
    max_redirects: int
    raise_for_status: None | bool | Callable[[ClientResponse], Awaitable[None]]
    timeout: float | None

class _PrivateRequestOptions(PublicRequestOptions, total=False):
    """Private request options."""

    private_key1: bool
    another_thing_we_dont_want_public: bool
    expect100: bool
# aiohttp/client.py
# updated request signatures
        def request( self, method: str, url: StrOrURL, **kwargs: Unpack[_PrivateRequestOptions]) -> "_RequestContextManager": ...
# my_client.py
    async def _request( self, method: str, *, url: str, **kwargs: Unpack[PublicRequestOptions]) -> ClientResponse: ...

dpgraham4401 avatar Aug 04 '25 20:08 dpgraham4401

Before every request with the ClientSession we need to acquire a token from our rate limiter.

We implemented middlewares for exactly these type of cases, so you don't need to abstract the aiohttp client at all: https://docs.aiohttp.org/en/stable/client_advanced.html#aiohttp-client-middleware https://docs.aiohttp.org/en/stable/client_middleware_cookbook.html

Dreamsorcerer avatar Aug 04 '25 20:08 Dreamsorcerer