Repository navigation
Replies: 2 comments
|
I guess I could subclass |
|
For the linked An One application-level approach is to let your ordinary generators yield either a request or an explicit blocking operation. The shared adapter consumes the operations internally and yields only requests to HTTPX: from collections.abc import Callable
from dataclasses import dataclass
from typing import Any
import anyio
import httpx
@dataclass(frozen=True)
class BlockingCall:
fn: Callable[[], Any]
class ComposedAuth(httpx.Auth):
def steps(self, request):
# Override with a generator yielding Request or BlockingCall.
yield request
def sync_auth_flow(self, request):
raise RuntimeError("This implementation requires AsyncClient")
async def async_auth_flow(self, request):
if self.requires_request_body:
await request.aread()
flow = self.steps(request)
try:
step = next(flow)
while True:
if isinstance(step, BlockingCall):
try:
value = await anyio.to_thread.run_sync(step.fn)
except Exception as exc:
step = flow.throw(exc)
continue
elif isinstance(step, httpx.Request):
value = yield step
if self.requires_response_body:
await value.aread()
else:
raise TypeError(f"Unexpected auth step: {type(step)!r}")
step = flow.send(value)
except StopIteration:
return
finally:
flow.close()Your backend then inherits from functools import partial
import keyring
# Inside steps(), or a regular helper delegated to with yield from:
password = yield BlockingCall(
partial(keyring.get_password, "your-service", username)
)
Keep Prepared with Codex and tested locally with Python 3.12 / HTTPX 0.28.1 using |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Ok, so, I'm using httpx in swiss-army-upload. Part of this is that I (will) have multiple
httpx.Authimplementations for various backend systems. With such complexity, there's some common flows I'd like to break out, eg the stuff needed to get a real OIDC JWT token when running inside of GitHub Actions.Which is fine, you can just
yield fromand it's pretty easy. Cool. Hardly a trifle.But then I needed to start doing non-HTTP things inside the auth, namely talking to credentials storage (keyring) without blocking the async loop. Cool, fine, wrap it up in async wrappers, switch from
auth_flowtoasync_auth_flow, easy enough.Except that you can't use
yield frominside of async functions.Here's what I can think of:
.send(),StopIteration, etc)for loopand.send())Is there a better way of handling this?
All reactions