classification
Title: using asyncio.iscoroutinefunction() on a functools.partial object
Type: enhancement Stage:
Components: asyncio Versions: Python 3.4, Python 3.5
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: curtmcd, gvanrossum, mathieui, vstinner, yselivanov
Priority: normal Keywords:

Created on 2015-02-25 11:00 by mathieui, last changed 2017-06-09 02:28 by gvanrossum. This issue is now closed.

Files
File name Uploaded Description Edit
example_partial.py mathieui, 2015-02-26 13:26
Messages (8)
msg236569 - (view) Author: Mathieu Pasquet (mathieui) * Date: 2015-02-25 11:00
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)
msg236570 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2015-02-25 11:05
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.
msg236592 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2015-02-25 16:23
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.
msg236660 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2015-02-26 10:37
> Plus there is no use case.

Mathieu: can you maybe give some examples? How are you using functools.partial with coroutines?
msg236668 - (view) Author: Mathieu Pasquet (mathieui) * Date: 2015-02-26 13:26
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.
msg236693 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2015-02-26 17:52
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()).
msg295475 - (view) Author: Curt McDowell (curtmcd) Date: 2017-06-09 01:12
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')))
msg295478 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2017-06-09 02:28
Use a lambda instead of partial. It's more pythonic.
History
Date User Action Args
2017-06-09 02:28:01gvanrossumsetmessages: + msg295478
2017-06-09 01:12:13curtmcdsetnosy: + curtmcd
messages: + msg295475
2015-02-26 17:52:33gvanrossumsetstatus: open -> closed
resolution: not a bug
messages: + msg236693
2015-02-26 13:26:20mathieuisetfiles: + example_partial.py

messages: + msg236668
2015-02-26 10:37:39vstinnersetmessages: + msg236660
2015-02-25 16:23:29gvanrossumsetmessages: + msg236592
2015-02-25 11:05:18vstinnersetmessages: + msg236570
versions: + Python 3.5
2015-02-25 11:00:40mathieuicreate