Search code examples
pythonpython-3.xpersistencepython-asyncio

Persist and fetch data in with block


I have a situation - I'm using the asyncio package with Python 3.x, and persisting data in a with block, something like this:

test_repo = TestRepository()

with (yield from test_repo):
    res = yield from test_repo.get_by_lim_off(
            page_size=int(length),
            offset=start,
            customer_name=customer_name,
            customer_phone=customer_phone,
            return_type=return_type
        )

I need to get res data in the with block, but persistence and fetching data should happen when I exit from the with block. How can I achieve this?


Solution

  • This behavior is only supported in Python 3.5+, via asynchronous context managers (__aenter__/__aexit__), and async with, both of which were added in PEP 492:

    class TestRepository:
       # All your normal methods go here
    
       async def __aenter__(self):
          # You can call coroutines here
          await self.some_init()
    
       async def __aexit__(self, exc_type, exc, tb):
          # You can call coroutines here
          await self.do_persistence()
          await self.fetch_data()
    
    
    async def do_work():
        test_repo = TestRepository()
    
        async with test_repo:
            res = await test_repo.get_by_lim_off(
                    page_size=int(length),
                    offset=start,
                    customer_name=customer_name,
                    customer_phone=customer_phone,
                    return_type=return_type
                )
    
     asyncio.get_event_loop().run_until_complete(do_work())
    

    Prior to 3.5, you have to use a try/finally block with explicit calls to the init/cleanup coroutines, unfortunately:

    @asyncio.coroutine
    def do_work():
        test_repo = TestRepository()
    
        yield from test_repo.some_init()
        try:
            res = yield from test_repo.get_by_lim_off(
                    page_size=int(length),
                    offset=start,
                    customer_name=customer_name,
                    customer_phone=customer_phone,
                    return_type=return_type
                )
        finally:
            yield from test_repo.do_persistence()
            yield from test_repo.fetch_data()