chore: 升级到 Python 3.14 并现代化代码

- 升级 Docker 基础镜像从 Python 3.12 到 3.14
- 更新 pyproject.toml 支持 Python 3.13/3.14
- 移除 Python 3.8/3.9/3.10/3.11 分类器
- 更新 black 和 mypy 配置目标版本
- 将 get_event_loop() 替换为 get_running_loop() 加上 RuntimeError 处理
- 简化 compute_cost_sync 中的 asyncio.run 使用
- Dict/List/Tuple/Set → dict/list/tuple/set (PEP 585)
- Optional[T] → T | None (PEP 604)
- Union[A, B] → A | B (PEP 604)
- 移除废弃的 typing 导入
- 移除不必要的字符串引号注解
This commit is contained in:
AAEE86
2026-01-30 03:10:21 +08:00
parent 3e75bc8964
commit 24d24f6829
255 changed files with 4062 additions and 4173 deletions

View File

@@ -1,8 +1,7 @@
"""OAuth 管理端点(管理员)。"""
from __future__ import annotations
from typing import Any, Dict, List, Optional
from typing import Any
from fastapi import APIRouter, Depends, Request
from pydantic import BaseModel, Field, ValidationError
@@ -27,24 +26,24 @@ class SupportedOAuthType(BaseModel):
default_authorization_url: str
default_token_url: str
default_userinfo_url: str
default_scopes: List[str]
default_scopes: list[str]
class OAuthProviderUpsertRequest(BaseModel):
display_name: str = Field(..., min_length=1, max_length=100)
client_id: str = Field(..., min_length=1, max_length=255)
client_secret: Optional[str] = Field(None, max_length=2048)
client_secret: str | None = Field(None, max_length=2048)
authorization_url_override: Optional[str] = Field(None, max_length=500)
token_url_override: Optional[str] = Field(None, max_length=500)
userinfo_url_override: Optional[str] = Field(None, max_length=500)
scopes: Optional[List[str]] = None
authorization_url_override: str | None = Field(None, max_length=500)
token_url_override: str | None = Field(None, max_length=500)
userinfo_url_override: str | None = Field(None, max_length=500)
scopes: list[str] | None = None
redirect_uri: str = Field(..., min_length=1, max_length=500)
frontend_callback_url: str = Field(..., min_length=1, max_length=500)
attribute_mapping: Optional[Dict[str, Any]] = None
extra_config: Optional[Dict[str, Any]] = None
attribute_mapping: dict[str, Any] | None = None
extra_config: dict[str, Any] | None = None
is_enabled: bool = False
force: bool = False
@@ -55,14 +54,14 @@ class OAuthProviderAdminResponse(BaseModel):
display_name: str
client_id: str
has_secret: bool
authorization_url_override: Optional[str] = None
token_url_override: Optional[str] = None
userinfo_url_override: Optional[str] = None
scopes: Optional[List[str]] = None
authorization_url_override: str | None = None
token_url_override: str | None = None
userinfo_url_override: str | None = None
scopes: list[str] | None = None
redirect_uri: str
frontend_callback_url: str
attribute_mapping: Optional[Dict[str, Any]] = None
extra_config: Optional[Dict[str, Any]] = None
attribute_mapping: dict[str, Any] | None = None
extra_config: dict[str, Any] | None = None
is_enabled: bool
@@ -77,19 +76,19 @@ class OAuthProviderTestRequest(BaseModel):
"""测试请求,使用表单数据而非数据库配置"""
client_id: str = Field(..., min_length=1)
client_secret: Optional[str] = None
authorization_url_override: Optional[str] = None
token_url_override: Optional[str] = None
client_secret: str | None = None
authorization_url_override: str | None = None
token_url_override: str | None = None
redirect_uri: str = Field(..., min_length=1)
@router.get("/supported-types", response_model=List[SupportedOAuthType])
@router.get("/supported-types", response_model=list[SupportedOAuthType])
async def get_supported_types(request: Request, db: Session = Depends(get_db)) -> Any:
adapter = GetSupportedTypesAdapter()
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)
@router.get("/providers", response_model=List[OAuthProviderAdminResponse])
@router.get("/providers", response_model=list[OAuthProviderAdminResponse])
async def list_provider_configs(request: Request, db: Session = Depends(get_db)) -> Any:
adapter = ListOAuthProviderConfigsAdapter()
return await pipeline.run(adapter=adapter, http_request=request, db=db, mode=adapter.mode)

View File

@@ -1,8 +1,7 @@
"""OAuth 公开端点(无需登录)。"""
from __future__ import annotations
from typing import Any, Optional
from typing import Any
from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.orm import Session
@@ -38,10 +37,10 @@ async def oauth_authorize(provider_type: str, db: Session = Depends(get_db)) ->
async def oauth_callback(
provider_type: str,
db: Session = Depends(get_db),
code: Optional[str] = Query(None),
state: Optional[str] = Query(None),
error: Optional[str] = Query(None),
error_description: Optional[str] = Query(None),
code: str | None = Query(None),
state: str | None = Query(None),
error: str | None = Query(None),
error_description: str | None = Query(None),
) -> RedirectResponse:
"""
OAuth 回调端点。

View File

@@ -1,8 +1,7 @@
"""OAuth 用户端点(需登录)。"""
from __future__ import annotations
from typing import Any, Optional, cast
from typing import Any, cast
from fastapi import APIRouter, Depends, HTTPException, Request, status
from sqlalchemy.orm import Session
@@ -53,7 +52,7 @@ async def bind_oauth_provider(
provider_type: str,
request: Request,
db: Session = Depends(get_db),
bind_token: Optional[str] = None,
bind_token: str | None = None,
) -> RedirectResponse:
"""发起 OAuth 绑定流程,支持通过 bind_token 参数进行安全认证"""
adapter = BindOAuthProviderAdapter(provider_type=provider_type, bind_token=bind_token)
@@ -115,10 +114,10 @@ class BindOAuthProviderAdapter(AuthenticatedApiAdapter):
2. bind_token 参数 (浏览器跳转场景)
"""
def __init__(self, provider_type: str, bind_token: Optional[str] = None):
def __init__(self, provider_type: str, bind_token: str | None = None):
self.provider_type = provider_type
self.bind_token = bind_token
self._user_from_bind_token: Optional[User] = None
self._user_from_bind_token: User | None = None
@property
def mode(self) -> ApiMode: # type: ignore[override]
@@ -136,7 +135,7 @@ class BindOAuthProviderAdapter(AuthenticatedApiAdapter):
raise HTTPException(status_code=401, detail="未登录")
async def handle(self, context: ApiRequestContext) -> RedirectResponse: # type: ignore[override]
user: Optional[User] = context.user
user: User | None = context.user
# 如果使用 bind_token验证并获取用户
if self.bind_token: