Closed maximlt closed 8 months ago
import inspect
from functools import partial
import sys
print(sys.version)
class Foo:
async def foo(self, x=None):
return
cb = partial(Foo().foo, x=1)
print(inspect.iscoroutinefunction(cb))
# 3.10.5 | packaged by conda-forge | (main, Jun 14 2022, 07:05:37) [Clang 13.0.1 ]
# False
# 3.10.13 | packaged by conda-forge | (main, Oct 26 2023, 18:09:17) [Clang 16.0.6 ]
# True
I'm pretty sure this change occurred in https://github.com/python/cpython/pull/94050. In our case f
is not a method but a partial, that is unwrapped to a method, and a method is not a function so this used to return False
. In the newer version with _signature_is_functionlike(f)
that evaluates to True
in our case the returned value is True
. Anyway, what matters is that this has been backported to CPython 3.10 and 3.11, precisely to CPython 3.10.6 and 3.11.0 (backported before the actual release). So we could get rid of the partial unwrapping starting from Python 3.11.0.
def _has_code_flag(f, flag):
while ismethod(f):
f = f.__func__
f = functools._unwrap_partial(f)
- if not isfunction(f):
+ if not (isfunction(f) or _signature_is_functionlike(f)):
return False
return bool(f.__code__.co_flags & flag)
We've observed that
inspect.iscoroutinefunction
doesn't return the same output of different versions of Python 3.10 when the function is afunctools.partial
. We make sure that param'siscoroutinefunction
(that covers async generators too) unpacks partials before checking if they wrap a coroutine/async generator or not.