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>:
from collections.abc import Coroutine
from inspect import iscoroutinefunction
from types import CoroutineType
from typing import reveal_type
def native_coroutine_factory() -> CoroutineType[None, None, None]: ...
def coroutine_factory() -> Coroutine[None, None, None]: ...
def object_factory() -> object: ...
if iscoroutinefunction(native_coroutine_factory):
reveal_type(native_coroutine_factory)
# () -> CoroutineType[None, None, None]
if iscoroutinefunction(coroutine_factory):
reveal_type(coroutine_factory)
# () -> Coroutine[None, None, None]
if iscoroutinefunction(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 python3
import inspect
def generator_function():
yield
async def coroutine_function():
pass
async def async_generator_function():
yield
def main():
# `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)?