-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can I use aiofile.async_open without a with statement? #67
Comments
You could write: async def test():
f = aiofile.async_open('filename.txt', mode='w')
try:
await f.file
await f.write('123')
finally:
pass
# await f.close()
asyncio.run(test()) But I don't really understand the need for this from your example. The only thing I can think of would be that maybe you'd want to return @asynccontextmanager
async def foo():
async with aiofile.async_open('filename.txt', mode='w') as afp:
await afp.write('123')
yield afp
async def bar():
async with foo() as afp:
await afp.write('456')
asyncio.run(bar()) This seems safer to ensure |
Thank you -- is helpful.
Sure - but many applications are not so trivial and the thing writing to the file may not have async_open in its stack.
Simply, the write call might not be in the stack of |
Thank you, I understand your requirements a little better. Here's how I'd do it with the log rotate example: import asyncio
from datetime import datetime
from pathlib import Path
from aiofile import AIOFile, Writer
class AsyncRotatedLog:
def __init__(self, directory='./logs/'):
self._aio_file = None
self._current_log_path = None
self._writer = None
self._directory = Path(directory).resolve()
self._lock = asyncio.Lock()
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
if self._aio_file:
await self._aio_file.close()
async def _get_writer(self):
async with self._lock:
filename = self._directory / f'{datetime.now().strftime("%Y.%m.%d_%H:%M:%S")}.log'
if filename != self._current_log_path:
if self._aio_file:
await self._aio_file.close()
self._aio_file = await AIOFile(filename, 'w')
self._current_log_path = filename
self._writer = Writer(self._aio_file)
return self._writer
async def write(self, msg: str):
msg = msg.strip('\n') + '\n'
writer = await self._get_writer()
await writer(msg)
class Foo:
def __init__(self, async_logger):
self.async_logger = async_logger
async def log_message(self, msg):
await self.async_logger.write(msg)
async def on_x(self, msg): # Runs concurrently as a task
...
await self.log_message(msg)
async def on_y(self, msg): # Runs concurrently as a task
...
await self.log_message(msg)
async def on_z(self, msg): # Runs concurrently as a task
...
await self.log_message(msg)
async def listen_for_xyz(self):
await self.on_x('X happened')
await asyncio.sleep(0.2)
await self.on_y('Y happened')
await asyncio.sleep(1.5)
await self.on_z('Z happened')
async def main():
async with AsyncRotatedLog() as logger:
foo = Foo(logger)
await foo.listen_for_xyz()
asyncio.run(main()) Basically, encapsulate your log rotation logic in its own class and make it an async context manager (this part is optional, you could just as easily replace the Disclaimer: this is simple example code. It's working but it may have bugs (I didn't spend much time on it). Use at your own risks. |
@stuz5000 this will be fixed in version 3.8.0. Code example: import asyncio
import atexit
import os
from tempfile import mktemp
from aiofile import async_open
TMP_NAME = mktemp()
atexit.register(os.unlink, TMP_NAME)
async def main():
afp = await async_open(TMP_NAME, "w")
await afp.write("Hello")
await afp.close()
asyncio.run(main())
assert open(TMP_NAME, "r").read() == "Hello" |
Python's open may be used directly, or as a context manager in a with block.
I love contextmanagers, but they're not always the right tool because cleanup on the stack is not always the right time to perform cleanup.
Can I use aiofile.async_open without a with statement?
The text was updated successfully, but these errors were encountered: