Open junqed opened 4 years ago
Not sure about the error on line 29, but the error from line 18 at least seems to be a legitimate one -- you need to use async with
(and consequently make your run
function an async def
). Otherwise you get the following runtime error:
Traceback (most recent call last):
File "test.py", line 34, in <module>
main()
File "test.py", line 30, in main
cons.run()
File "test.py", line 18, in run
with self.locker.with_lock() as name:
AttributeError: __enter__
Not sure about the error on line 29, but the error from line 18 at least seems to be a legitimate one -- you need to use
async with
(and consequently make yourrun
function anasync def
). Otherwise you get the following runtime error:
Sorry, I forgot about it, fixed in my example
It looks like the type annotations were incorrect and the errors were legitimate. This version passes without errors (I'm not 100% sure if the annotations are correct here, though):
import asyncio
from contextlib import asynccontextmanager
from typing import AsyncGenerator, AsyncContextManager
from typing_extensions import Protocol
class LockProto(Protocol):
def with_lock(self) -> AsyncContextManager[str]: ...
class Consumer:
def __init__(self, locker: LockProto) -> None:
self.locker = locker
async def run(self) -> None:
async with self.locker.with_lock() as name:
print(name)
class SockLock:
@asynccontextmanager
async def with_lock(self) -> AsyncGenerator[str, None]:
yield 'some-string'
async def main() -> None:
cons = Consumer(SockLock())
await cons.run()
if __name__ == '__main__':
asyncio.run(main())
Changes I made:
with_lock
a normal def
run
an async def
I wonder if some error messages could be improved here?
Thanks, moving away async
from the protocol fixed the error. But why? Do I understand correctly that the decorator asynccontextmanager
changes the function signature implicitly and mypy understands it? Is it a good idea to add such cases to the docs?
Yeah, asynccontextmanager
changes the signature and mypy understands (to a certain extent, at least). Mentioning this in the documentation may be a good idea, if we find a good place to put it. contextmanager
is another typical example and much more common, so it should be documented as well (or at first).
https://mypy.readthedocs.io/en/stable/kinds_of_types.html is it a good place for such kind of examples? Or at least just to put them in the examples https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html#miscellaneous
I'd say that appending to https://mypy.readthedocs.io/en/stable/kinds_of_types.html is a good place for contextmanager
. asynccontextmanager
could be documented in https://mypy.readthedocs.io/en/stable/more_types.html#typing-async-await. These don't feel important enough to be included in the cheat sheet.
I'm taking this issue
@JukkaL where should I add contextmanager
in https://mypy.readthedocs.io/en/stable/kinds_of_types.html
?
@joybhallaa I would create a new section called "Context Managers".
Are you reporting a bug, or opening a feature request? A bug
Please insert below the code you are checking with mypy,
import asyncio import typing as t from contextlib import asynccontextmanager
import typing_extensions as te
class LockProto(te.Protocol): async def with_lock(self) -> t.AsyncContextManager[str]: ...
class Consumer: def init(self, locker: LockProto) -> None: self.locker = locker
class SockLock: @asynccontextmanager async def with_lock(self) -> t.AsyncGenerator[str, None]: yield 'some-string'
async def main() -> None: cons = Consumer(SockLock()) await cons.run()
if name == 'main': asyncio.run(main())
bug.py:18: error: "Coroutine[Any, Any, AsyncContextManager[str]]" has no attribute "enter" bug.py:18: error: "Coroutine[Any, Any, AsyncContextManager[str]]" has no attribute "exit" bug.py:29: error: Argument 1 to "Consumer" has incompatible type "SockLock"; expected "LockProto" bug.py:29: note: Following member(s) of "SockLock" have conflicts: bug.py:29: note: Expected: bug.py:29: note: def with_lock(self) -> Coroutine[Any, Any, AsyncContextManager[str]] bug.py:29: note: Got: bug.py:29: note: def with_lock(*Any, **Any) -> AsyncContextManager[Any]