¿Cómo usar el estilo de Python 3.5 async y esperar en Tornado para websockets?

Considere este breve fragmento:

import tornado import tornado.websocket import tornado.ioloop import tornado.gen import tornado.web class NewWsHandler(tornado.websocket.WebSocketHandler): async def on_message(self, message): await self.write_message("echo " + message) class OldWsHandler(tornado.websocket.WebSocketHandler): @tornado.gen.coroutine def on_message(self, message): yield self.write_message("echo " + message) app = tornado.web.Application([(r'/', OldWsHandler)]) app.listen(8080) tornado.ioloop.IOLoop.current().start() 

OldWsHandler usa la forma pre-3.5 de hacer funciones asíncronas en Tornado, y funciona bien. Sin embargo, como indica la documentación , se prefiere usar PEP 0492 para facilitar la lectura y la velocidad.

La documentación dice:

Simplemente use async def foo() en lugar de una definición de función con el decorador @gen.coroutine , y await en lugar de yield .

Así que escribí NewWsHandler . Sin embargo, al enviar un mensaje de websocket, genera una advertencia:

 /usr/lib/python3.5/site-packages/tornado/websocket.py:417: RuntimeWarning: nunca se esperó el mensaje 'on_message' de coroutine
   callback (* args, ** kwargs)

Realmente no sé cómo (correctamente) arreglarlo. Intenté decorarlo en tornado.web.asynchronous , pero eso supone un método de verbo HTTP . Entonces, después de anular el finish() (los websockets no pueden hacer eso), parece que está funcionando:

 class NewWsHandler(tornado.websocket.WebSocketHandler): def finish(self): pass @tornado.web.asynchronous async def on_message(self, message): await self.write_message("echo " + message) 

Pero esto todavía parece hacker, y parece estar contradiciendo la documentación. ¿Cuál es la forma correcta de hacer esto?

Nota: Estoy usando Python 3.5.1 y Tornado 4.3.

Los coroutines se llaman de manera diferente a las funciones regulares; por lo tanto, al subclasificar y anular métodos, no puede cambiar un método regular en la clase base a una clase secundaria en su subclase (a menos que la clase base específicamente diga que esto está bien). WebSocketHandler.on_message posible que WebSocketHandler.on_message no sea una guía (a partir de Tornado 4.3; esto puede cambiar en el futuro).

En cambio, si necesita hacer algo asíncrono en respuesta a un mensaje, coloque las partes asíncronas en una función separada y IOLoop.current().spawn_callback con IOLoop.current().spawn_callback . (o si write_message es la única cosa asíncrona que estás haciendo, simplemente llámalo sincrónicamente)


Actualizar

Esto cambió en Tornado 4.5, WebSocketHandler.on_message ahora se puede usar como una rutina. Consulte http://www.tornadoweb.org/en/stable/releases/v4.5.0.html#tornado-websocket .