Skip to content

Conversation

@ssanderson
Copy link
Owner

For #15. cc @touilleMan

def is_coroutine(f):
return False
else:
def is_coroutine(f):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not using inspect.iscoroutinefunction instead ?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iscoroutinefunction only checks if a function was defined as an async def by looking at the CO_COROUTINE flag on the code object. For older codebases with lots of yield from coroutines, there's also the types.coroutine decorator, which sets a different flag, CO_ITERABLE_COROUTINE. This implementation handles both styles (and treats them as equivalent).

Copy link
Owner Author

@ssanderson ssanderson May 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though, from reading the docs for iscoroutinefunction, I think it's just a bug that it doesn't handle types.coroutine functions correctly...

In [1]: from inspect import iscoroutinefunction In [2]: iscoroutinefunction?? Signature: iscoroutinefunction(object) Source: def iscoroutinefunction(object): """Return true if the object is a coroutine function. Coroutine functions are defined with "async def" syntax, or generators decorated with "types.coroutine". """ return bool((isfunction(object) or ismethod(object)) and object.__code__.co_flags & CO_COROUTINE) File: /usr/lib/python3.5/inspect.py Type: function In [3]: import types In [4]: @types.coroutine ...: def foo(): ...: yield 3 ...: In [5]: iscoroutinefunction(foo) Out[5]: False 

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, it seems a bit more messy than what I originally thought:

Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import asyncio, types, inspect >>> asyncio.coroutine is types.coroutine False >>> @asyncio.coroutine ... def asyncio_coroutine(): ... return 'foo' ... >>> asyncio_coroutine() <generator object asyncio_coroutine at 0x7f532573cdb0> >>> inspect.iscoroutinefunction(asyncio_coroutine) False >>> inspect.iscoroutine(asyncio_coroutine()) False >>> @types.coroutine ... def types_coroutine(): ... return 'foo' ... >>> types_coroutine() 'foo' >>> inspect.iscoroutinefunction(types_coroutine) False >>> inspect.iscoroutine(types_coroutine()) False >>> async def async_func(): ... return 'foo' ... >>> async_func() <coroutine object async_func at 0x7f532573cdb0> >>> inspect.iscoroutinefunction(async_func) True >>> inspect.iscoroutine(async_func()) True 

So basically:

  • using async def foo() works as expected
  • using asyncio.coroutine generate a coroutine but inspect module doesn't realize this... I guess it's a bug
  • using types.coroutine doesn't even turn the function into a coroutine function (i.e. calling types_coroutine in the example returns the result instead of a coroutine), this is definitely a bug !

Note that I've done this test with CPython 3.5.2 and 3.6.3, both giving the same result

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've realized I made a mistake with types.coroutine which must take a generator function (I was testing with a regular function).
So my last bullet point was wrong, but anyway inspect doesn't work with it:

>>> import asyncio, types, inspect >>> @types.coroutine ... def types_coroutine(): ... yield 42 ... >>> types_coroutine() <generator object types_coroutine at 0x7f36577fff68> >>> inspect.iscoroutinefunction(types_coroutine) False >>> inspect.iscoroutine(types_coroutine()) False 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants