Potential Issue: Overly restrictive coroutine check rejects valid Cython awaitables #1105
Replies: 2 comments
|
Your reading looks right to me, and there's a detail in the source that supports it: the guard is marked as never-executed. coro = self.trace_extension(prefix_and_name, info)
if not inspect.iscoroutine(coro): # pragma: no cover
raise TypeError(
"If you're using an asynchronous interface, "
"the callback of the `trace` extension should "
"be an asynchronous function rather than a normal function."
)
await coroThat The argument for It also doesn't weaken the guard's actual purpose. The mistake the message describes — passing a normal function — returns whatever that function returned, typically Worth mentioning the second symptom in your report as part of the same change: the raise happens after the callback has already been called, so the returned awaitable is discarded without ever being awaited, which is where the |
|
Your reading is right, and I think the fix is safe for a reason beyond the awaitable protocol itself.
The current code is: coro = self.trace_extension(prefix_and_name, info)
if not inspect.iscoroutine(coro): # pragma: no cover
raise TypeError(
"If you're using an asynchronous interface, "
"the callback of the `trace` extension should "
"be an asynchronous function rather than a normal function."
)
await coroSwitching to The One nit on the error message if you do open a PR. If it is going to accept any awaitable, then wording it around "asynchronous function" is slightly off, since a callable returning an awaitable is now fine too. Something like "should return an awaitable" would match the new check more closely. Worth checking whether |
Uh oh!
There was an error while loading. Please reload this page.
I created a minimal reproducer, but the issue template asks that potential bugs start as discussions. httpcore’s coroutine check rejects valid awaitables returned by Cython-compiled async callbacks.
Environment
Python: 3.14.3
httpcore: 1.0.9
Cython: 3.2.9
setuptools: 80.9.0
OS: Linux x86_64
Expected behavior
The Cython-compiled callback should be accepted because its result implements the awaitable protocol and can be used with await.
Actual behavior
inspect.isawaitable: True
inspect.iscoroutine: False
TypeError: If you're using an asynchronous interface, the callback of the
traceextension should be an asynchronous function rather than a normalfunction.
RuntimeWarning: coroutine 'trace_callback' was never awaited
The pure-Python invocation reports:
inspect.isawaitable: True
inspect.iscoroutine: True
and completes successfully.
Likely cause
Trace.atrace()currently validates the returned object with:Because the object is immediately used with await, would it be appropriate to validate the general awaitable protocol instead?
Demonstration
repro.py
How to run it
All reactions