Skip to content

Commit 1bfcdca

Browse files
committed
refactor: resolve all 26 baseline mypy errors; precise test assertions
Per-error treatment (no bulk script): honest annotations for StoredDownload (Path/bytes/Callable), KeyValue.value (Any for JSONField), dict[str, Any] for form/config dicts; signature split in create_token; str() normalization in config int(); platform/type-ignore only where the checker cannot follow (msvcrt, FastAPI Request injection). Baseline file and ratchet compare now redundant at zero errors but kept as the guard against regressions. Tests: assertions tightened to status_code == 403 with HTTPException raises; _create_share explicit parameters replace **extra passthrough; seek-fix pointer-reset assertion persisted.
1 parent 915566d commit 1bfcdca

15 files changed

Lines changed: 74 additions & 71 deletions

‎apps/admin/config_service.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ async def update_config(self, data: dict):
9494
raise HTTPException(status_code=400, detail=f"{key} 配置值格式错误")
9595

9696
try:
97-
session_expire = int(next_config.get("admin_session_expire"))
97+
session_expire = int(str(next_config.get("admin_session_expire")))
9898
except (TypeError, ValueError):
9999
raise HTTPException(
100100
status_code=400,

‎apps/admin/dependencies.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ def get_admin_session(authorization: str = Header(default=None)) -> dict:
5454

5555

5656
async def admin_required(
57-
authorization: str = Header(default=None), request: Request = None
57+
authorization: str = Header(default=None),
58+
request: Request = None, # type: ignore[assignment] # FastAPI 运行时注入 Request;可选语义由下方 if request 判断
5859
):
5960
"""
6061
验证管理员权限

‎apps/admin/local_files.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Admin-side local (NAS) file browsing and deletion."""
22
from pathlib import Path
3+
from typing import Any
34

45
from fastapi import HTTPException
56

@@ -20,7 +21,7 @@ async def list_files(self, path: str = ""):
2021
raise HTTPException(status_code=404, detail="目录不存在")
2122

2223
root = get_local_root()
23-
items = []
24+
items: list[dict[str, Any]] = []
2425
try:
2526
children = list(directory.iterdir())
2627
except OSError as exc:

‎apps/admin/views.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# @File : views.py
44
# @Software: PyCharm
55
import datetime
6+
from typing import Any
67
from collections import Counter
78
from typing import Optional
89

@@ -273,14 +274,15 @@ async def batch_update_files(
273274
if not data.ids:
274275
raise HTTPException(status_code=400, detail="请选择要更新的文件")
275276

276-
update_data = {}
277+
update_data: dict[str, Any] = {}
277278
fields_set = data.model_fields_set
278279
should_clear_expired_at = bool(data.clear_expired_at)
279280

280281
if should_clear_expired_at:
281282
update_data["expired_at"] = None
282283
update_data["expired_count"] = -1
283284
elif "expired_at" in fields_set and data.expired_at != "":
285+
# schema 声明 Union[datetime, str]——透传两种形态,tortoise 均可序列化
284286
update_data["expired_at"] = data.expired_at
285287

286288
if (

‎apps/base/auth.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ def create_token(data: dict, expires_in: int | None = None) -> str:
6262
).encode()
6363
).decode().rstrip("=")
6464

65-
signature = hmac.new(
65+
signature_digest = hmac.new(
6666
_get_jwt_secret(), f"{header}.{payload}".encode(), "sha256"
6767
).digest()
68-
signature = base64.urlsafe_b64encode(signature).decode().rstrip("=")
68+
signature = base64.urlsafe_b64encode(signature_digest).decode().rstrip("=")
6969

7070
return f"{header}.{payload}.{signature}"
7171

‎apps/base/models.py‎

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
# @Author : Lan
33
# @File : models.py
44
# @Software: PyCharm
5-
from typing import Optional
5+
6+
from typing import Any
67

78
from tortoise.models import Model
89
from tortoise.contrib.pydantic import pydantic_model_creator
910

1011
from tortoise import fields, models
11-
from datetime import datetime
1212
from core.utils import get_now
1313

1414

@@ -57,14 +57,13 @@ class UploadChunk(models.Model):
5757

5858

5959
class KeyValue(Model):
60-
id: Optional[int] = fields.IntField(pk=True)
61-
key: Optional[str] = fields.CharField(
62-
max_length=255, description="键", index=True, unique=True
63-
)
64-
value: Optional[str] = fields.JSONField(description="值", null=True)
65-
created_at: Optional[datetime] = fields.DatetimeField(
66-
auto_now_add=True, description="创建时间"
67-
)
60+
# 与 FileCodes 保持同一风格:类属性不写值注解(等号右侧的 Field 描述符
61+
# 才是类级真身;实例级由 tortoise 运行时给出对应 Python 值)
62+
id = fields.IntField(pk=True)
63+
key = fields.CharField(max_length=255, description="键", index=True, unique=True)
64+
# JSONField 实际承载 dict/list(如 settings 配置)
65+
value: Any = fields.JSONField(description="值", null=True)
66+
created_at = fields.DatetimeField(auto_now_add=True, description="创建时间")
6867

6968

7069
class PresignUploadSession(models.Model):

‎apps/base/services.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,9 @@ async def create_file_share(
197197
raise
198198
finally:
199199
await release_storage(token)
200-
return {"code": code, "name": file.filename}
200+
# UploadFile.filename 类型为 str | None;路径生成已用 "" 兜底,
201+
# 响应处保持 str 以匹配 dict[str, str] 契约
202+
return {"code": code, "name": file.filename or ""}
201203

202204
@staticmethod
203205
async def complete_chunked_upload(
@@ -402,6 +404,9 @@ def response_from_download(download: StoredDownload):
402404
return Response(
403405
download.content, media_type=download.media_type, headers=download.headers
404406
)
407+
if download.stream_factory is None:
408+
# 数据契约要求三者至少其一;防御性 500 语义
409+
raise ValueError("StoredDownload 缺少可用的下载载荷")
405410
return StreamingResponse(
406411
download.stream_factory(),
407412
media_type=download.media_type,

‎apps/base/setup_wizard.py‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import html
66
from urllib.parse import parse_qs
77

8+
from typing import Any
9+
810
from fastapi import Request
911
from fastapi.responses import HTMLResponse
1012

@@ -73,14 +75,14 @@ def build_public_meta() -> dict:
7375

7476

7577

76-
def get_form_value(data: dict, key: str, default: str = "") -> str:
78+
def get_form_value(data: dict[str, Any], key: str, default: str = "") -> str:
7779
value = data.get(key, default)
7880
if isinstance(value, list):
7981
value = value[-1] if value else default
8082
return str(value if value is not None else default)
8183

8284

83-
def get_form_list(data: dict, key: str) -> list[str]:
85+
def get_form_list(data: dict[str, Any], key: str) -> list[str]:
8486
value = data.get(key, [])
8587
if isinstance(value, list):
8688
return [str(item) for item in value if str(item)]
@@ -96,7 +98,7 @@ def normalize_bool_field(data: dict, key: str, default: bool) -> bool:
9698

9799

98100
def parse_int_field(
99-
data: dict,
101+
data: dict[str, Any],
100102
key: str,
101103
default: int,
102104
label: str,

‎core/database.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def _lock_file(file_obj: IO[str]) -> None:
4747
if os.fstat(file_obj.fileno()).st_size == 0:
4848
file_obj.write("0")
4949
file_obj.flush()
50-
msvcrt.locking(file_obj.fileno(), msvcrt.LK_LOCK, 1)
50+
msvcrt.locking(file_obj.fileno(), msvcrt.LK_LOCK, 1) # type: ignore[attr-defined]
5151
else:
5252
import fcntl
5353

@@ -58,7 +58,7 @@ def _unlock_file(file_obj: IO[str]) -> None:
5858
if os.name == "nt":
5959
import msvcrt
6060

61-
msvcrt.locking(file_obj.fileno(), msvcrt.LK_UNLCK, 1)
61+
msvcrt.locking(file_obj.fileno(), msvcrt.LK_UNLCK, 1) # type: ignore[attr-defined]
6262
else:
6363
import fcntl
6464

‎core/security.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ def _endpoint_host_is_denied(host: str) -> bool:
119119
except (socket.gaierror, UnicodeError, OSError):
120120
return False
121121
for info in infos:
122-
if _endpoint_ip_is_denied(info[4][0]):
122+
# getaddrinfo 的 sockaddr 首元素在 IPv4/IPv6 下均为 str(int 仅出现在
123+
# AF_UNIX 等异形族)——显式 str() 让类型检查器与运行时一致。
124+
if _endpoint_ip_is_denied(str(info[4][0])):
123125
return True
124126
return False
125127

0 commit comments

Comments
 (0)