在模块中配置时,Python龙卷风自动回放不起作用



我正试图弄清楚为什么Python Tornado autoreload功能在模块内配置和启动时不起作用。以下模块包含一个MyTornadoApp类,如果设置了正确的选项,该类将配置并启动自动回放:

import os
import tornado.autoreload
import tornado.web
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello from index handler!")
class MyTornadoApp:
"""Setup my custom tornado app with default settings"""
# default tornado settings
default_settings = dict(
debug=False,
autoreload=True,
compress_response=True,
port=8080,
)
default_handlers = [
(r"/", IndexHandler),
]
def __init__(self, user_settings):
self.options = {**self.default_settings, **user_settings}
if self.options['autoreload'] == True:
self._autoreload_config()
self.tornado = tornado.web.Application(self.default_handlers,
**self.options)
def _autoreload_config(self):
"""Setup autoreload for tornado"""
print("Setting up autoreload for tornado...")
# autoreload (exclusive) monitor file
monitoring_file = os.path.abspath('autoreload')
if not os.path.isfile(monitoring_file):
with open(monitoring_file, 'w', encoding='UTF-8') as f:
f.write('Do NOT delete. Monitoring changes in this file!')
tornado.autoreload.watch(monitoring_file)
tornado.autoreload.start()

下面的主python脚本随后创建龙卷风应用程序,但不幸的是,autoreload只有在调用start时才有效(同样,根据龙卷风发出的警告消息(。知道为什么会发生这种事吗?这是一个功能还是一个bug?我错过了什么?TIA。

import asyncio
import tornado.web
from tornadoapp import MyTornadoApp
async def main():
################################################################
#   Why do I need this in order to autoreload work properly???
################################################################
if app.options['autoreload'] == True:
tornado.autoreload.start()
app.tornado.listen(app.options['port'])
print(f"Tornado is listening on port {app.options['port']}")
await asyncio.Event().wait()
if __name__ == "__main__":
my_settings = dict(
debug=False,
autoreload=True,
)
app = MyTornadoApp(my_settings)
asyncio.run(main())

请注意警告消息:tornado.autoreload started more than once in the same process。但是,如果我们从main()函数中删除tornado.autoreload.start()行,那么如果我们更改监控文件(或任何其他关注的文件(,则不会触发自动回放。

这是asyncio.run的一个不幸的怪癖/缺陷:它将默默地丢弃线程中已经存在的任何事件循环,并创建一个新的事件循环来运行主函数。由于Tornado在构造应用程序时会初始化autoreload,这意味着当您在main之外构造它时,它使用了错误的事件循环。

有两种可能的解决方案:

  1. 使用asyncio.get_event_loop().run_until_complete()而不是asyncio.run()。这应该按照您期望的方式工作,但这种用法已被弃用,并将在未来的python版本中删除
  2. 继续使用asyncio.run(),但在主函数内执行所有操作(包括应用程序的构建(。这是未来的推荐模式

最新更新