python-trio / async_generator

Making it easy to write async iterators in Python 3.5
Other
95 stars 23 forks source link

Abstract async context manager in Python3.6 #29

Open JoseKilo opened 5 years ago

JoseKilo commented 5 years ago

I have an abstract class that defines an abstract async context manager (Python 3.7 code):

import abc
import contextlib

class Foo(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    @contextlib.asynccontextmanager
    async def bar(self):
        pass

In order to make it compatible with Python 3.6, I would use async_generator.asynccontextmanager

import async_generator

class Foo(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    @async_generator.asynccontextmanager
    async def bar(self):
        pass

However, this raises an error:

TypeError: must be an async generator (native or from async_generator; if using @async_generator then @acontextmanager must be on top.

This can be fixed using async_generator.async_generator, but I think that was intended for Python3.5 (which lacked native async generators) and not for Python3.6.

class Foo(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    @async_generator.asynccontextmanager
    @async_generator.async_generator
    async def bar(self):
        pass

This seems to work on Python3.5 too.

I can extend the class and implement the method without using async_generator.async_generator in both, Python3.6 and Python3.7 (as expected):

class Bar(Foo):

    @async_generator.asynccontextmanager
    async def bar(self):
        print('Before')
        yield 42
        print('After')

bar = Bar()
async with bar.bar() as context:
    print('Context:', context)

Maybe the docs / readme could include an abstract method example. Or maybe Python3.6 should work without adding @async_generator.