return type cannot be awaitable | int
?
#5629
-
Hello! I maintain Python package which supports both sync and async syntax with same code base, depending on selected adapter (requests or aiohttp) -- https://github.com/pbelskiy/ujenkins I've faced with problem with Pyright, it ignores return type, but mypy works here ok. Why? Here Pyright says:
But it in fact import asyncio
from typing import Awaitable
ASYNC_MODE = True
async def echo_async(arg: int) -> int:
return arg
def echo_sync(arg: int) -> int:
return arg
def echo(arg: int) -> Awaitable | int: # <--- PROBLEM HERE
if ASYNC_MODE:
return echo_async(arg)
else:
return echo_sync(arg)
async def example():
print(await echo(777))
asyncio.run(example()) |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
Pyright's behavior here is correct. Your function Not surprisingly, mypy generates the same error in this case. (Actually, mypy doesn't generate an error by default here because mypy skips type checking for any function that is unannotated. If you add a Most libraries that support both sync and async operations offer distinct functions for both cases. It looks like you're trying to handle both cases with the same function ( If you change your example as follows, it works fine: async def example() -> None:
print(await echo_async(777)) |
Beta Was this translation helpful? Give feedback.
-
I took a light look at ujenkins library and if your approach is having separate adapter classes then generics + overloads could do this. Simplified idea, AsyncMode = TypeVar('AsyncT', Literal[True, False])
class MainJob(Generic[AsyncMode]):
@overload
def __init__(self: MainJob[Literal[True]], adapter: AsyncAdapter):
...
@overload
def __init__(self: MainJob[Literal[False]], adapter: SyncAdapter):
...
@overload
def echo(self: MainJob[Literal[True]], message: str) -> Awaitable:
...
@overload
def echo(self: MainJob[False], message: str) -> int:
... Key trick is adapter determines where MainJob type variable for asyncness is true/false and overloads can be used from there to select Awaitable/int as needed. If you want same function to handle both async/sync you'll need overloads and either make class generic or add an argument to function to pick the mode. An alternate variation is class MainJob:
@overload
def __new__(cls, adapter: AsyncAdapter) -> AsyncJob:
...
@overload
def __new__(cls, adapter: SyncAdapter) -> SyncJob:
...
class AsyncJob(MainJob):
...
class SyncJob(MainJob):
... python is rather flexible although whether complexity is worth it is your decision. |
Beta Was this translation helpful? Give feedback.
I took a light look at ujenkins library and if your approach is having separate adapter classes then generics + overloads could do this. Simplified idea,
Key trick is adapter determines where MainJob type variable for asyncness is true/false and overloads can be us…