Compare commits
1 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
40d25d2990 |
|
|
@ -5,10 +5,9 @@ on:
|
|||
branches: [master]
|
||||
paths-ignore:
|
||||
- 'requirements.txt'
|
||||
- '*RuntimeDockerfile'
|
||||
- 'RuntimeDockerfile'
|
||||
- '.gitignore'
|
||||
- 'README.md'
|
||||
- 'pyproject.toml'
|
||||
- '.gitea/workflows/**'
|
||||
|
||||
|
||||
|
|
@ -28,8 +27,16 @@ jobs:
|
|||
- run: |
|
||||
var=${{ gitea.repository }}
|
||||
repo=${var##*/}
|
||||
version=$(grep -oP '(?<=version = ")(.*)(?=")' "pyproject.toml")
|
||||
new_version="v${version}"
|
||||
url="https://hub.airpig.cn/api/v2.0/projects/library/repositories/${repo}/artifacts?page=1&page_size=10&with_tag=true&with_label=false&with_scan_overview=false&with_signature=false&with_immutable_status=false&with_accessory=false"
|
||||
version=$(curl -X 'GET' $url \
|
||||
-H 'accept: application/json' \
|
||||
-H 'X-Accept-Vulnerabilities: application/vnd.security.vulnerability.report; version=1.1, application/vnd.scanner.adapter.vuln.report.harbor+json; version=1.0' \
|
||||
-u 'admin:Chenweijia!' | jq '.[0].tags[0].name')
|
||||
if [ ! $version ]; then
|
||||
new_version=v1.0.0
|
||||
else
|
||||
new_version=$(echo $version | sed 's/\"//g' | awk -F. '{$NF = $NF + 1;} 1' OFS=.)
|
||||
fi
|
||||
docker build -t hub.airpig.cn/library/$repo:$new_version .
|
||||
docker push hub.airpig.cn/library/$repo:$new_version
|
||||
docker rmi hub.airpig.cn/library/$repo:$new_version
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ on:
|
|||
paths:
|
||||
- 'requirements.txt'
|
||||
- 'poetry.lock'
|
||||
- '*RuntimeDockerfile'
|
||||
- 'pyproject.toml'
|
||||
- 'RuntimeDockerfile'
|
||||
|
||||
jobs:
|
||||
build-runtime:
|
||||
|
|
@ -24,9 +25,18 @@ jobs:
|
|||
- run: |
|
||||
var=${{ gitea.repository }}
|
||||
repo=${var##*/}"-runtime"
|
||||
version=$(grep -oP '(?<=version = ")(.*)(?=")' "pyproject.toml")
|
||||
new_version="v${version}"
|
||||
docker build -t hub.airpig.cn/library/$repo:$new_version -f AlpineRuntimeDockerfile .
|
||||
echo $repo
|
||||
url="https://hub.airpig.cn/api/v2.0/projects/library/repositories/${repo}/artifacts?page=1&page_size=10&with_tag=true&with_label=false&with_scan_overview=false&with_signature=false&with_immutable_status=false&with_accessory=false"
|
||||
version=$(curl -X 'GET' $url \
|
||||
-H 'accept: application/json' \
|
||||
-H 'X-Accept-Vulnerabilities: application/vnd.security.vulnerability.report; version=1.1, application/vnd.scanner.adapter.vuln.report.harbor+json; version=1.0' \
|
||||
-u 'admin:Chenweijia!' | jq '.[0].tags[0].name')
|
||||
if [ ! $version ]; then
|
||||
new_version=v1.0.0
|
||||
else
|
||||
new_version=$(echo $version | sed 's/\"//g' | awk -F. '{$NF = $NF + 1;} 1' OFS=.)
|
||||
fi
|
||||
docker build -t hub.airpig.cn/library/$repo:$new_version -f RuntimeDockerfile .
|
||||
docker push hub.airpig.cn/library/$repo:$new_version
|
||||
docker rmi hub.airpig.cn/library/$repo:$new_version
|
||||
- run: echo "This job's status is ${{ job.status }}."
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
FROM python:3.11-alpine as builder
|
||||
|
||||
RUN pip install poetry -i https://mirrors.aliyun.com/pypi/simple/
|
||||
|
||||
WORKDIR /venv
|
||||
|
||||
COPY poetry.lock pyproject.toml /venv/
|
||||
|
||||
RUN poetry config virtualenvs.options.no-pip true \
|
||||
&& poetry config virtualenvs.options.no-setuptools true \
|
||||
&& poetry config virtualenvs.in-project true \
|
||||
&& poetry install
|
||||
|
||||
|
||||
FROM python:3.11-alpine as release
|
||||
|
||||
COPY --from=builder /venv /venv
|
||||
|
||||
ENV PATH="/venv/.venv/bin:${PATH}"
|
||||
|
||||
RUN chmod a+x /venv/.venv/bin/activate \
|
||||
&& source /venv/.venv/bin/activate
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . /app
|
||||
|
||||
ENV FAST_API_ENV=prod
|
||||
|
||||
CMD ["/usr/local/bin/uvicorn", "main:fast_api_app", "--reload", "--host", "0.0.0.0", "--port", "80"]
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
# FastAPI App 文档
|
||||
|
||||
## 0 开发说明
|
||||
Python(3.10+) and pip(20.2.4+)
|
||||
Python(3.8.6+) and pip(20.2.4+)
|
||||
### 开发命名规范
|
||||
> * 避免采用的名字
|
||||
> 不要使用字符‘l’(小写字母el),‘O’(大写字母oh)或‘I’(大写字母eye)作为单字符变量名。
|
||||
|
|
@ -32,12 +32,12 @@ database=test
|
|||
|
||||
## 2 开发环境下安装依赖和运行项目
|
||||
``` bash
|
||||
pip install poetry -i https://pypi.tuna.tsinghua.edu.cn/simple/ \
|
||||
pip install poetry -i https://mirrors.aliyun.com/pypi/simple/ \
|
||||
&& poetry source add --priority=primary mirrors https://pypi.tuna.tsinghua.edu.cn/simple/ \
|
||||
&& poetry config virtualenvs.path /install \
|
||||
&& poetry install
|
||||
./start.bat (windows)
|
||||
./start.sh (mac/linux)
|
||||
./start.sh (mac)
|
||||
```
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,11 @@ class MySQLConfig(BaseSettings):
|
|||
|
||||
@property
|
||||
def sqlalchemy_db_uri(self):
|
||||
return f"mysql+pymysql://{self.username}:{self.password}@{self.host}:{self.port}/{self.database}?charset=utf8"
|
||||
return f"mysql+pymysql://{self.username}:{self.password}@{self.host}:{self.port}/{self.database}?charset=utf8mb4"
|
||||
|
||||
@property
|
||||
def async_sqlalchemy_db_uri(self):
|
||||
return f"mysql+aiomysql://{self.username}:{self.password}@{self.host}:{self.port}/{self.database}?charset=utf8mb4"
|
||||
|
||||
class RedisConfig(RedisSettings):
|
||||
redis_host: Optional[str] = 'localhost'
|
||||
|
|
|
|||
51
main.py
51
main.py
|
|
@ -1,26 +1,27 @@
|
|||
import logging.config as logging_config
|
||||
import os
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
import fastapi_plugins
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.exceptions import HTTPException, RequestValidationError
|
||||
# from fastapi.middleware.wsgi import WSGIMiddleware
|
||||
from fastapi_sqlalchemy import DBSessionMiddleware
|
||||
from authx.exceptions import AuthXException
|
||||
from fastapi.middleware.wsgi import WSGIMiddleware
|
||||
from fastapi_async_sqlalchemy import SQLAlchemyMiddleware
|
||||
|
||||
from config import init_config
|
||||
# from src.middleware.flask import flask_app
|
||||
from src.utils.exception import (http_exception_handler,
|
||||
request_validation_error_handler)
|
||||
|
||||
from src.utils.exception import http_exception_handler, request_validation_error_handler, authx_exception_handler
|
||||
# 请求限制
|
||||
import redis.asyncio as aio_redis
|
||||
from fastapi_limiter import FastAPILimiter
|
||||
|
||||
|
||||
def create_app():
|
||||
mysql_config, redis_config = init_config()
|
||||
app = FastAPI()
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
mysql_config, redis_config = init_config()
|
||||
# 添加sqlalchemy数据库中间件
|
||||
# once the middleware is applied, any route can then access the database session from the global ``db``
|
||||
app.add_middleware(SQLAlchemyMiddleware, db_url=mysql_config.async_sqlalchemy_db_uri)
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
# 创建日志文件夹和临时文件上传文件夹
|
||||
if not os.path.exists("files"):
|
||||
os.mkdir("files")
|
||||
|
|
@ -31,33 +32,25 @@ def create_app():
|
|||
logging_config.fileConfig('conf/log.ini')
|
||||
# 初始化配置文件
|
||||
# Redis 缓存初始化
|
||||
print(redis_config)
|
||||
await fastapi_plugins.redis_plugin.init_app(app, redis_config)
|
||||
await fastapi_plugins.redis_plugin.init()
|
||||
# 请求限制
|
||||
await FastAPILimiter.init(redis=aio_redis.from_url("redis://localhost:6379", encoding="utf8"))
|
||||
yield
|
||||
# 应用关闭时,关闭redis连接
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown_event():
|
||||
await fastapi_plugins.redis_plugin.terminate()
|
||||
await FastAPILimiter.close()
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
# 添加sqlalchemy数据库中间件
|
||||
# once the middleware is applied, any route can then access the database session from the global ``db``
|
||||
app.add_middleware(DBSessionMiddleware, db_url=mysql_config.sqlalchemy_db_uri)
|
||||
|
||||
# 添加异常处理
|
||||
app.add_exception_handler(HTTPException, http_exception_handler)
|
||||
app.add_exception_handler(RequestValidationError, request_validation_error_handler)
|
||||
# AuthX异常处理
|
||||
app.add_exception_handler(AuthXException, authx_exception_handler)
|
||||
|
||||
|
||||
# 可以在这里挂载Flask的应用,复用之前项目的相关代码
|
||||
# app.mount("/v1", WSGIMiddleware(flask_app))
|
||||
|
||||
|
||||
# 在这里添加API route
|
||||
from src.api import example,auth_example
|
||||
app.include_router(example.router, tags=["API示例"], prefix="/v1/example")
|
||||
app.include_router(auth_example.router, tags=["认证示例"], prefix="/v1/auth_example")
|
||||
from src.api import example
|
||||
app.include_router(example.router, tags=["API示例"], prefix="/example")
|
||||
|
||||
return app
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -127,31 +127,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "authx"
|
||||
version = "1.3.0"
|
||||
description = "Ready to use and customizable Authentications and Oauth2 management for FastAPI"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "authx-1.3.0-py3-none-any.whl", hash = "sha256:347485b78a5016e655ac78b0ff0dd0c2aef3935148af4a863145399a20c718e8"},
|
||||
{file = "authx-1.3.0.tar.gz", hash = "sha256:1f7c102a74d082c6a8850c26ff1e8fba73a146589fd95d84531df41e091586a5"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
fastapi = ">=0.111.0"
|
||||
pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<3.0.0"
|
||||
pydantic-settings = ">=2.1.0"
|
||||
pyjwt = {version = ">=2.6.0,<3.0.0", extras = ["crypto"]}
|
||||
python-dateutil = ">=2.8,<3.0.0"
|
||||
python-jose = ">=3.3.0,<4.0.0"
|
||||
pytz = ">=2023.3,<2025.0"
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "captcha"
|
||||
version = "0.6.0"
|
||||
|
|
@ -187,90 +162,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "cffi"
|
||||
version = "1.17.0"
|
||||
description = "Foreign Function Interface for Python calling C code."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-win32.whl", hash = "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-win32.whl", hash = "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29"},
|
||||
{file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pycparser = "*"
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "3.3.2"
|
||||
|
|
@ -410,60 +301,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "43.0.0"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "cryptography-43.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-win32.whl", hash = "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-win32.whl", hash = "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709"},
|
||||
{file = "cryptography-43.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c6d112bf61c5ef44042c253e4859b3cbbb50df2f78fa8fae6747a7814484a70"},
|
||||
{file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:844b6d608374e7d08f4f6e6f9f7b951f9256db41421917dfb2d003dde4cd6b66"},
|
||||
{file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51956cf8730665e2bdf8ddb8da0056f699c1a5715648c1b0144670c1ba00b48f"},
|
||||
{file = "cryptography-43.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:aae4d918f6b180a8ab8bf6511a419473d107df4dbb4225c7b48c5c9602c38c7f"},
|
||||
{file = "cryptography-43.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:232ce02943a579095a339ac4b390fbbe97f5b5d5d107f8a08260ea2768be8cc2"},
|
||||
{file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5bcb8a5620008a8034d39bce21dc3e23735dfdb6a33a06974739bfa04f853947"},
|
||||
{file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:08a24a7070b2b6804c1940ff0f910ff728932a9d0e80e7814234269f9d46d069"},
|
||||
{file = "cryptography-43.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e9c5266c432a1e23738d178e51c2c7a5e2ddf790f248be939448c0ba2021f9d1"},
|
||||
{file = "cryptography-43.0.0.tar.gz", hash = "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
|
||||
docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"]
|
||||
nox = ["nox"]
|
||||
pep8test = ["check-sdist", "click", "mypy", "ruff"]
|
||||
sdist = ["build"]
|
||||
ssh = ["bcrypt (>=3.1.5)"]
|
||||
test = ["certifi", "cryptography-vectors (==43.0.0)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
|
||||
test-randomorder = ["pytest-randomly"]
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "dnspython"
|
||||
version = "2.6.1"
|
||||
|
|
@ -489,29 +326,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "ecdsa"
|
||||
version = "0.19.0"
|
||||
description = "ECDSA cryptographic signature library (pure python)"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
files = [
|
||||
{file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"},
|
||||
{file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
six = ">=1.9.0"
|
||||
|
||||
[package.extras]
|
||||
gmpy = ["gmpy"]
|
||||
gmpy2 = ["gmpy2"]
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "email-validator"
|
||||
version = "2.1.1"
|
||||
|
|
@ -583,6 +397,26 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "fastapi-async-sqlalchemy"
|
||||
version = "0.6.1"
|
||||
description = "SQLAlchemy middleware for FastAPI"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "fastapi-async-sqlalchemy-0.6.1.tar.gz", hash = "sha256:c4e0c9832e5e7ef9d647e7eb134e6d326945dca28323e503a21f3d4ab2dee160"},
|
||||
{file = "fastapi_async_sqlalchemy-0.6.1-py3-none-any.whl", hash = "sha256:0f4edfbc7b0f5fc2e0017cd903a953f4e0b01870f09e86cd0bc79087f3606bc4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
SQLAlchemy = ">=1.4.19"
|
||||
starlette = ">=0.13.6"
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "fastapi-cli"
|
||||
version = "0.0.4"
|
||||
|
|
@ -605,26 +439,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "fastapi-limiter"
|
||||
version = "0.1.6"
|
||||
description = "A request rate limiter for fastapi"
|
||||
optional = false
|
||||
python-versions = ">=3.9,<4.0"
|
||||
files = [
|
||||
{file = "fastapi_limiter-0.1.6-py3-none-any.whl", hash = "sha256:2e53179a4208b8f2c8795e38bb001324d3dc37d2800ff49fd28ec5caabf7a240"},
|
||||
{file = "fastapi_limiter-0.1.6.tar.gz", hash = "sha256:6f5fde8efebe12eb33861bdffb91009f699369a3c2862cdc7c1d9acf912ff443"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
fastapi = "*"
|
||||
redis = ">=4.2.0rc1"
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "fastapi-plugins"
|
||||
version = "0.13.0"
|
||||
|
|
@ -656,26 +470,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "fastapi-sqlalchemy"
|
||||
version = "0.2.1"
|
||||
description = "Adds simple SQLAlchemy support to FastAPI"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "FastAPI-SQLAlchemy-0.2.1.tar.gz", hash = "sha256:7a9d44e46cbc73c3f5ee8c444f7e0bcd3d01370a878740abd4cd4d2e900ce9af"},
|
||||
{file = "FastAPI_SQLAlchemy-0.2.1-py3-none-any.whl", hash = "sha256:d3bfc6d9388a73a2c3726bc6bd7764cd82debfa71c16e3991c544b9701f48d96"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
SQLAlchemy = ">=1.2"
|
||||
starlette = ">=0.12.9"
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "greenlet"
|
||||
version = "3.0.3"
|
||||
|
|
@ -1015,22 +809,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "itsdangerous"
|
||||
version = "2.2.0"
|
||||
description = "Safely pass data to untrusted environments and back."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"},
|
||||
{file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"},
|
||||
]
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "jinja2"
|
||||
version = "3.1.4"
|
||||
|
|
@ -1356,38 +1134,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "pyasn1"
|
||||
version = "0.6.0"
|
||||
description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"},
|
||||
{file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"},
|
||||
]
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "2.22"
|
||||
description = "C parser in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
|
||||
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
|
||||
]
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.7.3"
|
||||
|
|
@ -1551,31 +1297,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "pyjwt"
|
||||
version = "2.9.0"
|
||||
description = "JSON Web Token implementation in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"},
|
||||
{file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""}
|
||||
|
||||
[package.extras]
|
||||
crypto = ["cryptography (>=3.4.0)"]
|
||||
dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"]
|
||||
docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"]
|
||||
tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "pymysql"
|
||||
version = "1.1.1"
|
||||
|
|
@ -1596,25 +1317,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.9.0.post0"
|
||||
description = "Extensions to the standard Python datetime module"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||
files = [
|
||||
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
|
||||
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
six = ">=1.5"
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.0.1"
|
||||
|
|
@ -1634,32 +1336,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "python-jose"
|
||||
version = "3.3.0"
|
||||
description = "JOSE implementation in Python"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "python-jose-3.3.0.tar.gz", hash = "sha256:55779b5e6ad599c6336191246e95eb2293a9ddebd555f796a65f838f07e5d78a"},
|
||||
{file = "python_jose-3.3.0-py2.py3-none-any.whl", hash = "sha256:9b1376b023f8b298536eedd47ae1089bcdb848f1535ab30555cd92002d78923a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
ecdsa = "!=0.15"
|
||||
pyasn1 = "*"
|
||||
rsa = "*"
|
||||
|
||||
[package.extras]
|
||||
cryptography = ["cryptography (>=3.4.0)"]
|
||||
pycrypto = ["pyasn1", "pycrypto (>=2.6.0,<2.7.0)"]
|
||||
pycryptodome = ["pyasn1", "pycryptodome (>=3.3.1,<4.0.0)"]
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "python-json-logger"
|
||||
version = "2.0.7"
|
||||
|
|
@ -1871,25 +1547,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "4.9"
|
||||
description = "Pure-Python RSA implementation"
|
||||
optional = false
|
||||
python-versions = ">=3.6,<4"
|
||||
files = [
|
||||
{file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"},
|
||||
{file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyasn1 = ">=0.1.3"
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "shellingham"
|
||||
version = "1.5.4"
|
||||
|
|
@ -1906,22 +1563,6 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
files = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
]
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "mirrors"
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.1"
|
||||
|
|
@ -2475,4 +2116,4 @@ reference = "mirrors"
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "d43623d3a4da31efcc1a54e1318db9ef412e1791ae9af50374d0c5d6faae6357"
|
||||
content-hash = "a2d3f4dd231a21f18cf3bb4faabebaa59ee95ec5597b388c83326036eda1b458"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "fastapi-template"
|
||||
version = "0.1.5"
|
||||
name = "fastapi-app-template"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["chenwj113 <chenwj113@gmail.com>"]
|
||||
license = "MIT"
|
||||
|
|
@ -13,15 +13,12 @@ sqlalchemy = "2.0.0"
|
|||
aioredis = "2.0.1"
|
||||
aiomysql = "0.1.1"
|
||||
fastapi-plugins = "0.13.0"
|
||||
fastapi-sqlalchemy = "^0.2.1"
|
||||
passlib = "^1.7.4"
|
||||
pytz = "^2024.1"
|
||||
qiniu = "^7.13.2"
|
||||
pillow = "^10.4.0"
|
||||
captcha = "^0.6.0"
|
||||
fastapi-limiter = "^0.1.6"
|
||||
authx = "^1.3.0"
|
||||
itsdangerous = "^2.2.0"
|
||||
fastapi-async-sqlalchemy = "^0.6.1"
|
||||
|
||||
|
||||
[[tool.poetry.source]]
|
||||
|
|
|
|||
100
requirements.txt
100
requirements.txt
|
|
@ -1,75 +1,25 @@
|
|||
--index-url https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
|
||||
aiojobs==1.2.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
aiomysql==0.1.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
aioredis==2.0.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
annotated-types==0.7.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
anyio==4.4.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
async-timeout==4.0.3 ; python_version >= "3.10" and python_version < "4.0"
|
||||
authx==1.3.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
captcha==0.6.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
certifi==2024.6.2 ; python_version >= "3.10" and python_version < "4.0"
|
||||
cffi==1.17.0 ; python_version >= "3.10" and python_version < "4.0" and platform_python_implementation != "PyPy"
|
||||
charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0"
|
||||
click==8.1.7 ; python_version >= "3.10" and python_version < "4.0"
|
||||
colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and (sys_platform == "win32" or platform_system == "Windows")
|
||||
cryptography==43.0.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
dnspython==2.6.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
ecdsa==0.19.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
email-validator==2.1.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
exceptiongroup==1.2.1 ; python_version >= "3.10" and python_version < "3.11"
|
||||
fastapi-cli==0.0.4 ; python_version >= "3.10" and python_version < "4.0"
|
||||
fastapi-limiter==0.1.6 ; python_version >= "3.10" and python_version < "4.0"
|
||||
fastapi-plugins==0.13.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
fastapi-sqlalchemy==0.2.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
fastapi==0.111.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
greenlet==3.0.3 ; python_version >= "3.10" and python_version < "4.0" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32")
|
||||
h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
hiredis==2.3.2 ; python_version >= "3.10" and python_version < "4.0"
|
||||
httpcore==1.0.5 ; python_version >= "3.10" and python_version < "4.0"
|
||||
httptools==0.6.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
httpx==0.27.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
idna==3.7 ; python_version >= "3.10" and python_version < "4.0"
|
||||
itsdangerous==2.2.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
jinja2==3.1.4 ; python_version >= "3.10" and python_version < "4.0"
|
||||
markdown-it-py==3.0.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0"
|
||||
mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0"
|
||||
orjson==3.10.4 ; python_version >= "3.10" and python_version < "4.0"
|
||||
passlib==1.7.4 ; python_version >= "3.10" and python_version < "4.0"
|
||||
pillow==10.4.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
pyasn1==0.6.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
pycparser==2.22 ; python_version >= "3.10" and python_version < "4.0" and platform_python_implementation != "PyPy"
|
||||
pydantic-core==2.18.4 ; python_version >= "3.10" and python_version < "4.0"
|
||||
pydantic-settings==2.3.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
pydantic==2.7.3 ; python_version >= "3.10" and python_version < "4.0"
|
||||
pygments==2.18.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
pyjwt[crypto]==2.9.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
pymysql==1.1.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
python-dateutil==2.9.0.post0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
python-jose==3.3.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
python-json-logger==2.0.7 ; python_version >= "3.10" and python_version < "4.0"
|
||||
python-multipart==0.0.9 ; python_version >= "3.10" and python_version < "4.0"
|
||||
pytz==2024.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
qiniu==7.13.2 ; python_version >= "3.10" and python_version < "4.0"
|
||||
redis==5.0.5 ; python_version >= "3.10" and python_version < "4.0"
|
||||
redis[hiredis]==5.0.5 ; python_version >= "3.10" and python_version < "4.0"
|
||||
requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0"
|
||||
rich==13.7.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
rsa==4.9 ; python_version >= "3.10" and python_version < "4"
|
||||
shellingham==1.5.4 ; python_version >= "3.10" and python_version < "4.0"
|
||||
six==1.16.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
sqlalchemy==2.0.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0"
|
||||
tenacity==8.3.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
typer==0.12.3 ; python_version >= "3.10" and python_version < "4.0"
|
||||
typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0"
|
||||
ujson==5.10.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
urllib3==2.2.2 ; python_version >= "3.10" and python_version < "4.0"
|
||||
uvicorn[standard]==0.30.1 ; python_version >= "3.10" and python_version < "4.0"
|
||||
uvloop==0.19.0 ; (sys_platform != "win32" and sys_platform != "cygwin") and platform_python_implementation != "PyPy" and python_version >= "3.10" and python_version < "4.0"
|
||||
watchfiles==0.22.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
websockets==12.0 ; python_version >= "3.10" and python_version < "4.0"
|
||||
aiofiles==22.1.0
|
||||
aioredis==2.0.1
|
||||
aiomysql==0.1.1
|
||||
bcrypt==4.0.1
|
||||
email_validator>=2.0.0
|
||||
fastapi==0.111.0
|
||||
fastapi-plugins==0.13.0
|
||||
FastAPI-SQLAlchemy==0.2.1
|
||||
pydantic>=2.0.0
|
||||
pydantic-settings==2.2.1
|
||||
# pydantic-sqlalchemy==0.0.9
|
||||
python-multipart>=0.0.7
|
||||
pytest==7.2.1
|
||||
requests==2.28.2
|
||||
sqlacodegen==2.3.0
|
||||
SQLAlchemy==2.0.1
|
||||
uvicorn==0.20.0
|
||||
PyJWT==2.6.0
|
||||
passlib==1.7.4
|
||||
Pillow==9.4.0
|
||||
captcha==0.4
|
||||
jinja2==3.1.2
|
||||
pycryptodome==3.17
|
||||
qiniu==7.10.0
|
||||
pytz==2022.7.1
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
from fastapi import APIRouter, HTTPException, Depends
|
||||
# 校验授权token
|
||||
from src.middleware.auth import security
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get('/', dependencies=[Depends(security.access_token_required)])
|
||||
def index():
|
||||
return {"message": "Hello World"}
|
||||
|
||||
@router.get('/login')
|
||||
def login(username: str, password: str):
|
||||
if username == "test" and password == "test":
|
||||
token = security.create_access_token(uid=username)
|
||||
return {"access_token": token}
|
||||
raise HTTPException(401, detail={"message": "Bad credentials"})
|
||||
|
|
@ -5,10 +5,8 @@ import aioredis
|
|||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from fastapi_plugins import depends_redis
|
||||
from fastapi_sqlalchemy import db
|
||||
from fastapi_async_sqlalchemy import db
|
||||
from sqlalchemy.sql import text
|
||||
from fastapi_limiter.depends import RateLimiter
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from src.service.example import get_user_by_id
|
||||
|
|
@ -17,8 +15,8 @@ from src.dtos.example import UserExampleListPagesResult
|
|||
|
||||
router = APIRouter()
|
||||
|
||||
# 并发数限制 每5秒最多100次请求
|
||||
@router.get("/", dependencies=[Depends(RateLimiter(times=100, seconds=5))])
|
||||
|
||||
@router.get("/")
|
||||
def index():
|
||||
return {"msg": "This is Index Page"}
|
||||
|
||||
|
|
@ -66,8 +64,10 @@ async def get_user_list_pages(page: int = Query(..., description="当前页码")
|
|||
# 数据库查询
|
||||
@router.get('/get_db_version')
|
||||
async def get_db_version():
|
||||
result = db.session.execute(text("SELECT version()")).first()
|
||||
return dict(result=result.tuple()[0])
|
||||
async with db():
|
||||
result = await db.session.execute(text("SELECT version()"))
|
||||
version = result.first().tuple()[0]
|
||||
return dict(result=version)
|
||||
|
||||
# Redis 缓存查询
|
||||
@router.get("/ping")
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
from authx import AuthX, AuthXConfig
|
||||
from datetime import timedelta
|
||||
|
||||
config = AuthXConfig()
|
||||
config.JWT_ALGORITHM = "HS256"
|
||||
config.JWT_SECRET_KEY = "SECRET_KEY"
|
||||
config.JWT_TOKEN_LOCATION = ["headers", "query", "cookies", "json"]
|
||||
config.JWT_HEADER_NAME = "X-Token"
|
||||
config.JWT_HEADER_TYPE = ""
|
||||
# access token expires in 24 hours
|
||||
config.JWT_ACCESS_TOKEN_EXPIRES = timedelta(hours=24)
|
||||
|
||||
security = AuthX(config=config)
|
||||
|
|
@ -4,7 +4,7 @@ from traceback import format_exc
|
|||
import struct
|
||||
import sqlalchemy
|
||||
from sqlalchemy import text
|
||||
from fastapi_sqlalchemy import db
|
||||
from fastapi_async_sqlalchemy import db
|
||||
from jinja2 import Template
|
||||
from pymysql import err
|
||||
from pymysql.constants import FIELD_TYPE
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import logging
|
||||
from collections import defaultdict
|
||||
|
||||
from fastapi import Request, status
|
||||
from fastapi.exceptions import HTTPException, RequestValidationError
|
||||
from fastapi.responses import JSONResponse
|
||||
import authx.exceptions as authx_exceptions
|
||||
|
||||
from src.dtos import BaseResponse, ErrorModel
|
||||
|
||||
logger = logging.getLogger("uvicorn.error")
|
||||
|
|
@ -12,32 +11,35 @@ logger = logging.getLogger("uvicorn.error")
|
|||
|
||||
def request_validation_error_handler(req: Request, exc: RequestValidationError):
|
||||
"""
|
||||
请求校验错误处理
|
||||
请求响应校验错误处理
|
||||
:param req:
|
||||
:param exc:
|
||||
:return:
|
||||
"""
|
||||
errors = exc.errors()
|
||||
logger.error(f"{req.method} {req.url} , errors: {errors}")
|
||||
group_err = defaultdict(list)
|
||||
for err in errors:
|
||||
group_err[err["type"]].append(err)
|
||||
details = ""
|
||||
for err_type, err_list in group_err.items():
|
||||
match err_type:
|
||||
case "missing" | "value_error.missing" :
|
||||
details += f"缺少字段:{', '.join([err['loc'][-1] for err in err_list])};"
|
||||
case "value_error.jsondecode":
|
||||
details += "请求参数JSON编码有误;"
|
||||
case "value_error":
|
||||
details += "; ".join([err["msg"] for err in err_list])
|
||||
case "type_error":
|
||||
details += "; ".join([err["msg"].replace("value", f"{err['loc'][1]}") for err in err_list])
|
||||
case "type_error.none.not_allowed":
|
||||
details += f"字段:{', '.join([err['loc'][-1] for err in err_list])} 不能为空;"
|
||||
case _:
|
||||
pass
|
||||
err_model = ErrorModel(code=status.HTTP_400_BAD_REQUEST, message="接口请求校验异常", details=details)
|
||||
response_errors = [error for error in errors if error["loc"][0] == "response"]
|
||||
if len(response_errors) > 0:
|
||||
message = "接口响应异常 "
|
||||
else:
|
||||
message = "接口请求异常 "
|
||||
json_err = [err["msg"] for err in errors if "value_error.jsondecode" == err["type"]]
|
||||
if json_err:
|
||||
message += "请求参数JSON编码有误;"
|
||||
value_err = [err["msg"] for err in errors if "value_error" == err["type"]]
|
||||
if value_err:
|
||||
message += "; ".join(value_err)
|
||||
missing_err = [err["loc"][-1] for err in errors if "value_error.missing" == err["type"]]
|
||||
if missing_err:
|
||||
message += "缺少字段:{} ".format(", ".join(missing_err))
|
||||
type_err = [err["msg"].replace("value", f"{err['loc'][1]}") for err in errors if "type_error" == err["type"]]
|
||||
if type_err:
|
||||
message += "; ".join(type_err)
|
||||
not_none_err = [err["loc"][-1] for err in errors if "type_error.none.not_allowed" == err["type"]]
|
||||
if not_none_err:
|
||||
message += "字段:{} 不能为空".format(", ".join(not_none_err))
|
||||
|
||||
err_model = ErrorModel(code=status.HTTP_400_BAD_REQUEST, message=message, details=message)
|
||||
res = BaseResponse(error=err_model)
|
||||
return JSONResponse(status_code=200, content=res.dict())
|
||||
|
||||
|
|
@ -52,23 +54,4 @@ def http_exception_handler(req: Request, exc: HTTPException):
|
|||
logger.error(f"{req.method} {req.url} , exception:{exc.detail}")
|
||||
err = ErrorModel(code=exc.status_code, message=exc.detail)
|
||||
res = BaseResponse(result=None, error=err)
|
||||
return JSONResponse(status_code=exc.status_code, content=res.model_dump())
|
||||
|
||||
|
||||
def authx_exception_handler(req: Request, exc: authx_exceptions.AuthXException):
|
||||
"""
|
||||
AuthX Exception 错误处理
|
||||
:param req:
|
||||
:param exc:
|
||||
:return:
|
||||
"""
|
||||
logger.error(f"{req.method} {req.url} , exception:{exc}")
|
||||
match type(exc):
|
||||
case authx_exceptions.MissingTokenError:
|
||||
err = ErrorModel(code=status.HTTP_401_UNAUTHORIZED, message="请求头缺失X-Token")
|
||||
case authx_exceptions.JWTDecodeError:
|
||||
err = ErrorModel(code=status.HTTP_401_UNAUTHORIZED, message="X-Token解析失败")
|
||||
case _:
|
||||
err = ErrorModel(code=status.HTTP_401_UNAUTHORIZED, message="未知的错误导致认证失败")
|
||||
res = BaseResponse(result=None, error=err)
|
||||
return JSONResponse(status_code=err.code, content=res.model_dump())
|
||||
return JSONResponse(status_code=exc.status_code, content=res.dict())
|
||||
Loading…
Reference in New Issue