-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
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
using asyncio.iscoroutinefunction() on a functools.partial object #67707
Comments
Using iscoroutinefunction() on an object returned by functools.partial() should return True if the function wrapped was a coroutine function. (a recursive loop like the one in asyncio/events.py get_function_source() may be what needs to be done) |
Take a look at asyncio.events._get_function_source() which supports wrapped functions and functools.partial. Can you propose a patch? If iscoroutinefunction() becomes "expensive", we might make checks optional, only run them in debug mode. |
I recall discussing this before (maybe on the tulip list). I am firmly against. It is a slippery slope -- why inspect a partial but not a lambda? Plus there is no use case. |
Mathieu: can you maybe give some examples? How are you using functools.partial with coroutines? |
Using functools.partial with coroutines would be mostly out of convenience, in order to avoid having factories in that return parametrized coroutine functions. I guess in such cases it might be better to create a two-lines wrapper around partial() to make it return a coroutine rather than change the stdlib for that. In the attached file is an example of such use, where EventNotifier is a Protocol which receives external events and triggers event handlers based on that, and where the add_event_handler function checks if the handler is a coroutine function. In which case it uses asyncio.async to schedule the handler call; otherwise it uses loop.call_soon. You can close this, I guess. |
Yeah, your "add event handler" routine shouldn't be so picky to insist that iscoroutinefunction() returns True. It should just call the thing and verify that it has returned a coroutine object (asyncio.iscoroutine()). |
There are use cases for this. I hit the problem and eventually wound up here, so I'd like to make a case to re-open. My project has a callback registry of asyncio handler routines. register_callback(condition1, handler1)
register_callback(condition2, handler2)
... I want to register many callbacks, but use only one handler and an argument to differentiate it. I realize our callback systems should provide for a cookie, but it doesn't. register_callback(condition1, functools.partial(handler, 'detail1'))
register_callback(condition2, functools.partial(handler, 'detail2')) The callback registry makes sure iscoroutinefunction(handler) because we don't want to defer error checking to the distant future. But iscoroutinefunction() returns False for the partial function. I was hopeful that this might work, but alas, no: register_callback(condition1,
asyncio.coroutine(functools.partial(handler, 'detail1'))) |
Use a lambda instead of partial. It's more pythonic. |
this is fixed in #79071 |
looking at this more closely - this is a bug in this code will now work - if you use register_callback(condition1, functools.partial(handler, 'detail1'))
register_callback(condition2, functools.partial(handler, 'detail2')) here's a demo: import inspect
import functools
import asyncio
async def demo(v):
pass
@asyncio.coroutine
def demo_old(v):
pass
print(f"{inspect.iscoroutinefunction(functools.partial(demo, v=1))=}")
print(f"{asyncio.iscoroutinefunction(functools.partial(demo, v=1))=}")
print(f"{inspect.iscoroutinefunction(functools.partial(demo_old, v=1))=}")
print(f"{asyncio.iscoroutinefunction(functools.partial(demo_old, v=1))=}")
# this prints:
# /home/graingert/projects/bar.py:10: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
# def demo_old(v):
# inspect.iscoroutinefunction(functools.partial(demo, v=1))=True
# asyncio.iscoroutinefunction(functools.partial(demo, v=1))=True
# inspect.iscoroutinefunction(functools.partial(demo_old, v=1))=False
# asyncio.iscoroutinefunction(functools.partial(demo_old, v=1))=False |
So can I close this? (I'm not sure what happened here exactly, I don't recall reopening, maybe GitHub did something funky?) |
ah I thought you were cryptically telling me the issue was still valid when you re-opened this - it caused me to re-read the issue and find that it is actually still a bug - although now only relevant on python 3.10 and maybe on 3.11 |
I have a PR to fix it here #94907 but I think it would be better to drop This would require making |
Honestly if this is fixed in 3.11 by deleting Deleting |
I opened an issue for that removal #94912 |
Okay, closing this issue as fixed. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: