Skip to content

Instantly share code, notes, and snippets.

@allemangD
Last active November 1, 2018 15:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save allemangD/bba8dc2d059310623f752ebf65bb6cdc to your computer and use it in GitHub Desktop.
Save allemangD/bba8dc2d059310623f752ebf65bb6cdc to your computer and use it in GitHub Desktop.
Show how Context Managers do not correctly support suspended execution
import asyncio
class CM:
mode = 0
def __init__(self, m):
self.m = m
def __enter__(self):
self.old = CM.mode
CM.mode = self.m
def __exit__(self, *_):
CM.mode = self.old
async def long_op():
with CM('long'):
print(f'- - mode {CM.mode}')
await asyncio.sleep(3)
print(f'- - mode {CM.mode} done')
async def short_op():
with CM('short'):
for i in range(5):
print(f'{i} - mode {CM.mode}')
await asyncio.sleep(1)
print(f'{i} - mode {CM.mode} done')
async def main():
await asyncio.gather(short_op(),
long_op())
asyncio.run(main())
@1st1
Copy link

1st1 commented Nov 1, 2018

This is how your example can be fixed with the contextvars module:

import asyncio
import contextvars

cm_mode = contextvars.ContextVar('cm_mode', default=None)

class CM:

    def __init__(self, m):
        self.m = m

    @property
    def mode(self):
        return cm_mode.get()

    def __enter__(self):
        self.old = cm_mode.get()
        cm_mode.set(self.m)
        return self

    def __exit__(self, *_):
        cm_mode.set(self.old)


async def long_op():
    with CM('long') as cm:
        print(f'- - mode {cm.mode}')
        await asyncio.sleep(3)
        print(f'- - mode {cm.mode} done')

async def short_op():
    with CM('short') as cm:
        for i in range(5):
            print(f'{i} - mode {cm.mode}')
            await asyncio.sleep(1)
            print(f'{i} - mode {cm.mode} done')


async def main():
    await asyncio.gather(short_op(),
                         long_op())

asyncio.run(main())

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment