refactor: 统一代码格式,调整多行代码换行风格
对多个文件进行代码格式化调整,将长行参数拆分为多行书写,提升代码可读性,包括: - 调整函数定义、调用的多行换行格式 - 优化列表、元组、字典的多行排版 - 新增README.md项目说明文档
This commit is contained in:
@@ -34,7 +34,9 @@ def client(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> Iterator[TestClie
|
||||
return None
|
||||
|
||||
monkeypatch.setattr(QdrantService, "ensure_collections", _noop_ensure_collections)
|
||||
monkeypatch.setattr(document_module.settings, "upload_dir", str(tmp_path / "uploads"))
|
||||
monkeypatch.setattr(
|
||||
document_module.settings, "upload_dir", str(tmp_path / "uploads")
|
||||
)
|
||||
with TestClient(app) as test_client:
|
||||
yield test_client
|
||||
|
||||
@@ -45,7 +47,13 @@ def _inject_manager(monkeypatch: pytest.MonkeyPatch, manager: FakeManager) -> No
|
||||
|
||||
def _make_minimal_pdf(text: str = "Hello PDF World") -> bytes:
|
||||
content_stream = f"BT /F1 24 Tf 100 700 Td ({text}) Tj ET".encode("latin-1")
|
||||
content_obj = b"<< /Length " + str(len(content_stream)).encode() + b" >>\nstream\n" + content_stream + b"\nendstream"
|
||||
content_obj = (
|
||||
b"<< /Length "
|
||||
+ str(len(content_stream)).encode()
|
||||
+ b" >>\nstream\n"
|
||||
+ content_stream
|
||||
+ b"\nendstream"
|
||||
)
|
||||
return (
|
||||
b"%PDF-1.0\n"
|
||||
b"1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n"
|
||||
@@ -161,7 +169,13 @@ def test_upload_docx_extracts_text(
|
||||
content = _make_docx(["第一段落", "第二段落"])
|
||||
resp = client.post(
|
||||
"/api/v1/documents/upload",
|
||||
files={"file": ("doc.docx", content, "application/vnd.openxmlformats-officedocument.wordprocessingml.document")},
|
||||
files={
|
||||
"file": (
|
||||
"doc.docx",
|
||||
content,
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
assert resp.status_code == 202
|
||||
|
||||
@@ -14,7 +14,13 @@ from app.core.file_parser import parse_file, supported_extensions
|
||||
def _make_minimal_pdf(text: str = "Hello PDF World") -> bytes:
|
||||
"""构造一个含一页文本的最小 PDF(pypdf 可读出文本)"""
|
||||
content_stream = f"BT /F1 24 Tf 100 700 Td ({text}) Tj ET".encode("latin-1")
|
||||
content_obj = b"<< /Length " + str(len(content_stream)).encode() + b" >>\nstream\n" + content_stream + b"\nendstream"
|
||||
content_obj = (
|
||||
b"<< /Length "
|
||||
+ str(len(content_stream)).encode()
|
||||
+ b" >>\nstream\n"
|
||||
+ content_stream
|
||||
+ b"\nendstream"
|
||||
)
|
||||
return (
|
||||
b"%PDF-1.0\n"
|
||||
b"1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n"
|
||||
@@ -36,6 +42,7 @@ def _make_minimal_pdf(text: str = "Hello PDF World") -> bytes:
|
||||
|
||||
def _make_docx(text_lines: list[str]) -> bytes:
|
||||
from docx import Document # type: ignore[import-untyped]
|
||||
|
||||
document = Document()
|
||||
for line in text_lines:
|
||||
document.add_paragraph(line)
|
||||
@@ -222,7 +229,9 @@ def _patch_pdf_ocr_deps(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setitem(sys.modules, "rapidocr_onnxruntime", fake_module)
|
||||
|
||||
|
||||
def test_parse_pdf_ocr_fallback_when_text_layer_empty(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def test_parse_pdf_ocr_fallback_when_text_layer_empty(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""扫描件 PDF(文本层全空)触发 OCR 降级,返回识别文本"""
|
||||
_patch_pdf_ocr_deps(monkeypatch)
|
||||
monkeypatch.setattr(settings, "pdf_ocr_enabled", True)
|
||||
@@ -256,7 +265,9 @@ def test_parse_pdf_ocr_respects_max_pages(monkeypatch: pytest.MonkeyPatch) -> No
|
||||
assert "OCR文本第2页" not in result
|
||||
|
||||
|
||||
def test_parse_pdf_ocr_returns_empty_when_dependency_unavailable(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def test_parse_pdf_ocr_returns_empty_when_dependency_unavailable(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""rapidocr 导入失败:降级返回空文本,且把 _ocr_unavailable 置 True 避免重试"""
|
||||
monkeypatch.setattr("pypdf.PdfReader", _FakePdfReader)
|
||||
# 故意让 rapidocr_onnxruntime 提供一个非类的 RapidOCR,构造时抛错
|
||||
@@ -273,7 +284,9 @@ def test_parse_pdf_ocr_returns_empty_when_dependency_unavailable(monkeypatch: py
|
||||
assert fp_module._ocr_unavailable is True
|
||||
|
||||
|
||||
def test_parse_pdf_ocr_runtime_exception_falls_back_to_empty(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def test_parse_pdf_ocr_runtime_exception_falls_back_to_empty(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""OCR 运行时抛错:仅告警,降级返回空文本(不抛出 ValueError)"""
|
||||
monkeypatch.setattr("pypdf.PdfReader", _FakePdfReader)
|
||||
|
||||
@@ -291,7 +304,9 @@ def test_parse_pdf_ocr_runtime_exception_falls_back_to_empty(monkeypatch: pytest
|
||||
assert parse_file("scan.pdf", b"fake pdf bytes") == ""
|
||||
|
||||
|
||||
def test_parse_pdf_text_layer_present_skips_ocr(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def test_parse_pdf_text_layer_present_skips_ocr(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""文本层非空:直接返回文本,OCR 引擎不会被实例化"""
|
||||
call_count = 0
|
||||
|
||||
|
||||
@@ -7,15 +7,28 @@ from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from app.config import Settings
|
||||
from app.core.ingest_tasks import DEDUP_KEY_PREFIX, REDIS_KEY_PREFIX, IngestTaskManager, IngestTaskStatus
|
||||
from app.core.ingest_tasks import (
|
||||
DEDUP_KEY_PREFIX,
|
||||
REDIS_KEY_PREFIX,
|
||||
IngestTaskManager,
|
||||
IngestTaskStatus,
|
||||
)
|
||||
from app.core.ingestion import IngestionError
|
||||
from app.models.document import DocumentInput, DocumentSummary, IngestionResult, SummaryLevel
|
||||
from app.models.document import (
|
||||
DocumentInput,
|
||||
DocumentSummary,
|
||||
IngestionResult,
|
||||
SummaryLevel,
|
||||
)
|
||||
|
||||
|
||||
def make_summary() -> DocumentSummary:
|
||||
"""构造固定的三级总结"""
|
||||
return DocumentSummary(
|
||||
l1_summary="一句话总结", l2_outline=None, l3_content_outline="内容大纲", level=SummaryLevel.L3
|
||||
l1_summary="一句话总结",
|
||||
l2_outline=None,
|
||||
l3_content_outline="内容大纲",
|
||||
level=SummaryLevel.L3,
|
||||
)
|
||||
|
||||
|
||||
@@ -42,7 +55,9 @@ class FakeIngester:
|
||||
self.gate: asyncio.Event | None = None
|
||||
self.started = asyncio.Event()
|
||||
|
||||
async def ingest(self, doc: DocumentInput, progress_cb: Callable[[str], None] | None = None) -> IngestionResult:
|
||||
async def ingest(
|
||||
self, doc: DocumentInput, progress_cb: Callable[[str], None] | None = None
|
||||
) -> IngestionResult:
|
||||
self.calls.append(doc)
|
||||
self.started.set()
|
||||
if progress_cb is not None:
|
||||
@@ -64,7 +79,9 @@ class FakeRedis:
|
||||
self.writes: list[tuple[str, dict[str, Any], int | None]] = []
|
||||
self.store: dict[str, dict[str, Any]] = {}
|
||||
|
||||
async def set_json(self, key: str, value: dict[str, Any], ttl: int | None = None) -> bool:
|
||||
async def set_json(
|
||||
self, key: str, value: dict[str, Any], ttl: int | None = None
|
||||
) -> bool:
|
||||
self.writes.append((key, value, ttl))
|
||||
if self.fail_writes:
|
||||
raise RuntimeError("redis down")
|
||||
@@ -105,8 +122,12 @@ async def test_submit_returns_immediately_and_completes() -> None:
|
||||
|
||||
async def test_ingestion_error_marks_failed_with_stage_and_partial_summary() -> None:
|
||||
"""IngestionError:任务 failed,error.stage 透传,partial_summary 保留"""
|
||||
summary = DocumentSummary(l1_summary="L1", l2_outline=None, l3_content_outline="L3", level=SummaryLevel.L3)
|
||||
ingester = FakeIngester(error=IngestionError("classify", "分类判定失败: boom", summary=summary))
|
||||
summary = DocumentSummary(
|
||||
l1_summary="L1", l2_outline=None, l3_content_outline="L3", level=SummaryLevel.L3
|
||||
)
|
||||
ingester = FakeIngester(
|
||||
error=IngestionError("classify", "分类判定失败: boom", summary=summary)
|
||||
)
|
||||
manager = IngestTaskManager(ingester, FakeRedis(), Settings())
|
||||
|
||||
task_id = await manager.submit(DocumentInput(text="正文"))
|
||||
@@ -179,10 +200,14 @@ async def test_redis_mirror_ttl_done_and_failed() -> None:
|
||||
assert done_writes[-1][0]["status"] == IngestTaskStatus.DONE
|
||||
|
||||
redis2 = FakeRedis()
|
||||
failing_manager = IngestTaskManager(FakeIngester(error=RuntimeError("boom")), redis2, settings)
|
||||
failing_manager = IngestTaskManager(
|
||||
FakeIngester(error=RuntimeError("boom")), redis2, settings
|
||||
)
|
||||
failed_id = await failing_manager.submit(DocumentInput(text="y"))
|
||||
await failing_manager.wait_done(failed_id, timeout=5)
|
||||
failed_writes = [(v, ttl) for key, v, ttl in redis2.writes if key.endswith(failed_id)]
|
||||
failed_writes = [
|
||||
(v, ttl) for key, v, ttl in redis2.writes if key.endswith(failed_id)
|
||||
]
|
||||
assert failed_writes
|
||||
assert failed_writes[-1][0]["status"] == IngestTaskStatus.FAILED
|
||||
assert failed_writes[-1][1] == 604800
|
||||
@@ -275,6 +300,7 @@ async def test_dedup_skipped_when_redis_unavailable() -> None:
|
||||
|
||||
async def test_dedup_lookup_failure_falls_back_to_normal_pipeline() -> None:
|
||||
"""Redis get_json 抛错:去重查询降级为未命中,走原流水线"""
|
||||
|
||||
class _ExplodingRedis(FakeRedis):
|
||||
async def get_json(self, key: str) -> dict[str, Any] | None:
|
||||
raise RuntimeError("redis down")
|
||||
|
||||
Reference in New Issue
Block a user