From 295203672f5bb1ae452ed2d04998d01b738a7802 Mon Sep 17 00:00:00 2001 From: pandego <7780875+pandego@users.noreply.github.com> Date: Wed, 15 Apr 2026 16:50:13 +0200 Subject: [PATCH] fix(split): serialize split_class in multipart requests --- src/landingai_ade/_client.py | 11 +++++---- .../types/client_split_params.py | 2 +- tests/test_client.py | 24 +++++++++++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/landingai_ade/_client.py b/src/landingai_ade/_client.py index 15a1310..749cd4e 100644 --- a/src/landingai_ade/_client.py +++ b/src/landingai_ade/_client.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +import json import importlib.metadata from typing import TYPE_CHECKING, Any, Dict, Union, Mapping, Iterable, Optional, cast from pathlib import Path @@ -559,7 +560,7 @@ def parse( def split( self, *, - split_class: Iterable[client_split_params.SplitClass], + split_class: Union[str, Iterable[client_split_params.SplitClass]], markdown: Union[FileTypes, str, None] | Omit = omit, markdown_url: Optional[str] | Omit = omit, model: Optional[str] | Omit = omit, @@ -606,9 +607,10 @@ def split( # Store original inputs for filename extraction original_markdown = markdown original_markdown_url = markdown_url + normalized_split_class = split_class if isinstance(split_class, str) else json.dumps(list(split_class)) body = deepcopy_minimal( { - "split_class": split_class, + "split_class": normalized_split_class, "markdown": markdown, "markdown_url": markdown_url, "model": model, @@ -1080,7 +1082,7 @@ async def parse( async def split( self, *, - split_class: Iterable[client_split_params.SplitClass], + split_class: Union[str, Iterable[client_split_params.SplitClass]], markdown: Union[FileTypes, str, None] | Omit = omit, markdown_url: Optional[str] | Omit = omit, model: Optional[str] | Omit = omit, @@ -1119,9 +1121,10 @@ async def split( timeout: Override the client-level default timeout for this request, in seconds """ + normalized_split_class = split_class if isinstance(split_class, str) else json.dumps(list(split_class)) body = deepcopy_minimal( { - "split_class": split_class, + "split_class": normalized_split_class, "markdown": markdown, "markdown_url": markdown_url, "model": model, diff --git a/src/landingai_ade/types/client_split_params.py b/src/landingai_ade/types/client_split_params.py index 28f9398..4331898 100644 --- a/src/landingai_ade/types/client_split_params.py +++ b/src/landingai_ade/types/client_split_params.py @@ -11,7 +11,7 @@ class ClientSplitParams(TypedDict, total=False): - split_class: Required[Iterable[SplitClass]] + split_class: Required[Union[str, Iterable[SplitClass]]] """List of split classification options/configuration. Can be provided as JSON string in form data. diff --git a/tests/test_client.py b/tests/test_client.py index c0d01b9..bdf1ee5 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -579,6 +579,30 @@ def test_multipart_repeating_array(self, client: LandingAIADE) -> None: b"", ] + def test_split_sends_split_class_as_json_string_in_multipart(self, client: LandingAIADE) -> None: + request = client._build_request( + FinalRequestOptions.construct( + method="post", + url="/v1/ade/split", + headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, + json_data={"split_class": json.dumps([{"name": "Bank Statement"}]), "markdown": "# doc"}, + files=(), + ) + ) + + assert request.read().split(b"\r\n") == [ + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="split_class"', + b"", + b'[{"name": "Bank Statement"}]', + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="markdown"', + b"", + b"# doc", + b"--6b7ba517decee4a450543ea6ae821c82--", + b"", + ] + @pytest.mark.respx(base_url=base_url) def test_binary_content_upload(self, respx_mock: MockRouter, client: LandingAIADE) -> None: respx_mock.post("/upload").mock(side_effect=mirror_request_content)