Skip to content

Commit adc6aec

Browse files
Extract images/text: Fix async test parity
Assisted-by: Codex
1 parent 1d9ecbb commit adc6aec

2 files changed

Lines changed: 195 additions & 0 deletions

File tree

tests/test_extract_images.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,33 @@ def test_extract_images_payload_invalid_page_range() -> None:
5252
ExtractImagesPayload.model_validate({"files": [file_repr], "pages": ["5-2"]})
5353

5454

55+
@pytest.mark.asyncio
56+
async def test_async_extract_images_payload_rejects_non_pdf() -> None:
57+
file_id = str(PdfRestFileID.generate())
58+
text_file = PdfRestFile.model_validate(
59+
{
60+
"id": file_id,
61+
"name": "notes.txt",
62+
"url": f"https://api.pdfrest.com/resource/{file_id}",
63+
"type": "text/plain",
64+
"size": 64,
65+
"modified": "2024-01-01T00:00:00Z",
66+
"scheduledDeletionTimeUtc": None,
67+
}
68+
)
69+
with pytest.raises(ValidationError, match="Must be a PDF file"):
70+
ExtractImagesPayload.model_validate({"files": [text_file]})
71+
72+
73+
@pytest.mark.asyncio
74+
async def test_async_extract_images_payload_invalid_page_range() -> None:
75+
file_repr = make_pdf_file(PdfRestFileID.generate(1))
76+
with pytest.raises(
77+
ValidationError, match="The start page must be less than or equal to the end"
78+
):
79+
ExtractImagesPayload.model_validate({"files": [file_repr], "pages": ["5-2"]})
80+
81+
5582
def test_extract_images_success(monkeypatch: pytest.MonkeyPatch) -> None:
5683
monkeypatch.delenv("PDFREST_API_KEY", raising=False)
5784
input_file = make_pdf_file(PdfRestFileID.generate(1))
@@ -164,6 +191,68 @@ def handler(request: httpx.Request) -> httpx.Response:
164191
assert timeout_value == pytest.approx(0.3)
165192

166193

