Merge pull request #862 from cbcoutinho/fix/pypdfium2-page-close-and-coverage
fix: close pypdfium2 page handle on error + cover classifier/OCR edge cases
This commit is contained in:
@@ -40,11 +40,15 @@ def _extract(content: bytes) -> tuple[str, dict[str, Any]]:
|
|||||||
page_texts: list[str] = []
|
page_texts: list[str] = []
|
||||||
for i in range(len(pdf)):
|
for i in range(len(pdf)):
|
||||||
page = pdf[i]
|
page = pdf[i]
|
||||||
textpage = page.get_textpage()
|
|
||||||
try:
|
try:
|
||||||
page_texts.append(textpage.get_text_bounded() or "")
|
textpage = page.get_textpage()
|
||||||
|
try:
|
||||||
|
page_texts.append(textpage.get_text_bounded() or "")
|
||||||
|
finally:
|
||||||
|
textpage.close()
|
||||||
finally:
|
finally:
|
||||||
textpage.close()
|
# Outer finally so the page handle is freed even if
|
||||||
|
# get_textpage() raises on a corrupt page.
|
||||||
page.close()
|
page.close()
|
||||||
doc_meta = pdf.get_metadata_dict() or {}
|
doc_meta = pdf.get_metadata_dict() or {}
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@@ -185,3 +185,21 @@ def test_classify_from_text_no_pages_routes_fast():
|
|||||||
assert c.recommended_tier == "fast"
|
assert c.recommended_tier == "fast"
|
||||||
assert c.ocr_page_fraction == pytest.approx(0.0)
|
assert c.ocr_page_fraction == pytest.approx(0.0)
|
||||||
assert c.flags == set()
|
assert c.flags == set()
|
||||||
|
|
||||||
|
|
||||||
|
def test_classify_from_text_junk_layer_flags_bad_text_layer():
|
||||||
|
# Each short segment (<MIN_PAGE_CHARS) sets needs_ocr -> high ocr_frac, and
|
||||||
|
# total_chars>0 with mean_quality<MIN_TEXT_QUALITY (no-whitespace junk scores
|
||||||
|
# 0.0) -> bad_text_layer (gated on ocr_frac, matching classify_pdf).
|
||||||
|
text = "x1y2zx1y2z"
|
||||||
|
c = clf.classify_from_text(
|
||||||
|
text,
|
||||||
|
[
|
||||||
|
{"page": 1, "start_offset": 0, "end_offset": 5},
|
||||||
|
{"page": 2, "start_offset": 5, "end_offset": 10},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert c.recommended_tier == "ocr"
|
||||||
|
assert c.total_chars > 0
|
||||||
|
assert "bad_text_layer" in c.flags
|
||||||
|
assert "no_text_layer" not in c.flags
|
||||||
|
|||||||
@@ -71,6 +71,19 @@ def test_build_backend_auto_none_configured():
|
|||||||
assert ocr.build_ocr_backend(_settings()) is None
|
assert ocr.build_ocr_backend(_settings()) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_backend_gateway_missing_m2m_raises():
|
||||||
|
# client_id set but token_url/secret missing -> explicit ValueError (not a
|
||||||
|
# stripped assert), surfaced on backend resolution.
|
||||||
|
with pytest.raises(ValueError, match="EMBEDDING_GATEWAY_TOKEN_URL"):
|
||||||
|
ocr.build_ocr_backend(
|
||||||
|
_settings(
|
||||||
|
document_ocr_provider="gateway",
|
||||||
|
embedding_gateway_url="http://gw",
|
||||||
|
embedding_gateway_client_id="cid",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_gateway_backend_url_normalization():
|
def test_gateway_backend_url_normalization():
|
||||||
b = ocr._GatewayOcrBackend("http://gw", "mistral/mistral-ocr-latest")
|
b = ocr._GatewayOcrBackend("http://gw", "mistral/mistral-ocr-latest")
|
||||||
assert b._url == "http://gw/v1/ocr"
|
assert b._url == "http://gw/v1/ocr"
|
||||||
|
|||||||
Reference in New Issue
Block a user