fix(tooling): 修复 pyright 解释器配置与类型守卫,补齐 ruff 门禁与两处历史 bug

- pyrightconfig.json 钉死 Python 3.12 虚拟环境,消除由于查找系统 Python 3.9 带来的假性报错
- 修复 huya/login.py 引用不存在函数的问题并补充单元测试
- 修复 browser_harvest.py 对 set 下标访问的错误并提升报错信息质量
- 虎牙 6 个子路由显式导入依赖,消除 import * 带来的未定义变量报警
- 规范化 Pydantic Field(default=...) 默认值声明
- 完善 solver.py / app_login.py 等核心路径类型守卫与 @overload 重载
- 在 pyproject.toml 中显式锁定 ruff lint 规则集 (E4, E7, E9, F, B, I, BLE)
- 门禁脚本同步增加 ruff check 检查并在 AGENTS.md 补齐实践经验总结
This commit is contained in:
yml2213
2026-10-08 12:33:39 +08:00
parent ec07e4fc06
commit a3c3a46b9c
31 changed files with 599 additions and 96 deletions
@@ -41,10 +41,10 @@ from __future__ import annotations
import json
from datetime import UTC, datetime, timedelta
from typing import Any
from typing import Any, cast
from loguru import logger
from sqlalchemy import text
from sqlalchemy import CursorResult, text
from sqlalchemy.orm import Session
from ....models import AutomationJob
@@ -133,7 +133,9 @@ def _delete_batch(
),
params,
)
return int(result.rowcount or 0)
# Session.execute 的静态返回类型是 Result[Any],但 DML 语句实际拿到的是
# CursorResult(rowcount 只定义在它上面)。运行期行为不变,只是把这一点写实。
return int(cast(CursorResult[Any], result).rowcount or 0)
def run_douyu_tasks_retention(db: Session, job: AutomationJob) -> dict[str, Any]:
+5 -3
View File
@@ -211,9 +211,11 @@ class ManualMixin:
account.esports_opened = manual_type is not None and manual_type >= 1
# 到期时间也落库 —— 否则界面只能显示"已开通",看不到什么时候到期
expire_raw = result.get("expire_time")
expire_int = (
int(expire_raw) if str(expire_raw or "").strip().isdigit() else None
)
# 先规整成字符串再判 isdigit:原来写 `int(expire_raw) if str(expire_raw
# or "").strip().isdigit()` —— 判的是 A、转的是 B,类型检查器收窄不了,
# 而且同一份值取了两遍。规整到一个局部变量后两个问题一起没了。
expire_text = str(expire_raw or "").strip()
expire_int = int(expire_text) if expire_text.isdigit() else None
# ⚠️ 斗鱼用 0 表示「没有到期时间」。直接存 0 的话界面会显示 1970/1/1
# (这个坑在积分到期上踩过一次,这里别再踩)。
account.esports_expire_time = (
@@ -67,9 +67,12 @@ def _match_suit_item(want: str, rows: list[dict[str, Any]]) -> dict[str, Any] |
# 优先找带「套装」前缀的
for it in rows:
cname = str(it.get("commodityName") or "").strip()
if core in cname and not any(k in cname for k in SUIT_EXCLUDE_KEYWORDS):
if "套装" in cname:
return it
if (
core in cname
and not any(k in cname for k in SUIT_EXCLUDE_KEYWORDS)
and "套装" in cname
):
return it
# 3. 兜底匹配不带排除词的项
for it in rows:
+4 -2
View File
@@ -7,7 +7,7 @@ import copy
import threading
import time
from datetime import UTC, datetime
from typing import Any
from typing import Any, Literal
from loguru import logger
from sqlalchemy.orm import Session
@@ -51,7 +51,9 @@ class HuyaBatchRunnerCore:
def stop(self):
self._stop.set()
def _open_wss_session(self, uid: int, cookie: str, kind: str):
def _open_wss_session(
self, uid: int, cookie: str, kind: Literal["activity", "shop"]
):
"""在当前任务线程创建并登记 WSS 会话,统一由 finally 回收。"""
from core.huya.elite_session import HuyaEliteWssSession
+4 -2
View File
@@ -4,7 +4,7 @@ from __future__ import annotations
import time
from datetime import UTC, datetime
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Literal
from sqlalchemy.orm import Session
@@ -40,7 +40,9 @@ class RechargeMixin:
def _push_log(self, level: str, message: str) -> None: ...
def _mark_task(self, *args: Any, **kwargs: Any) -> None: ...
def _update_task_progress(self, *args: Any, **kwargs: Any) -> None: ...
def _open_wss_session(self, uid: int, cookie: str, kind: str): ...
def _open_wss_session(
self, uid: int, cookie: str, kind: Literal["activity", "shop"]
): ...
def _shop_client(self, uid: int, cookie: str): ...
@staticmethod