-
Notifications
You must be signed in to change notification settings - Fork 106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Transport implementations: embracing __aenter__ and __aexit__ #146
Comments
So, I'd also been thinking about the interaction between I don't think it's particularly problematic - the base implementation of We could just enforce that constraint unilaterally throughout, and force users into... async with httpx.AsyncClient(...) as client:
... That's possible okay in a newish async ecosystem, where we can be bullish about allowed usage styles, but unless we're a bit fiddly it also forces the sync usage to only ever use the same style. with httpx.Client(...) as client:
... Which isn't a pattern that fits with existing client = httpx.Client(...)
# Just use this global `client` instance throughout. Right now our approach is to instead walk-the-fine-line, and say that clients don't impose a strict context managed style, but transports may choose to import one (Eg. ASGITransport might end up doing so) or may have some optional functionality that's only present if it is used (Eg. AsyncConnectionPool could perform in-background keep-alive cleanups when used as a context manager, or send periodic HTTP/2 pings to support long-lived idle connections.). |
Sorry if I'm sounding cocky and repetitive here (since I've been saying this a few times in the past few days - if there's anything wrong with my reasoning here please let me know!), but again I don't think this is particularly relevant to the # No need to enforce context managed usage,
# since this doesn't "spin up" anything.
transport = ASGITransport(app=app)
# ... But this runs an app in the background, so we
# do want to enforce context-managed usage here, which #145 would allow.
with transport.request(...) as ...:
... This being said, I agree with your points about practicality of just being able to do So as I understand we'd be trying to support both styles…?
In case 1/, this issue is mostly irrelevant. These dunder methods are not being called in practice, and In case 2/, transport authors will probably want to define Okay, this all makes sense. Then I guess one extra question I'd have, and this is more of an HTTPX one, is what should high-level clients do in their own Here's what I think should happen so that the properties I described above are well-transfered to the high-level client layer…
Sounds obvious when written like this, but currently this is what we have (bold = what needs to change):
So effectively right now we're not supporting context-manager-only transports well (since their I guess this is what encode/httpx#1145 is pretty much about, and there's nothing else we need to do here wrt HTTPCore and the transport API? |
Yup, exactly all that. 😊 |
Closing as resolved via encode/httpx#1218 |
Another thing I noticed while reworking encode/httpx#998 and thinking about encode/httpx#1145... (Actually, anyone that tries to solve encode/httpx#1145 should arrive at the same conclusion than I'm exposing in this issue, since the HTTPX clients does the wrong thing there as well, which causes issues with exception handling.)
Right now when someone wants to implement a custom transport, we tell them:
.request(...) -> ...
..aclose() -> None
.I think we might want to consider switch to:
.request(...) -> ...
..__aenter__() -> None
and__aexit__(...) -> None
.That is, making it clear to transport implementers that transports are just context managers. More specifically, that if they want their transport to wrap around an async resource, they can do so by forwarding
__aenter__()
and__aexit__()
to that resource.We can probably (?) keep
.aclose()
as a synonym of.__aexit__(None, None, None)
, but it's actually not clear to me whether keeping it wouldn't maintain some sort of confusion. If we really want to enforce context managed usage of transports (and it looks like we should), thentransport = Transport()
(plain instantiation) + calling.aclose()
is not a correct option.So,
AsyncHTTPTransport
would become this:The text was updated successfully, but these errors were encountered: