【问题标题】:fastapi - import config from main.pyfastapi - 从 main.py 导入配置
【发布时间】:2020-07-07 17:21:33
【问题描述】:

我是 fastapi 的新手,到目前为止它真的很棒,但我很难找到一种干净的方式将我的应用配置导入另一个模块。

编辑:我需要能够在运行单元测试时更改配置

这是我的目录树:

/app
| __init__.py
| /router
| | __init__.py
| | my_router.py
| /test
| | test_api.py
| config.py
| main.py

这是我的main.py 文件:

from functools import lru_cache

from fastapi import FastAPI

from .router import my_router
from . import config

app = FastAPI()

app.include_router(
    my_router.router,
    prefix="/r",
    tags=["my-router"],
)


@lru_cache()
def get_setting():
    return config.Settings(admin_email="admin@domain.com")


@app.get('/')
def hello():
    return 'Hello world'

这里是router.py

from fastapi import APIRouter

from ..main import get_setting

router = APIRouter()

@router.get('/test')
def get_param_list(user_id: int):
    config = get_setting()
    return 'Import Ok'

这是配置文件

from pydantic import BaseSettings


class Settings(BaseSettings):
    param_folder: str = "param"
    result_folder: str = "output"

    class Config:
        env_prefix = "APP_"

然后运行 ​​uvicorn app.main:app --reload 我得到了:ERROR: Error loading ASGI app. Could not import module "app.main". 我猜是因为一种循环导入。但是我不知道如何将我的配置传递给我的路由器?

感谢您的帮助:)

【问题讨论】:

    标签: python python-3.x python-import fastapi


    【解决方案1】:

    直接在config.py中设置lru缓存怎么样。

    from functools import lru_cache
    from pydantic import BaseSettings
    
    
    class Settings(BaseSettings):
        admin_email: str = "admin@example.com"
        param_folder: str = "param"
        result_folder: str = "output"
    
        class Config:
            env_prefix = "APP_"
    
    @lru_cache()
    def get_setting():
        return Settings()
    

    还有my_router.py

    from fastapi import APIRouter, Depends
    
    from ..config import Settings, get_setting
    
    router = APIRouter()
    
    @router.get('/test')
    def get_param_list(config: Settings = Depends(get_setting)):
        return config
    

    还有test.py

    from fastapi.testclient import TestClient
    
    from . import config, main
    
    client = TestClient(main.app)
    
    
    def get_settings_override():
        return config.Settings(admin_email="testing_admin@example.com")
    
    
    main.app.dependency_overrides[config.get_settings] = get_settings_override
    
    def test_app():
        response = client.get("/r/test")
        data = response.json()
        assert data == config.Settings(admin_email="testing_admin@example.com")
    

    【讨论】:

    【解决方案2】:

    我使用 FastAPI 依赖系统使其正常工作,并按照 @Kassym Dorsel 的建议,将 lru_cache 移动到 config.py

    唯一的缺点是我必须在每个需要设置的函数调用中添加setting: config.Setting = Depends(config.get_setting),这是相当“重”的。

    我是这样做的:

    config.py文件:

    from pydantic import BaseSettings
    
    
    class Settings(BaseSettings):
        param_folder: str = "param"
        result_folder: str = "output"
    
        class Config:
            env_prefix = "APP_"
    
    @lru_cache()
    def get_setting():
        return config.Settings(admin_email="admin@domain.com")
    

    main.py文件:

    from functools import lru_cache
    
    from fastapi import FastAPI
    
    from .router import my_router
    
    app = FastAPI()
    
    app.include_router(
        my_router.router,
        prefix="/r",
        tags=["my-router"],
    )
    
    @app.get('/')
    def hello():
        return 'Hello world'
    

    router.py文件:

    from fastapi import APIRouter, Depends
    
    from .. import config
    
    router = APIRouter()
    
    @router.get('/test')
    def get_param_list(user_id: int, setting: config.Setting = Depends(config.get_setting)):
        return setting
    

    这样我可以使用test_api.py 中的dependency_overrides 来更改测试的配置:

    from fastapi.testclient import TestClient
    
    from .. import config, server
    
    client = TestClient(server.app)
    
    TEST_PARAM_FOLDER = 'server/test/param'
    TEST_RESULT_FOLDER = 'server/test/result'
    
    def get_setting_override():
        return config.Setting(param_folder=TEST_PARAM_FOLDER, result_folder=TEST_RESULT_FOLDER)
    
    
    server.app.dependency_overrides[config.get_setting] = get_setting_override
    
    def test_1():
        ...
    

    【讨论】:

      【解决方案3】:

      唯一的缺点是我必须在每个需要设置的函数调用中添加设置:config.Setting = Depends(config.get_setting),这个设置相当“繁重”。

      您可以使用 fastapi_utils 包中的Class Based Views

      from fastapi import APIRouter, Depends
      from fastapi_utils.cbv import cbv
      from starlette import requests
      from logging import Logger
      from .. import config
      
      router = APIRouter()
      
      @cbv(router)
      class MyQueryCBV:
          settings: config.Setting = Depends(config.get_setting)  # you can introduce settings dependency here
      
          def __init__(self, r: requests.Request):  # called for each query
              self.logger: Logger = self.settings.logger
              self.logger.warning(str(r.headers))
      
          @router.get('/test')
          def get_param_list(self, user_id: int)
              self.logger.warning(f"get_param_list: {user_id}")
              return self.settings
      
          @router.get("/test2")
          def get_param_list2(self):
              self.logger.warning(f"get_param_list2")
              return self.settings
      

      【讨论】:

        猜你喜欢
        • 2022-07-20
        • 2019-05-10
        • 2023-01-06
        • 2023-01-30
        • 1970-01-01
        • 2020-02-06
        • 2019-11-16
        • 2019-11-21
        • 1970-01-01
        相关资源
        最近更新 更多