surprises from get_standard_streams
dougransom opened this issue · 10 comments
I was expecting the streams from get_standard_streams to provide awaitables when performing i/o. That doesn't seem to be the case.
I don't understand the purpose of get_standard_streams at all.
>>> i,o=await con.get_standard_streams()
>>> dir(o)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'buffer', 'close', 'drain', 'is_closing', 'loop', 'stream', 'task_finalizer', 'wait_closed', 'write', 'write_task']
>>> o.write("one")
one>>> o.write("two")
two>>> await o.write("Three")
Traceback (most recent call last):
File "C:\Users\dougr\OneDrive\doug\codingprojects\aioutil\env\lib\site-packages\aioconsole\execute.py", line 140, in aexec
result, new_local = await coro
File "<console>", line 2, in __corofn
TypeError: object NoneType can't be used in 'await' expression
I was expecting the streams from get_standard_streams to provide awaitables when performing i/o. That doesn't seem to be the case.
The objects returned by get_standard_streams
are instances of StreamReader and StreamWriter, so the write method is indeed synchronous. To the contrary, the read
, readline
and drain
methods are asynchronous.
I don't understand the purpose of get_standard_streams at all.
It's more of an internal helper to get access to an asyncio-compatible interface for stdin
and stdout
.
I hope that helps.
Well I was looking for a asyncio-compatible interface for stdin, get you can see the standard output stream write operation from get_standard_streams is not awaitable:
two>>> await o.write("Three") Traceback (most recent call last): File "C:\Users\dougr\OneDrive\doug\codingprojects\aioutil\env\lib\site-packages\aioconsole\execute.py", line 140, in aexec result, new_local = await coro File "<console>", line 2, in __corofn TypeError: object NoneType can't be used in 'await' expression
So this is or isn't compatible with asyncio?
So this is or isn't compatible with asyncio?
It is. In the asyncio world, writing to a stream is usually synchronous as you can see in the StreamWriter interface. It's the same if you open a tcp connection using asyncio.open_connection. See this exemple from the documentation:
import asyncio
async def tcp_echo_client(message):
reader, writer = await asyncio.open_connection(
'127.0.0.1', 8888)
print(f'Send: {message!r}')
writer.write(message.encode())
await writer.drain()
data = await reader.read(100)
print(f'Received: {data.decode()!r}')
print('Close the connection')
writer.close()
await writer.wait_closed()
asyncio.run(tcp_echo_client('Hello World!'))
Also note the use of StreamWriter.drain
Thanks for the explanation, i was incorrectly expecting the same behavior as aoifiles write interface and i didn't get the drain method.
Alright :)
if aioconsole provides an interface to stdin, presumably it would be possible to adapt to general files?
I'm not sure I understand your point, could you elaborate?
Well something like this using file IO.
with something.open("myfile.txt") as writer:
writer.write("some text") await writer.drain()
which aoiconsole can already do with stdout.
presumably writer.drain() would complete once the data is written to the file?
Isn't it what aiofiles
is doing already? I think it's fine to use both aioconsole
and aiofiles
in the same project.
aiofiles uses an asynchronous write interface:
async with aiofiles.tempfile.TemporaryFile('wb') as f: await f.write(b'Hello, World!')