Code Monkey home page Code Monkey logo

asyncio_extras's Issues

Methods using async_contextmanager decorator don't pass pylint

I have a context manager method using the async_contextmanager decorator:

@asyncio_extras.async_contextmanager
async def scoped_session():
    session = Session()
    try:
        yield session
        session.commit()
    except:
        session.rollback()
        raise
    finally:
        session.close()

And then I use this context manager like so:

async def create_api_key(module):
    async with scoped_session() as session:
        pass
    pass

When I try to run this through pylint, it fails, being unable to find the context manager object's __aenter__ and __aexit__ methods.

$ pylint -E file.py
No config file found, using default configuration
************* Module file
E:  6,10: Async context manager 'generator' doesn't implement __aenter__ and __aexit__. (not-async-context-manager)

Async Context Manager incorrectly fails to handle return/StopAsyncIteration in generator.athrow

Consider the following context manager:

class TransactionAbort(IOError):
    pass

@async_contextmanager
async def transaction(conn):
    try:
        yield conn
    except TransactionAbort:
        ...
        return
    else:
        ...

The early return in the generator will cause await self.generator.athrow(exc_type) to get a StopAsyncIteration back as per https://www.python.org/dev/peps/pep-0525/#pyasyncgenasend-and-pyasyncgenathrow (see case 3).

Suggestion:

Change

await self.generator.athrow(exc_val)
to:

        try:
            await self.generator.athrow(exc_val)
        except StopAsyncIteration:
            return True  # tell python that the exception (StopAsyncIteration) is safe to suppress

I have the following monkey patch for others to use until this is addressed:

from asyncio_extras import contextmanager


def patch_context_manager():
    if hasattr(contextmanager._AsyncContextManager.__aexit__, '__horcruxed__'):
        return

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if exc_val is not None:
            try:
                await self.generator.athrow(exc_val)
            except StopAsyncIteration:
                return True
        else:
            try:
                await self.generator.asend(None)
            except StopAsyncIteration:
                pass
            else:
                raise RuntimeError("async generator didn't stop")
    __aexit__.__horcruxed__ = time.time()
    contextmanager._AsyncContextManager.__aexit__ = __aexit__

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.