style: apply ruff format to OCR modules
This commit is contained in:
+10
-6
@@ -295,11 +295,15 @@ class OcrClient:
|
||||
await self._record_quietly(self._quota.mark_progress())
|
||||
self._feed_outcome(source.name, ok=True)
|
||||
latency_ms = int((self._now() - started) * 1000)
|
||||
await self._emit(kind, image, source, call_id, started, session_id, parent_call_id, result)
|
||||
await self._emit(
|
||||
kind, image, source, call_id, started, session_id, parent_call_id, result
|
||||
)
|
||||
return _AttemptOutcome(result, source, call_id, latency_ms)
|
||||
except (RequestRejectedError, ResultInvalidError) as exc:
|
||||
await self._gate_on_terminal(exc, entry)
|
||||
await self._emit(kind, image, source, call_id, started, session_id, parent_call_id, error=exc)
|
||||
await self._emit(
|
||||
kind, image, source, call_id, started, session_id, parent_call_id, error=exc
|
||||
)
|
||||
raise
|
||||
except asyncio.CancelledError:
|
||||
if entry.is_probe:
|
||||
@@ -314,7 +318,9 @@ class OcrClient:
|
||||
reasons[source.name] = reason
|
||||
await self._record_quietly(self._breaker.record_failure(entry, reason, dead))
|
||||
self._feed_outcome(source.name, ok=False)
|
||||
await self._emit(kind, image, source, call_id, started, session_id, parent_call_id, error=exc)
|
||||
await self._emit(
|
||||
kind, image, source, call_id, started, session_id, parent_call_id, error=exc
|
||||
)
|
||||
return _FailedAttempt(exc, immediate=dead)
|
||||
finally:
|
||||
await self._settle_and_release(permit)
|
||||
@@ -474,9 +480,7 @@ class OcrClient:
|
||||
# 严禁静默用 MonkeyOcrTransport 打别家端点(默认值掩盖错误)
|
||||
alien = sorted({s.provider for s in sources if s.provider != "monkey"})
|
||||
if alien:
|
||||
raise ValueError(
|
||||
f"OCR 装配仅支持 provider=monkey(D9 其余后端预留未实现): 发现 {alien}"
|
||||
)
|
||||
raise ValueError(f"OCR 装配仅支持 provider=monkey(D9 其余后端预留未实现): 发现 {alien}")
|
||||
return cls(
|
||||
scope=gw.scope,
|
||||
sources=sources,
|
||||
|
||||
@@ -75,7 +75,11 @@ def _classify_status(
|
||||
exc: httpx.HTTPStatusError, source_name: str, operation: str
|
||||
) -> TransientError | SourceDeadError | RequestRejectedError:
|
||||
status = exc.response.status_code
|
||||
ctx: dict[str, Any] = {"source_name": source_name, "status_code": status, "operation": operation}
|
||||
ctx: dict[str, Any] = {
|
||||
"source_name": source_name,
|
||||
"status_code": status,
|
||||
"operation": operation,
|
||||
}
|
||||
message = f"{source_name} OCR {operation} HTTP {status}"
|
||||
if status >= 500 or status == 429:
|
||||
return TransientError(message, **ctx)
|
||||
@@ -146,7 +150,9 @@ def _parse_pages(payload: object) -> tuple[list[OcrLayoutElement], list[tuple[fl
|
||||
return elements, page_sizes
|
||||
|
||||
|
||||
def _parse_middle_json(zip_bytes: bytes) -> tuple[list[OcrLayoutElement], list[tuple[float, float]]]:
|
||||
def _parse_middle_json(
|
||||
zip_bytes: bytes,
|
||||
) -> tuple[list[OcrLayoutElement], list[tuple[float, float]]]:
|
||||
"""ZIP → (elements, page_sizes);一切形态异常归 ResultInvalid(坏图≠坏服务)。
|
||||
|
||||
数值防御全量下沉自 CHS `_parse_table_result`(invokers.py:437-479),
|
||||
|
||||
@@ -249,14 +249,20 @@ class TestMiddleJsonDefense:
|
||||
self._expect_invalid(_zip_bytes(_middle_bytes([page])))
|
||||
|
||||
def test_bbox_order_invalid(self):
|
||||
self._expect_invalid(_zip_bytes(_middle_bytes([_page([_block("table", (218, 48, 41, 282))])])))
|
||||
self._expect_invalid(
|
||||
_zip_bytes(_middle_bytes([_page([_block("table", (218, 48, 41, 282))])]))
|
||||
)
|
||||
|
||||
def test_bbox_int_degenerate(self):
|
||||
# float 合法但 int() 后宽度为零: 专为 CHS shim 的裁剪路径兜底
|
||||
self._expect_invalid(_zip_bytes(_middle_bytes([_page([_block("table", (1.2, 1.2, 1.8, 5))])])))
|
||||
self._expect_invalid(
|
||||
_zip_bytes(_middle_bytes([_page([_block("table", (1.2, 1.2, 1.8, 5))])]))
|
||||
)
|
||||
|
||||
def test_bbox_non_finite(self):
|
||||
self._expect_invalid(_zip_bytes(_middle_bytes([_page([_block("table", (1, 2, float("inf"), 4))])])))
|
||||
self._expect_invalid(
|
||||
_zip_bytes(_middle_bytes([_page([_block("table", (1, 2, float("inf"), 4))])]))
|
||||
)
|
||||
|
||||
def test_type_missing(self):
|
||||
block = {"bbox": [1, 2, 30, 40], "index": 0}
|
||||
@@ -278,8 +284,13 @@ class TestMiddleJsonDefense:
|
||||
class TestErrorTranslation:
|
||||
@pytest.mark.parametrize(
|
||||
("status", "exc_type"),
|
||||
[(502, TransientError), (429, TransientError), (401, SourceDeadError),
|
||||
(403, SourceDeadError), (404, RequestRejectedError)],
|
||||
[
|
||||
(502, TransientError),
|
||||
(429, TransientError),
|
||||
(401, SourceDeadError),
|
||||
(403, SourceDeadError),
|
||||
(404, RequestRejectedError),
|
||||
],
|
||||
)
|
||||
async def test_http_status(self, status, exc_type):
|
||||
t = _transport_for(_routes(text_resp=httpx.Response(status)))
|
||||
|
||||
@@ -234,9 +234,7 @@ class TestTerminalOutcomes:
|
||||
assert client._selector.outcomes == [] # 坏结果 ≠ 坏服务,不喂健康
|
||||
|
||||
async def test_rejected_with_status_counts_no_attempt(self):
|
||||
client, _, gate = _client(
|
||||
[_src()], [RequestRejectedError("parse failed", status_code=200)]
|
||||
)
|
||||
client, _, gate = _client([_src()], [RequestRejectedError("parse failed", status_code=200)])
|
||||
with pytest.raises(RequestRejectedError):
|
||||
await client.parse_layout(b"jpg")
|
||||
assert gate.successes == [("m1", False)]
|
||||
@@ -378,9 +376,7 @@ class TestAssembly:
|
||||
await client.aclose()
|
||||
|
||||
async def test_non_monkey_provider_rejected(self):
|
||||
env = {
|
||||
k.replace("MONKEY", "GLM"): v for k, v in self._ENV.items()
|
||||
}
|
||||
env = {k.replace("MONKEY", "GLM"): v for k, v in self._ENV.items()}
|
||||
with pytest.raises(ValueError, match="monkey"):
|
||||
OcrClient.from_env("OCR", env=env)
|
||||
|
||||
|
||||
@@ -11,6 +11,12 @@ def test_ocr_public_surface_exported():
|
||||
"""M3 OCR 公共 API 面(设计 §3;transport 结果与 Protocol 不出顶层)。"""
|
||||
import polygateway
|
||||
|
||||
for name in ("OcrClient", "OcrSettings", "OcrTextResult", "OcrLayoutResult", "OcrLayoutElement"):
|
||||
for name in (
|
||||
"OcrClient",
|
||||
"OcrSettings",
|
||||
"OcrTextResult",
|
||||
"OcrLayoutResult",
|
||||
"OcrLayoutElement",
|
||||
):
|
||||
assert hasattr(polygateway, name), name
|
||||
assert name in polygateway.__all__, name
|
||||
|
||||
Reference in New Issue
Block a user