一个fastapi小项目的main文件示例

396 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

项目背景:导入Excel表,然后生成对应的指定格式的新的Excel表 依赖包版本如下:

[tool.poetry.dependencies]
python = "^3.8"
shici = {git = "https://gitee.com/waketzheng/shici.git"}
xlwt = "^1.3.0"
xlutils = "^2.0.0"
xlrd = "^2.0.1"
openpyxl = "^3.0.9"
fastapi = "^0.75.0"
python-dotenv = "^0.19.2"
python-multipart = "^0.0.5"
uvicorn = "^0.17.6"

main文件内容如下:

#!/usr/bin/env python
"""
Usage::

    $ ./main.py r  # Start server
"""
import re
import traceback
from datetime import datetime
from pathlib import Path

import shici
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.staticfiles import StaticFiles

from routers import api
from settings import DEBUG, MEDIA_ROOT, PORT

RE_VERSION = re.compile(r'version = "([.\w]+)"')
if not MEDIA_ROOT.exists():
    MEDIA_ROOT.mkdir()


def get_version(filename: str = "pyproject.toml") -> str:
    if not (p := Path(__file__).parent / filename).exists():
        p = p.resolve().parent.parent / filename
    if m := RE_VERSION.search(p.read_text()):
        return m.group(1)  # type: ignore
    return "1.0.0"


CURRENT_VERSION = get_version()

app_kwargs: dict = {"version": get_version()}
if DEBUG:
    app_kwargs["title"] = "Salary Tip--调试版"
    app_kwargs.update(debug=True)
else:
    app_kwargs["title"] = "洪荒之力-- Make it easy"
    app_kwargs["redoc_url"] = None


app = FastAPI(**app_kwargs)
app.mount("/media", StaticFiles(directory="media"), name="media")


@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start = datetime.now()
    try:
        response = await call_next(request)
    except AssertionError as e:
        response = JSONResponse({"detail": str(e)}, 400)
    except Exception:
        code = int(datetime.now().timestamp())
        error = traceback.format_exc()
        print(code, f"{request.url = }", error)
        if request.url.path.split("/")[-1].startswith("_"):
            # 内部接口直接返回错误详情
            response = JSONResponse({"detail": f"{code=}; {error = }"}, 500)
        else:
            response = JSONResponse({"detail": f"数据异常,请刷新页面后重试!({code})"}, 500)
    end = datetime.now()
    process_time = end - start
    cost = f"{round(process_time.total_seconds()*1000, 3)} ms"
    print(f"{start} --> {end} || Cost: {cost}")
    response.headers["X-Process-Time"] = cost
    response.headers["version"] = CURRENT_VERSION
    return response


app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


# routers
app.include_router(api.router, prefix="/api", tags=["api"])


@app.get("/")
async def home(request: Request):
    ip = request.client.host
    word = f"<p><i>{shici.random()}</i></p>"
    return HTMLResponse(word + f"<p>Your IP is: {ip}</p>")


@app.get("/robots.txt")
async def robots_txt():
    return """
    User-agent: *

    Disallow: /
    """


def main():
    import os
    import sys

    if not (sys_argv := sys.argv[1:]):
        print("No args, do nothing.")
        return
    cmd = f"uvicorn {Path(__file__).stem}:app --proxy-headers"
    if DEBUG:
        cmd += " --reload --debug --host 0.0.0.0"
    else:
        cmd += " --reload"
    if "r" in sys_argv:
        cmd += f" --port={PORT}"
    else:
        if (p := sys_argv[0]).isdigit():
            cmd += f" --port={p}"
        elif p == "clear":  # 清除redis缓存
            raise NotImplementedError

    print("-->", cmd)
    os.system(cmd)


if __name__ == "__main__":
    main()

启动服务: 直接执行如下命令

poetry run python main.py r