给出以下(示例)处理程序(取自此处):
handlers = [
(r"/", MainHandler),
(r"/auth/login", AuthLoginHandler),
(r"/auth/logout", AuthLogoutHandler),
]
有没有办法以编程方式在单独的页面上打印处理程序?我在想一些类似的事情:
handlers = [
(r"/", MainHandler),
(r"/auth/login", AuthLoginHandler),
(r"/auth/logout", AuthLogoutHandler),
(r"/routes", RoutePrinter),
]
...
class RoutePrinter(...):
def get(self):
self.write(str(self.application.routes))
这给了我
[(<_sre.SRE_Pattern object at 0x216c130>, [, , , , , , , , , , , , , , , , , , , , , , ])]
我尝试了几种不同的访问器,但并没有真正帮助。是否可以生成我的路线列表?
编辑
根据进一步的搜索,我找到了从这些正则表达式对象打印模式/标志的方法。问题是我很难理解如何解除它们的嵌套,因为它不像
self.application.handlers[0][0]
然后 self.application.handlers[1][0]
那么直观。第二个是“超出范围”,尽管它看起来应该是“/auth/login”。
我错过了什么?
这个怎么样?
[handler.regex.pattern for handler in self.application.handlers[0][1]]
如果您还想要处理程序类的名称:
[(handler.regex.pattern, handler.handler_class) for handler in self.application.handlers[0][1]]
我遇到了这个问题,所以我写了这个。
适用于
Tornado 6.4.1
def list_routes(tornado_app: tornado.web.Application) -> str:
def collect_routes(router: tornado.routing.Router) -> list[tuple[str, str] | str]:
routes: list[tuple[str, str] | str] = []
if not hasattr(router, 'rules'):
return routes
for rule in router.rules:
if isinstance(rule.target, tornado.routing.Router):
routes.extend(collect_routes(rule.target))
elif isinstance(rule.matcher, tornado.routing.PathMatches):
handler = rule.target
if isinstance(handler, type):
handler_name = handler.__name__
else:
handler_name = str(handler)
routes.append((rule.matcher.regex.pattern, handler_name))
else:
handler = rule.target
if isinstance(handler, type):
handler_name = handler.__name__
else:
handler_name = str(handler)
routes.append((str(rule.matcher), handler_name))
return routes
routes = ["# default:"] + collect_routes(tornado_app.default_router)
routes += ["# wildcard:"] + collect_routes(tornado_app.wildcard_router)
result = "[\n"
result += ",\n".join([f"(r'{route[0]}', {route[1]})" if isinstance(route, tuple) else f"{route}" for route in routes])
result += "\n]"
return result
它会为 Streamlit 打印此内容:
[
# default:,
(r'^/_stcore/stream/?$', BrowserWebSocketHandler),
(r'^/(?:healthz|_stcore/health)/?$', HealthHandler),
(r'^/_stcore/message/?$', MessageCacheHandler),
(r'^/(?:st-metrics|_stcore/metrics)/?$', StatsRequestHandler),
(r'^/_stcore/host-config/?$', HostConfigHandler),
(r'^/_stcore/upload_file/(?P<session_id>[^/]+)/(?P<file_id>[^/]+)/?$', UploadFileRequestHandler),
(r'^/media/(.*)/?$', MediaFileHandler),
(r'^/component/(.*)/?$', ComponentRequestHandler),
(r'^/app/static/(.*)/?$', AppStaticFileHandler),
(r'^/(.*)/?$', StaticFileHandler),
(r'^/$', AddSlashHandler),
# wildcard:,
(r'^/_stcore/stream/?$', BrowserWebSocketHandler),
(r'^/(?:healthz|_stcore/health)/?$', HealthHandler),
(r'^/_stcore/message/?$', MessageCacheHandler),
(r'^/(?:st-metrics|_stcore/metrics)/?$', StatsRequestHandler),
(r'^/_stcore/host-config/?$', HostConfigHandler),
(r'^/_stcore/upload_file/(?P<session_id>[^/]+)/(?P<file_id>[^/]+)/?$', UploadFileRequestHandler),
(r'^/media/(.*)/?$', MediaFileHandler),
(r'^/component/(.*)/?$', ComponentRequestHandler),
(r'^/app/static/(.*)/?$', AppStaticFileHandler),
(r'^/(.*)/?$', StaticFileHandler),
(r'^/$', AddSlashHandler)
]