带有 APIRouter 插件系统的 FastAPI 不工作
FastAPI with APIRouter plugin system not working
我正在尝试创建一个简单的可插入 FastAPI 应用程序,其中插件可以添加或不添加 API 端点
这是我的文件夹结构:
server.py
import importlib
import pkgutil
from pathlib import Path
import uvicorn
from fastapi import FastAPI
PLUGINS_PATH = Path(__file__).parent.joinpath("plugins")
app = FastAPI()
def import_module(module_name):
"""Imports a module by it's name from plugins folder."""
module = f"plugins.{module_name}"
return importlib.import_module(module, ".")
def load_plugins() -> list:
"""Import plugins from plugins folder."""
loaded_apps = []
for _, application, _ in pkgutil.iter_modules([str(PLUGINS_PATH)]):
module = import_module(application)
print(
f"Loaded app: {module.__meta__['plugin_name']} -- version: {module.__meta__['version']}"
)
loaded_apps.append(module)
return loaded_apps
@app.get("/")
def main():
return "Hello World!"
if __name__ == "__main__":
plugins = load_plugins()
for plugin in plugins:
"""Register the plugins router."""
if "router" in plugin.__dir__():
app_router = plugin.router
app.include_router(app_router)
uvicorn.run("server:app", host="localhost", port=8000, reload=True)
在我的插件文件夹中有:
plugins/non_api_plugin/__init__.py
:
__meta__ = {"plugin_name": "NON API plugin", "version": "0.0.1"}
plugins/<v1|v2>/__init__.py
from .routes import routes as router
__meta__ = {"plugin_name": "API <v1|v2>", "version": "0.0.1"}
和routes.py个文件:
from fastapi import APIRouter
routes = APIRouter(prefix="/<v1|v2>")
@routes.get("/")
def novels():
return "Hello World from <v1|v2>"
当我 运行 服务器时,插件被加载并记录它们的信息,但是 API 端点没有被加载。
我在这里缺少什么?我最好的猜测是我的插件加载系统在某些时候是错误的。
您 运行 在代码路径中设置您的插件注册代码,当您的脚本具有主上下文时,该代码路径仅 运行s:
if __name__ == "__main__":
# plugin registration
由于您使用此部分调用 uvicorn
,uvicorn 会自行启动并导入您提供的模块。当 uvicorn 启动时,它会导入您的应用程序并确定哪些端点可用 - 但现在您自己的脚本不再是应用程序的主要上下文,因此 __name__ == "__main__"
中的任何内容块不会 运行.
一旦将插件注册块移出该范围,您就会看到预期的行为:
plugins = load_plugins()
for plugin in plugins:
"""Register the plugins router."""
if "router" in plugin.__dir__():
app_router = plugin.router
app.include_router(app_router, prefix='/foo') # I'd let the plugin name be the prefix here to avoid plugins using the same prefix
if __name__ == "__main__":
uvicorn.run("server:app", host="localhost", port=8000, reload=True)
我正在尝试创建一个简单的可插入 FastAPI 应用程序,其中插件可以添加或不添加 API 端点
这是我的文件夹结构:
server.py
import importlib
import pkgutil
from pathlib import Path
import uvicorn
from fastapi import FastAPI
PLUGINS_PATH = Path(__file__).parent.joinpath("plugins")
app = FastAPI()
def import_module(module_name):
"""Imports a module by it's name from plugins folder."""
module = f"plugins.{module_name}"
return importlib.import_module(module, ".")
def load_plugins() -> list:
"""Import plugins from plugins folder."""
loaded_apps = []
for _, application, _ in pkgutil.iter_modules([str(PLUGINS_PATH)]):
module = import_module(application)
print(
f"Loaded app: {module.__meta__['plugin_name']} -- version: {module.__meta__['version']}"
)
loaded_apps.append(module)
return loaded_apps
@app.get("/")
def main():
return "Hello World!"
if __name__ == "__main__":
plugins = load_plugins()
for plugin in plugins:
"""Register the plugins router."""
if "router" in plugin.__dir__():
app_router = plugin.router
app.include_router(app_router)
uvicorn.run("server:app", host="localhost", port=8000, reload=True)
在我的插件文件夹中有:
plugins/non_api_plugin/__init__.py
:
__meta__ = {"plugin_name": "NON API plugin", "version": "0.0.1"}
plugins/<v1|v2>/__init__.py
from .routes import routes as router
__meta__ = {"plugin_name": "API <v1|v2>", "version": "0.0.1"}
和routes.py个文件:
from fastapi import APIRouter
routes = APIRouter(prefix="/<v1|v2>")
@routes.get("/")
def novels():
return "Hello World from <v1|v2>"
当我 运行 服务器时,插件被加载并记录它们的信息,但是 API 端点没有被加载。
我在这里缺少什么?我最好的猜测是我的插件加载系统在某些时候是错误的。
您 运行 在代码路径中设置您的插件注册代码,当您的脚本具有主上下文时,该代码路径仅 运行s:
if __name__ == "__main__":
# plugin registration
由于您使用此部分调用 uvicorn
,uvicorn 会自行启动并导入您提供的模块。当 uvicorn 启动时,它会导入您的应用程序并确定哪些端点可用 - 但现在您自己的脚本不再是应用程序的主要上下文,因此 __name__ == "__main__"
中的任何内容块不会 运行.
一旦将插件注册块移出该范围,您就会看到预期的行为:
plugins = load_plugins()
for plugin in plugins:
"""Register the plugins router."""
if "router" in plugin.__dir__():
app_router = plugin.router
app.include_router(app_router, prefix='/foo') # I'd let the plugin name be the prefix here to avoid plugins using the same prefix
if __name__ == "__main__":
uvicorn.run("server:app", host="localhost", port=8000, reload=True)