refactor: HTTP 垫片异常层次收敛到 core.http_errors 单一来源

为什么:core/aiohttp_compat.py 与 core/sync_http.py 各自定义了一份
RequestException / HTTPError,是**两个不同的类**。调用方在同步段捕获
core.sync_http.HTTPError、异步段抛的却是 core.aiohttp_compat.HTTPError,
两者无继承关系——异常会穿透所有 except 分支,属于隐藏的跨层 bug。

改法:新建 core/http_errors.py 作为唯一定义处(RequestException 基类 +
HTTPError / Timeout / ConnectionError),两个垫片改为从它导入并再导出。
刻意保留 requests 的命名约定(Timeout / ConnectionError 与内置同名,
调用方需带模块前缀引用),已在 docstring 写明,避免后来者误改。

注意:sync_http 补了 __all__ 显式再导出——models._RetryFromScratch 继承它、
tests/test_aria2.py 直接导入它,符号必须保持可导入。
This commit is contained in:
snowy-yang committed 2026-09-26 18:53:53 +08:00
1 parent 2b4704183c
commit d7d3cfce69
3 files changed
+46 -34

No files matched your search

+6 -12
View File
@@ -16,22 +16,16 @@ from typing import Any
from core import async_bridge
from core.http_client import client as _client
from core.http_errors import HTTPError, RequestException
# 异常层次与异步垫片(core.aiohttp_compat)共用同一份定义——调用方可用同一组
# 类型捕获两条通道的失败。RequestException 在此再导出:music_downloader.models
# 的 _RetryFromScratch 继承它,既有 except 与测试也直接导入它。
__all__ = ['HTTPError', 'RequestException', 'Session', 'SyncResponse', 'get', 'post']
_DEFAULT_TIMEOUT = 30
class RequestException(Exception):
"""请求异常基类(对齐 requests 命名,便于迁移)。"""
class HTTPError(RequestException):
"""raise_for_status() 抛出的 HTTP 状态异常。"""
def __init__(self, message: str, response: 'SyncResponse | None' = None):
super().__init__(message)
self.response = response
class SyncResponse:
"""requests.Response 的同步子集(底层 aiohttp)。"""