Answer a question

I have a function which accepts both regular and asynchronous functions (not coroutines, but functions returning coroutines).

Internally it uses asyncio.iscoroutinefunction() test to see which type of function it got.

Recently it broke down when I attempted to create a partial async function.

In this demonstration, ptest is not recognized as a couroutine function, even if it returns a coroutine, i.e. ptest() is a coroutine.

import asyncio
import functools

async def test(arg): pass
print(asyncio.iscoroutinefunction(test))    # True

ptest = functools.partial(test, None)
print(asyncio.iscoroutinefunction(ptest))   # False!!

print(asyncio.iscoroutine(ptest()))         # True

The problem cause is clear, but the solution is not.

How to dynamically create a partial async func which passes the test?

OR

How to test the func wrapped inside a partial object?

Either answer would solve the problem.

Answers

Using Python versions < 3.8 you can't make a partial() object pass that test, because the test requires there to be a __code__ object attached directly to the object you pass to inspect.iscoroutinefunction().

You should instead test the function object that partial wraps, accessible via the partial.func attribute:

>>> asyncio.iscoroutinefunction(ptest.func)
True

If you also need to test for partial() objects, then test against functools.partial:

def iscoroutinefunction_or_partial(object):
    while isinstance(object, functools.partial):
        object = object.func
    return inspect.iscoroutinefunction(object)

In Python 3.8 (and newer), the relevant code in the inspect module (that asyncio.iscoroutinefunction() delegates to) was updated to handle partial() objects, and you no longer have to unwrap partial() objects yourself. The implementation uses the same while isinstance(..., functools.partial) loop.

Logo

Python社区为您提供最前沿的新闻资讯和知识内容

更多推荐