194+
@pytest.mark.asyncio
195+
async def test_async_extract_images_request_customization(
196+
monkeypatch: pytest.MonkeyPatch,
197+
) -> None:
198+
monkeypatch.delenv("PDFREST_API_KEY", raising=False)
199+
input_file = make_pdf_file(PdfRestFileID.generate(2))
200+
output_id = str(PdfRestFileID.generate())
201+
payload_dump = ExtractImagesPayload.model_validate(
202+
{"files": [input_file], "pages": ["1-last"]}
203+
).model_dump(mode="json", by_alias=True, exclude_none=True, exclude_unset=True)
204+
captured_timeout: dict[str, float | dict[str, float] | None] = {}
205+
206+
def handler(request: httpx.Request) -> httpx.Response:
207+
if request.method == "POST" and request.url.path == "/extracted-images":
208+
assert request.url.params["trace"] == "true"
209+
assert request.headers["X-Debug"] == "async"
210+
captured_timeout["value"] = request.extensions.get("timeout")
211+
payload = json.loads(request.content.decode("utf-8"))
212+
assert payload == payload_dump | {"debug": True}
213+
return httpx.Response(
214+
200,
215+
json={
216+
"inputId": str(input_file.id),
217+
"outputId": [output_id],
218+
},
219+
)
220+
if request.method == "GET" and request.url.path == f"/resource/{output_id}":
221+
assert request.url.params["format"] == "info"
222+
assert request.url.params["trace"] == "true"
223+
assert request.headers["X-Debug"] == "async"
224+
return httpx.Response(
225+
200,
226+
json=_make_png_file(output_id, "debug-async.png").model_dump(
227+
mode="json", by_alias=True
228+
),
229+
)
230+
msg = f"Unexpected request {request.method} {request.url}"
231+
raise AssertionError(msg)
232+
233+
transport = httpx.MockTransport(handler)
234+
async with AsyncPdfRestClient(api_key=ASYNC_API_KEY, transport=transport) as client:
235+
response = await client.extract_images(
236+
input_file,
237+
pages=["1-last"],
238+
extra_query={"trace": "true"},
239+
extra_headers={"X-Debug": "async"},
240+
extra_body={"debug": True},
241+
timeout=0.3,
242+
)
243+
244+
assert isinstance(response, PdfRestFileBasedResponse)
245+
assert len(response.output_files) == 1
246+
timeout_value = captured_timeout["value"]
247+
assert timeout_value is not None
248+
if isinstance(timeout_value, dict):
249+
assert all(
250+
component == pytest.approx(0.3) for component in timeout_value.values()
251+
)
252+
else:
253+
assert timeout_value == pytest.approx(0.3)
254+
255+
167256
@pytest.mark.asyncio
168257
async def test_async_extract_images_success(
169258
monkeypatch: pytest.MonkeyPatch,

tests/test_extract_pdf_text_to_file.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,33 @@ def test_extract_pdf_text_payload_invalid_page_range() -> None:
5252
ExtractTextPayload.model_validate({"files": [file_repr], "pages": ["5-2"]})
5353

5454

55+
@pytest.mark.asyncio
56+
async def test_async_extract_pdf_text_payload_rejects_non_pdf() -> None:
57+
file_id = str(PdfRestFileID.generate())
58+
text_file = PdfRestFile.model_validate(
59+
{
60+
"id": file_id,
61+
"name": "notes.txt",
62+
"url": f"https://api.pdfrest.com/resource/{file_id}",
63+
"type": "text/plain",
64+
"size": 64,
65+
"modified": "2024-01-01T00:00:00Z",
66+
"scheduledDeletionTimeUtc": None,
67+
}
68+
)
69+
with pytest.raises(ValidationError, match="Must be a PDF file"):
70+
ExtractTextPayload.model_validate({"files": [text_file]})
71+
72+
73+
@pytest.mark.asyncio
74+
async def test_async_extract_pdf_text_payload_invalid_page_range() -> None:
75+
file_repr = make_pdf_file(PdfRestFileID.generate(1))
76+
with pytest.raises(
77+
ValidationError, match="The start page must be less than or equal to the end"
78+
):
79+
ExtractTextPayload.model_validate({"files": [file_repr], "pages": ["5-2"]})
80+
81+
5582
def test_extract_pdf_text_to_file_success(monkeypatch: pytest.MonkeyPatch) -> None:
5683
monkeypatch.delenv("PDFREST_API_KEY", raising=False)
5784
input_file = make_pdf_file(PdfRestFileID.generate(1))
@@ -186,6 +213,85 @@ def handler(request: httpx.Request) -> httpx.Response:
186213
assert get_timeout == pytest.approx(0.35)
187214

188215

216+
@pytest.mark.asyncio
217+
async def test_async_extract_pdf_text_request_customization(
218+
monkeypatch: pytest.MonkeyPatch,
219+
) -> None:
220+
monkeypatch.delenv("PDFREST_API_KEY", raising=False)
221+
input_file = make_pdf_file(PdfRestFileID.generate(2))
222+
output_id = str(PdfRestFileID.generate())
223+
payload_dump = ExtractTextPayload.model_validate(
224+
{
225+
"files": [input_file],
226+
"output": "file-output",
227+
"full_text": "document",
228+
"preserve_line_breaks": "off",
229+
"word_style": "off",
230+
"word_coordinates": "off",
231+
"output_type": "file",
232+
}
233+
).model_dump(mode="json", by_alias=True, exclude_none=True, exclude_unset=True)
234+
captured_timeout: dict[str, float | dict[str, float] | None] = {}
235+
236+
def handler(request: httpx.Request) -> httpx.Response:
237+
if request.method == "POST" and request.url.path == "/extracted-text":
238+
assert request.url.params["trace"] == "true"
239+
assert request.headers["X-Debug"] == "async"
240+
captured_timeout["post"] = request.extensions.get("timeout")
241+
payload = json.loads(request.content.decode("utf-8"))
242+
assert payload == payload_dump | {"debug": True}
243+
return httpx.Response(
244+
200,
245+
json={
246+
"inputId": [str(input_file.id)],
247+
"outputId": [output_id],
248+
},
249+
)
250+
if request.method == "GET" and request.url.path == f"/resource/{output_id}":
251+
assert request.url.params["format"] == "info"
252+
assert request.url.params["trace"] == "true"
253+
assert request.headers["X-Debug"] == "async"
254+
captured_timeout["get"] = request.extensions.get("timeout")
255+
return httpx.Response(
256+
200,
257+
json=_make_text_file(output_id, "debug-async.txt").model_dump(
258+
mode="json", by_alias=True
259+
),
260+
)
261+
msg = f"Unexpected request {request.method} {request.url}"
262+
raise AssertionError(msg)
263+
264+
transport = httpx.MockTransport(handler)
265+
async with AsyncPdfRestClient(api_key=ASYNC_API_KEY, transport=transport) as client:
266+
response = await client.extract_pdf_text_to_file(
267+
input_file,
268+
output="file-output",
269+
extra_query={"trace": "true"},
270+
extra_headers={"X-Debug": "async"},
271+
extra_body={"debug": True},
272+
timeout=0.35,
273+
)
274+
275+
assert isinstance(response, PdfRestFileBasedResponse)
276+
assert len(response.output_files) == 1
277+
post_timeout = captured_timeout["post"]
278+
get_timeout = captured_timeout["get"]
279+
assert post_timeout is not None
280+
assert get_timeout is not None
281+
if isinstance(post_timeout, dict):
282+
assert all(
283+
component == pytest.approx(0.35) for component in post_timeout.values()
284+
)
285+
else:
286+
assert post_timeout == pytest.approx(0.35)
287+
if isinstance(get_timeout, dict):
288+
assert all(
289+
component == pytest.approx(0.35) for component in get_timeout.values()
290+
)
291+
else:
292+
assert get_timeout == pytest.approx(0.35)
293+
294+
189295
@pytest.mark.asyncio
190296
async def test_async_extract_pdf_text_to_file_success(
191297
monkeypatch: pytest.MonkeyPatch,

0 commit comments

Comments
 (0)