-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Description
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)?