TypeGuard-based overloads for inspect.is*function() were added in #8057, but they are somewhat controversial.
First, the first overload defines the return type via collections.abc.<Object>, while the rest define it via types.<Object>Type. As a result, type checkers infer the narrower type when the known return type differs from collections.abc.<Object>:
fromcollections.abcimportCoroutinefrominspectimportiscoroutinefunctionfromtypesimportCoroutineTypefromtypingimportreveal_typedefnative_coroutine_factory() ->CoroutineType[None, None, None]: ...
defcoroutine_factory() ->Coroutine[None, None, None]: ...
defobject_factory() ->object: ...
ifiscoroutinefunction(native_coroutine_factory):
reveal_type(native_coroutine_factory)
# () -> CoroutineType[None, None, None]ifiscoroutinefunction(coroutine_factory):
reveal_type(coroutine_factory)
# () -> Coroutine[None, None, None]ifiscoroutinefunction(object_factory):
reveal_type(object_factory)
# () -> CoroutineType[Any, Any, Any]
Second, inspect.is*function() also returns True for functions that return a non-native object (for example, if the function was compiled via Cython), which means that the return type may not be types.<Object>Type:
#!/usr/bin/env python3importinspectdefgenerator_function():
yieldasyncdefcoroutine_function():
passasyncdefasync_generator_function():
yielddefmain():
# `True` on both CPython and Cython:print(inspect.isgeneratorfunction(generator_function))
print(inspect.iscoroutinefunction(coroutine_function))
print(inspect.isasyncgenfunction(async_generator_function))
# `True` on CPython, `False` on Cython:print(inspect.isgenerator(generator_function()))
print(inspect.iscoroutine(coro:=coroutine_function()))
print(inspect.isasyncgen(async_generator_function()))
coro.close() # to avoid `RuntimeWarning`if__name__=="__main__":
main()
Third, I am also concerned about the Python core developer's statement that iscoroutinefunction() is basically defined for callable objects that return awaitable objects. Does this mean that we should use Awaitable as the return type instead of Coroutine for inspect.iscoroutinefunction() (since if users follow that definition, inspect.markcoroutinefunction() will be applied just as broadly, even though this somewhat contradicts the documentation)?
TypeGuard-based overloads forinspect.is*function()were added in #8057, but they are somewhat controversial.First, the first overload defines the return type via
collections.abc.<Object>, while the rest define it viatypes.<Object>Type. As a result, type checkers infer the narrower type when the known return type differs fromcollections.abc.<Object>:Second,
inspect.is*function()also returnsTruefor functions that return a non-native object (for example, if the function was compiled via Cython), which means that the return type may not betypes.<Object>Type:Third, I am also concerned about the Python core developer's statement that
iscoroutinefunction()is basically defined for callable objects that return awaitable objects. Does this mean that we should useAwaitableas the return type instead ofCoroutineforinspect.iscoroutinefunction()(since if users follow that definition,inspect.markcoroutinefunction()will be applied just as broadly, even though this somewhat contradicts the documentation)?