2 votes

Gestionnaire de contexte Tornado appelé dans gen.coroutine

Je travaille actuellement avec la bibliothèque AMQP pika. Ce que je veux développer, c'est un gestionnaire de contexte ou un décorateur qui assure l'établissement d'une connexion avec Rabbit. Le problème est qu'il est impossible d'utiliser des générateurs à l'intérieur des décorateurs car ils doivent retourner une fonction appelée. L'exemple suivant soulève une exception :

def ensure_conn(func):

    @gen.coroutine
    def wrapper(self, *args, **kwargs):
        yield self.connection.ensure_connection()
        return func(*args, **kwargs)

    return wrapper

Le problème est presque le même avec les gestionnaires de contexte. Il est impossible d'utiliser yield deux fois. L'exemple suivant soulève l'exception que le générateur ne s'est pas arrêté.

@contextlib.contextmanager
@gen.coroutine
def ensure_conn(self):
    yield self.ensure_connection()
    yield

Veuillez recommander une autre approche ? Bien sûr, je suis déjà satisfait des simples appels de coroutine. Je vous remercie.

3voto

Rustem K Points 148

En fait, il y a deux façons de créer un gestionnaire de contexte qui vous assure quelque chose. Dans mon cas, il s'agissait d'une connexion à AMQP. La première façon est de surcharger concurrent.futures.Future result() en la forçant à renvoyer une fonction génératrice décorée par la méthode contextlib.contextmanager . ajdavis a utilisé cette approche dans sa belle bibliothèque TORO . Vous pouvez la consulter en naviguant vers cette ligne .

Toutefois, si vous ne souhaitez pas remplacer le système concurrent.futures.Future je vous recommande de lire l'extrait suivant :

@gen.coroutine
def ensure_connection(*args, **kwargs):
    res = yield _make_connection(timeout=kwargs.pop('timeout', 5), *args, **kwargs)
    raise gen.Return(res)

@gen.coroutine
def ensure(*args, **kwargs):
    res = yield ensure_connection(*args, **kwargs)

    @contextlib.contextmanager
    def func(res):
       try:
          yield  # your wrapped code
       finally:
          pass

    return func(res)

@gen.coroutine
def simple_usage(conn):
    with (yield conn.ensure()) as res:
        # Do your target staff here

conn = ...
IOLoop.add_callback(callback=lambda : simple_usage(conn))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X