Skip to content

Should asyncio.iscoroutinefunction return some kind of TypeGuard? #8009

Description

@ajoino

I have the following use-case of a class that takes a regular function or a coroutine as an attribute, and then provides access to it through two properties. Basically the code looks like this:

"""example.py"""fromasyncioimportiscoroutinefunctionfromtypingimportTypeVar, Generic, Callable, Awaitable, AnyT=TypeVar('T')
classResponse(Generic[T]):
...
classRequest(Generic[T]):
...
classFoo:
def__init__(self, callback: Callable[[Request[T]], Response[T] |Awaitable[Response[T]]]):
self._callback=callback@propertydeffunc(self) ->Callable[[Request[T]], Response[T]]:
ifiscoroutinefunction(self._callback):
raiseAttributeError()
returnself._callback@propertydefcoro(self) ->Callable[[Request[T]], Awaitable[Response[T]]:
ifnotiscoroutinefunction(self._callback):
raiseAttributeError()
returnself._callbackasyncdefbar(req: Request[T]) ->Response[T]:
...
foo=Foo(bar)

Now, I expected mypy to give no errors due to type narrowing from `iscoroutinefunction, but instead I get

example.py:21: error: Incompatible return value type (got "Callable[[Request[T]], Union[Response[T], Awaitable[Response[T]]]]", expected "Callable[[Request[T]], Response[T]]")
example.py:28: error: Incompatible return value type (got "Callable[[Request[T]], Union[Response[T], Awaitable[Response[T]]]]", expected "Callable[[Request[T]], Awaitable[Response[T]]]")

After finding this, I started searching through the issues in both mypy and typeshed but couldn't find anything related to iscoroutinefunction. I then looked into typeshed and saw that the return type of iscoroutinefunction is just bool, and not a TypeGuard, despite the similar iscoroutine having one. This makes me think that iscoroutinefunction is annotated like that on purpose.

So my question is, should the return type of asyncio.iscoroutinefunction be a TypeGuard of some kind?

I'm new to the more advanced features of Python typing, and my naive implementation would be something like

fromtypingimportTypeVar, TypeGuardT=TypeVar('T')
defiscoroutinefunction(func: T) ->TypeGuard[T]: ...

If you feel like this should be changed, I'd be happy to submit a PR once I know what the type should be.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions