refactor: 拆分大型模块为 mixin/子模块结构

- cli_handler_base.py 拆分为 7 个 mixin (event/monitor/prefetch/request/sse_helpers/stream/sync)
- usage/service.py 拆分为 6 个子模块 (types/active_requests/cache_analysis/lifecycle/pricing/query/recording)
- models/database 拆分为独立模型文件 (auth/misc/model/provider/stats/usage/user)
- DUMMY_THOUGHT_SIGNATURE 常量提升到 core/api_format/conversion/constants 统一管理
- task/service.py 内联导入提升为顶层导入
- 流处理函数签名移除冗余的 http_client 参数
This commit is contained in:
fawney19
2026-02-14 12:55:58 +08:00
parent f464f32e48
commit 26ede849e2
32 changed files with 10173 additions and 7218 deletions

View File

@@ -80,7 +80,7 @@ def test_convert_sse_line_unwraps_before_convert_stream_chunk() -> None:
return []
with patch(
"src.api.handlers.base.cli_handler_base.get_format_converter_registry",
"src.api.handlers.base.cli_event_mixin.get_format_converter_registry",
return_value=_DummyRegistry(),
):
_lines, _events = handler._convert_sse_line(ctx, v1_line, [])
@@ -189,7 +189,6 @@ async def test_antigravity_forces_conversion_path_in_stream_with_prefetch() -> N
]
byte_iter = _AsyncIter([]) # no more bytes after prefetch
response_ctx = SimpleNamespace(__aexit__=AsyncMock(return_value=None))
http_client = SimpleNamespace(aclose=AsyncMock(return_value=None))
with patch.object(
handler,
@@ -198,7 +197,7 @@ async def test_antigravity_forces_conversion_path_in_stream_with_prefetch() -> N
) as mock_convert:
out = []
async for chunk in handler._create_response_stream_with_prefetch(
ctx, byte_iter, response_ctx, http_client, prefetched # type: ignore[arg-type]
ctx, byte_iter, response_ctx, prefetched # type: ignore[arg-type]
):
out.append(chunk)

View File

@@ -84,12 +84,7 @@ def test_process_line_handles_openai_usage_chunk_followed_by_done_without_blank_
class _DummyResponseCtx:
async def __aexit__(self, exc_type, exc, tb) -> None: # noqa: ANN001
return None
class _DummyHTTPClient:
async def aclose(self) -> None:
async def __aexit__(self, exc_type: type | None, exc: BaseException | None, tb: object) -> None:
return None
@@ -115,7 +110,6 @@ async def test_create_response_stream_flushes_usage_on_remote_protocol_error() -
ctx=ctx,
byte_iterator=_iter_bytes_then_remote_protocol_error(),
response_ctx=_DummyResponseCtx(),
http_client=_DummyHTTPClient(), # type: ignore[arg-type]
prefetched_chunks=[],
start_time=None,
):

View File

@@ -24,7 +24,7 @@ class DummyParser(ResponseParser):
return ""
async def _empty_async_iter():
async def _empty_async_iter() -> Any:
if False: # pragma: no cover
yield b""
@@ -43,9 +43,6 @@ async def test_create_response_stream_converts_claude_to_openai() -> None:
response_ctx = AsyncMock()
response_ctx.__aexit__ = AsyncMock(return_value=None)
http_client = AsyncMock()
http_client.aclose = AsyncMock(return_value=None)
message_start = {
"type": "message_start",
"message": {
@@ -79,7 +76,6 @@ async def test_create_response_stream_converts_claude_to_openai() -> None:
ctx,
byte_iterator=_empty_async_iter(),
response_ctx=response_ctx,
http_client=http_client,
prefetched_chunks=prefetched_chunks,
)
]

View File

@@ -1,5 +1,5 @@
import json
from typing import AsyncIterator, Optional
from typing import AsyncIterator
import pytest
@@ -10,12 +10,7 @@ from src.core.api_format.conversion import register_default_normalizers
class _DummyResponseCtx:
async def __aexit__(self, exc_type, exc, tb) -> None: # noqa: ANN001
return None
class _DummyHTTPClient:
async def aclose(self) -> None:
async def __aexit__(self, exc_type: type | None, exc: BaseException | None, tb: object) -> None:
return None
@@ -70,7 +65,6 @@ async def test_stream_processor_converts_gemini_json_lines_without_data_prefix()
ctx=ctx,
byte_iterator=_iter_bytes(upstream_lines),
response_ctx=_DummyResponseCtx(),
http_client=_DummyHTTPClient(), # type: ignore[arg-type]
prefetched_chunks=[],
start_time=None,
):