Fix Serve API contract: send to_formats as repeated form fields
Docling Serve expects array fields (to_formats) as repeated multipart keys (to_formats=md&to_formats=html&to_formats=json), not a JSON string. Changed _build_form_data to return list[tuple] so httpx sends repeated keys correctly. Fixes 422 Unprocessable Entity on convert. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
001cf6807c
commit
1b8cfe0a6b
2 changed files with 8 additions and 8 deletions
|
|
@ -108,14 +108,14 @@ class ServeConverter:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _build_form_data(options: ConversionOptions) -> dict[str, str]:
|
def _build_form_data(options: ConversionOptions) -> dict[str, str | list[str]]:
|
||||||
"""Build individual form fields matching Docling Serve's FormDepends pattern.
|
"""Build form fields matching Docling Serve's multipart form contract.
|
||||||
|
|
||||||
Docling Serve uses FormDepends to flatten ConvertDocumentsRequestOptions
|
Array fields (to_formats) are sent as lists — httpx encodes them as
|
||||||
into individual form fields (not a JSON blob).
|
repeated form keys (to_formats=md&to_formats=html&to_formats=json).
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
"to_formats": '["md","html","json"]',
|
"to_formats": ["md", "html", "json"],
|
||||||
"do_ocr": str(options.do_ocr).lower(),
|
"do_ocr": str(options.do_ocr).lower(),
|
||||||
"do_table_structure": str(options.do_table_structure).lower(),
|
"do_table_structure": str(options.do_table_structure).lower(),
|
||||||
"table_mode": options.table_mode,
|
"table_mode": options.table_mode,
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ class TestBuildFormData:
|
||||||
assert data["do_picture_description"] == "false"
|
assert data["do_picture_description"] == "false"
|
||||||
assert data["include_images"] == "false"
|
assert data["include_images"] == "false"
|
||||||
assert data["images_scale"] == "1.0"
|
assert data["images_scale"] == "1.0"
|
||||||
assert '"json"' in data["to_formats"]
|
assert set(data["to_formats"]) == {"md", "html", "json"}
|
||||||
|
|
||||||
def test_custom_options(self):
|
def test_custom_options(self):
|
||||||
opts = ConversionOptions(
|
opts = ConversionOptions(
|
||||||
|
|
@ -299,11 +299,11 @@ class TestServeConverterConvert:
|
||||||
assert len(result.pages[0].elements) == 1
|
assert len(result.pages[0].elements) == 1
|
||||||
assert result.pages[0].elements[0].type == "title"
|
assert result.pages[0].elements[0].type == "title"
|
||||||
|
|
||||||
# Verify form fields sent individually (not as JSON blob)
|
# Verify form fields sent as dict with list for repeated keys
|
||||||
call_kwargs = mock_client.post.call_args
|
call_kwargs = mock_client.post.call_args
|
||||||
sent_data = call_kwargs.kwargs.get("data", {})
|
sent_data = call_kwargs.kwargs.get("data", {})
|
||||||
assert "do_ocr" in sent_data
|
|
||||||
assert sent_data["do_ocr"] == "true"
|
assert sent_data["do_ocr"] == "true"
|
||||||
|
assert set(sent_data["to_formats"]) == {"md", "html", "json"}
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_http_error_raises(self, tmp_path):
|
async def test_http_error_raises(self, tmp_path):
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue