Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
174 commits
Select commit Hold shift + click to select a range
329a522
codegen metadata
stainless-app[bot] Mar 25, 2026
4e52aa4
feat(api): manual updates
stainless-app[bot] Mar 25, 2026
5199765
codegen metadata
stainless-app[bot] Mar 25, 2026
275d4a0
codegen metadata
stainless-app[bot] Mar 25, 2026
fd75ce3
codegen metadata
stainless-app[bot] Mar 26, 2026
9569811
codegen metadata
stainless-app[bot] Mar 26, 2026
3cd2646
codegen metadata
stainless-app[bot] Mar 26, 2026
961c570
codegen metadata
stainless-app[bot] Mar 26, 2026
78826a2
feat(api): manual updates
stainless-app[bot] Mar 26, 2026
6428819
codegen metadata
stainless-app[bot] Mar 27, 2026
3723b84
feat(api): manual updates
stainless-app[bot] Mar 27, 2026
f2797e3
feat(internal): implement indices array format for query and form ser…
stainless-app[bot] Mar 27, 2026
28addfc
codegen metadata
stainless-app[bot] Mar 27, 2026
c82f80b
codegen metadata
stainless-app[bot] Mar 27, 2026
667ec6b
feat(api): manual updates
stainless-app[bot] Mar 27, 2026
5b02f1d
codegen metadata
stainless-app[bot] Mar 27, 2026
652c7fa
codegen metadata
stainless-app[bot] Mar 27, 2026
e90de06
feat(api): manual updates
stainless-app[bot] Mar 27, 2026
7ce7964
feat(api): manual updates
stainless-app[bot] Mar 27, 2026
1617718
codegen metadata
stainless-app[bot] Mar 27, 2026
a909df1
feat(api): manual updates
stainless-app[bot] Mar 27, 2026
052bec3
feat(api): manual updates
stainless-app[bot] Mar 27, 2026
605ccec
codegen metadata
stainless-app[bot] Mar 27, 2026
6f041cd
feat(api): manual updates
stainless-app[bot] Mar 27, 2026
b49d17b
codegen metadata
stainless-app[bot] Mar 27, 2026
4abcc9e
codegen metadata
stainless-app[bot] Mar 28, 2026
b340e29
feat(api): manual updates
stainless-app[bot] Mar 28, 2026
38e54a6
codegen metadata
stainless-app[bot] Mar 28, 2026
39eab34
codegen metadata
stainless-app[bot] Mar 28, 2026
b5f97b6
feat(api): remove transforms
stainless-app[bot] Mar 28, 2026
077905a
codegen metadata
stainless-app[bot] Mar 28, 2026
51af8cd
codegen metadata
stainless-app[bot] Mar 28, 2026
25bffaa
feat(api): Add transform to fix file upload type for /upload endpoint
stainless-app[bot] Mar 29, 2026
5d16330
codegen metadata
stainless-app[bot] Mar 29, 2026
fb504e1
codegen metadata
stainless-app[bot] Mar 29, 2026
8eab40e
chore(internal): version bump
stainless-app[bot] Mar 29, 2026
c190346
codegen metadata
stainless-app[bot] Mar 29, 2026
ccfb6ed
codegen metadata
stainless-app[bot] Mar 29, 2026
9774c00
codegen metadata
stainless-app[bot] Mar 30, 2026
67af676
codegen metadata
stainless-app[bot] Mar 30, 2026
bfc847b
codegen metadata
stainless-app[bot] Mar 30, 2026
0c01abd
codegen metadata
stainless-app[bot] Mar 30, 2026
aaecd73
feat(api): api update
stainless-app[bot] Mar 30, 2026
179df28
codegen metadata
stainless-app[bot] Mar 30, 2026
a96d41c
feat(api): api update
stainless-app[bot] Mar 31, 2026
4146c37
codegen metadata
stainless-app[bot] Mar 31, 2026
fde52c2
codegen metadata
stainless-app[bot] Mar 31, 2026
7eea3a3
codegen metadata
stainless-app[bot] Mar 31, 2026
fdb9780
codegen metadata
stainless-app[bot] Apr 1, 2026
68b374f
codegen metadata
stainless-app[bot] Apr 1, 2026
e7d4d97
codegen metadata
stainless-app[bot] Apr 1, 2026
4bf4f63
codegen metadata
stainless-app[bot] Apr 1, 2026
58ca0e8
codegen metadata
stainless-app[bot] Apr 1, 2026
03f6ae9
codegen metadata
stainless-app[bot] Apr 1, 2026
5f4357e
codegen metadata
stainless-app[bot] Apr 1, 2026
10f7af2
codegen metadata
stainless-app[bot] Apr 1, 2026
726ac55
codegen metadata
stainless-app[bot] Apr 2, 2026
9b105d3
feat(api): api update
stainless-app[bot] Apr 2, 2026
c4c5702
codegen metadata
stainless-app[bot] Apr 2, 2026
c9a2cbe
codegen metadata
stainless-app[bot] Apr 2, 2026
1653267
codegen metadata
stainless-app[bot] Apr 2, 2026
dcbedf0
codegen metadata
stainless-app[bot] Apr 2, 2026
ab9c9c7
codegen metadata
stainless-app[bot] Apr 3, 2026
fa5e981
codegen metadata
stainless-app[bot] Apr 3, 2026
bf50f32
codegen metadata
stainless-app[bot] Apr 3, 2026
fe524d0
codegen metadata
stainless-app[bot] Apr 3, 2026
1bd9adb
codegen metadata
stainless-app[bot] Apr 3, 2026
f3ad30a
codegen metadata
stainless-app[bot] Apr 3, 2026
c8ac160
codegen metadata
stainless-app[bot] Apr 6, 2026
4f43481
codegen metadata
stainless-app[bot] Apr 6, 2026
edabac8
codegen metadata
stainless-app[bot] Apr 6, 2026
b75d76a
codegen metadata
stainless-app[bot] Apr 6, 2026
7a986ff
codegen metadata
stainless-app[bot] Apr 7, 2026
bbf66b3
chore: configure new SDK language
stainless-app[bot] Apr 7, 2026
1b64693
fix(client): preserve hardcoded query params when merging with user p…
stainless-app[bot] Apr 8, 2026
3f94c05
codegen metadata
stainless-app[bot] Apr 8, 2026
03884d1
codegen metadata
stainless-app[bot] Apr 8, 2026
f97904a
codegen metadata
stainless-app[bot] Apr 8, 2026
ed6766f
codegen metadata
stainless-app[bot] Apr 8, 2026
d315000
codegen metadata
stainless-app[bot] Apr 9, 2026
e49587b
codegen metadata
stainless-app[bot] Apr 9, 2026
abbe220
codegen metadata
stainless-app[bot] Apr 9, 2026
1b49812
codegen metadata
stainless-app[bot] Apr 10, 2026
8d92579
codegen metadata
stainless-app[bot] Apr 10, 2026
1ce77d1
codegen metadata
stainless-app[bot] Apr 11, 2026
9664396
fix: ensure file data are only sent as 1 parameter
stainless-app[bot] Apr 11, 2026
7366a61
feat(api): api update
stainless-app[bot] Apr 11, 2026
339e73c
codegen metadata
stainless-app[bot] Apr 13, 2026
a82f97f
codegen metadata
stainless-app[bot] Apr 14, 2026
b7c03bc
codegen metadata
stainless-app[bot] Apr 14, 2026
5b88ae9
codegen metadata
stainless-app[bot] Apr 15, 2026
31e60c1
codegen metadata
stainless-app[bot] Apr 15, 2026
a3412f5
codegen metadata
stainless-app[bot] Apr 15, 2026
f138e67
codegen metadata
stainless-app[bot] Apr 15, 2026
5121806
codegen metadata
stainless-app[bot] Apr 15, 2026
2909963
codegen metadata
stainless-app[bot] Apr 15, 2026
66f509e
codegen metadata
stainless-app[bot] Apr 16, 2026
dbf7566
feat(api): api update
stainless-app[bot] Apr 16, 2026
0f8b304
codegen metadata
stainless-app[bot] Apr 16, 2026
40c7ca8
codegen metadata
stainless-app[bot] Apr 17, 2026
943ec5d
codegen metadata
stainless-app[bot] Apr 17, 2026
31d6c0f
codegen metadata
stainless-app[bot] Apr 17, 2026
7a82a36
codegen metadata
stainless-app[bot] Apr 17, 2026
a398aaf
codegen metadata
stainless-app[bot] Apr 17, 2026
1259659
codegen metadata
stainless-app[bot] Apr 18, 2026
586a40a
perf(client): optimize file structure copying in multipart requests
stainless-app[bot] Apr 18, 2026
14b95fd
codegen metadata
stainless-app[bot] Apr 18, 2026
cdc928d
feat(api): api update
stainless-app[bot] Apr 20, 2026
b068387
feat(api): api update
stainless-app[bot] Apr 21, 2026
f94a5eb
codegen metadata
stainless-app[bot] Apr 21, 2026
a3d7655
codegen metadata
stainless-app[bot] Apr 21, 2026
48895d7
codegen metadata
stainless-app[bot] Apr 22, 2026
ef63a14
codegen metadata
stainless-app[bot] Apr 22, 2026
9dbc686
codegen metadata
stainless-app[bot] Apr 22, 2026
0ce89c2
chore(internal): more robust bootstrap script
stainless-app[bot] Apr 23, 2026
50d3894
codegen metadata
stainless-app[bot] Apr 23, 2026
1c5e866
codegen metadata
stainless-app[bot] Apr 24, 2026
2b818b5
codegen metadata
stainless-app[bot] Apr 24, 2026
c0149d3
codegen metadata
stainless-app[bot] Apr 24, 2026
a37c16c
codegen metadata
stainless-app[bot] Apr 25, 2026
14e9c55
codegen metadata
stainless-app[bot] Apr 25, 2026
4ec76c3
codegen metadata
stainless-app[bot] Apr 26, 2026
9e206a0
codegen metadata
stainless-app[bot] Apr 27, 2026
c1d729d
fix: use correct field name format for multipart file arrays
stainless-app[bot] Apr 28, 2026
b47f82e
feat: support setting headers via env
stainless-app[bot] Apr 28, 2026
43ba551
codegen metadata
stainless-app[bot] Apr 28, 2026
b70ad2c
codegen metadata
stainless-app[bot] Apr 28, 2026
2ea6ae5
codegen metadata
stainless-app[bot] Apr 28, 2026
4fddf5d
feat(api): api update
stainless-app[bot] Apr 29, 2026
1bcccb2
codegen metadata
stainless-app[bot] Apr 29, 2026
8f8e64e
codegen metadata
stainless-app[bot] Apr 29, 2026
cd200ea
codegen metadata
stainless-app[bot] Apr 29, 2026
f0db752
codegen metadata
stainless-app[bot] Apr 30, 2026
3240547
codegen metadata
stainless-app[bot] Apr 30, 2026
69a43cc
codegen metadata
stainless-app[bot] Apr 30, 2026
4d2d58e
codegen metadata
stainless-app[bot] Apr 30, 2026
0f8298f
codegen metadata
stainless-app[bot] May 1, 2026
ffd8b1f
codegen metadata
stainless-app[bot] May 1, 2026
b730f76
chore(internal): reformat pyproject.toml
stainless-app[bot] May 1, 2026
6adeab6
codegen metadata
stainless-app[bot] May 1, 2026
f892447
codegen metadata
stainless-app[bot] May 1, 2026
5243eb8
codegen metadata
stainless-app[bot] May 1, 2026
6c6e68a
codegen metadata
stainless-app[bot] May 1, 2026
9198f61
codegen metadata
stainless-app[bot] May 1, 2026
086a1dc
codegen metadata
stainless-app[bot] May 2, 2026
11c1e26
codegen metadata
stainless-app[bot] May 2, 2026
cb3bec2
codegen metadata
stainless-app[bot] May 4, 2026
1b0c109
codegen metadata
stainless-app[bot] May 4, 2026
ac39f40
codegen metadata
stainless-app[bot] May 5, 2026
61cc8c5
codegen metadata
stainless-app[bot] May 5, 2026
76000bb
feat(api): api update
stainless-app[bot] May 5, 2026
c8d8a6c
codegen metadata
stainless-app[bot] May 5, 2026
01aa4ed
codegen metadata
stainless-app[bot] May 5, 2026
03bdea1
codegen metadata
stainless-app[bot] May 5, 2026
7ba9049
feat(api): api update
stainless-app[bot] May 6, 2026
19797bf
codegen metadata
stainless-app[bot] May 6, 2026
88b838e
codegen metadata
stainless-app[bot] May 6, 2026
264984f
feat(api): api update
stainless-app[bot] May 6, 2026
19ee218
codegen metadata
stainless-app[bot] May 7, 2026
14e7486
codegen metadata
stainless-app[bot] May 7, 2026
e96f18f
codegen metadata
stainless-app[bot] May 8, 2026
db43b5e
codegen metadata
stainless-app[bot] May 8, 2026
c0944a6
codegen metadata
stainless-app[bot] May 8, 2026
671a63b
codegen metadata
stainless-app[bot] May 8, 2026
18f0239
codegen metadata
stainless-app[bot] May 8, 2026
073ae81
codegen metadata
stainless-app[bot] May 8, 2026
a1ff433
codegen metadata
stainless-app[bot] May 9, 2026
f46575b
fix(client): add missing f-string prefix in file type error message
stainless-app[bot] May 9, 2026
fb19781
codegen metadata
stainless-app[bot] May 10, 2026
b3afa61
codegen metadata
stainless-app[bot] May 11, 2026
56bbbc1
codegen metadata
stainless-app[bot] May 11, 2026
618a68d
codegen metadata
stainless-app[bot] May 11, 2026
e5eb30c
codegen metadata
stainless-app[bot] May 12, 2026
abde2ea
feat(internal/types): support eagerly validating pydantic iterators
stainless-app[bot] May 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.20.0"
".": "0.21.0"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 17
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/reducto%2Freductoai-1b16fbf5337f188d0b66a5992f0d241be80c46c45412ef9830cb19b11437d1c6.yml
openapi_spec_hash: 88f89b5803058bfa20d5da05c2bcf754
config_hash: 9dd1f73da997aefc8516b226e0e7fed7
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/reducto/reductoai-b36868a5180fdbbf68e1ec04645b9f3cafae6e8149be90e2b57a249fc8e5f070.yml
openapi_spec_hash: 22a35f1691ac8540ee6141d7c800119a
config_hash: 9fa10baf03f994be027bf73b29ac8572
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ and offers both synchronous and asynchronous clients powered by [httpx](https://

It is generated with [Stainless](https://www.stainless.com/).

## MCP Server

Use the Reducto MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.

[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=reductoai-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInJlZHVjdG9haS1tY3AiXSwiZW52Ijp7IlJFRFVDVE9fQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)
[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22reductoai-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22reductoai-mcp%22%5D%2C%22env%22%3A%7B%22REDUCTO_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)

> Note: You may need to set environment variables in your MCP client.

## Documentation

The REST API documentation can be found on [docs.reductoai.com](https://docs.reductoai.com). The full API of this library can be found in [api.md](api.md).
Expand Down Expand Up @@ -129,6 +138,23 @@ response = client.parse.run(
print(response.enhance)
```

## File uploads

Request parameters that correspond to file uploads can be passed as `bytes`, or a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`.

```python
from pathlib import Path
from reducto import Reducto

client = Reducto()

client.upload(
file=Path("/path/to/file"),
)
```

The async client uses the exact same interface. If you pass a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance, the file contents will be read asynchronously automatically.

## Handling errors

When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `reducto.APIConnectionError` is raised.
Expand Down
76 changes: 46 additions & 30 deletions api.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,39 @@
# Shared Types

```python
from reducto.types import Upload
from reducto.types import (
AdvancedCitationsConfig,
AdvancedProcessingOptions,
ArrayExtractConfig,
AsyncEditResponse,
AsyncExtractResponse,
AsyncParseResponse,
AsyncPipelineResponse,
AsyncSplitResponse,
BaseProcessingOptions,
Chunking,
ChunkingConfig,
ClassifyResponse,
DirectWebhookConfig,
EditResponse,
EnrichConfig,
ExperimentalProcessingOptions,
ExtractResponse,
FigureAgentic,
FigureSummaryConfig,
LargeTableChunkingConfig,
PageRange,
ParseResponse,
PipelineResponse,
SplitLargeTables,
SplitResponse,
SvixWebhookConfig,
TableAgentic,
TableSummaryConfig,
TextAgentic,
Upload,
WebhookConfigNew,
)
```

# Reducto
Expand All @@ -25,10 +57,8 @@ Types:
from reducto.types import (
AsyncConfigV3,
AsyncParseConfig,
AsyncParseResponse,
Enhance,
Formatting,
ParseResponse,
Retrieval,
Settings,
Spreadsheet,
Expand All @@ -39,7 +69,7 @@ from reducto.types import (
Methods:

- <code title="post /parse">client.parse.<a href="./src/reducto/resources/parse.py">run</a>(\*\*<a href="src/reducto/types/parse_run_params.py">params</a>) -> <a href="./src/reducto/types/parse_run_response.py">ParseRunResponse</a></code>
- <code title="post /parse_async">client.parse.<a href="./src/reducto/resources/parse.py">run_job</a>(\*\*<a href="src/reducto/types/parse_run_job_params.py">params</a>) -> <a href="./src/reducto/types/async_parse_response.py">AsyncParseResponse</a></code>
- <code title="post /parse_async">client.parse.<a href="./src/reducto/resources/parse.py">run_job</a>(\*\*<a href="src/reducto/types/parse_run_job_params.py">params</a>) -> <a href="./src/reducto/types/shared/async_parse_response.py">AsyncParseResponse</a></code>

# Extract

Expand All @@ -48,7 +78,6 @@ Types:
```python
from reducto.types import (
AsyncExtractConfig,
AsyncExtractResponse,
ExtractSettings,
ExtractUsage,
Instructions,
Expand All @@ -61,65 +90,52 @@ from reducto.types import (
Methods:

- <code title="post /extract">client.extract.<a href="./src/reducto/resources/extract.py">run</a>(\*\*<a href="src/reducto/types/extract_run_params.py">params</a>) -> <a href="./src/reducto/types/extract_run_response.py">ExtractRunResponse</a></code>
- <code title="post /extract_async">client.extract.<a href="./src/reducto/resources/extract.py">run_job</a>(\*\*<a href="src/reducto/types/extract_run_job_params.py">params</a>) -> <a href="./src/reducto/types/async_extract_response.py">AsyncExtractResponse</a></code>
- <code title="post /extract_async">client.extract.<a href="./src/reducto/resources/extract.py">run_job</a>(\*\*<a href="src/reducto/types/extract_run_job_params.py">params</a>) -> <a href="./src/reducto/types/shared/async_extract_response.py">AsyncExtractResponse</a></code>

# Split

Types:

```python
from reducto.types import (
DeepSplitPageEvidence,
ParseUsage,
SplitCategory,
SplitResponse,
SplitTableOptions,
SplitRunJobResponse,
)
from reducto.types import DeepSplitPageEvidence, ParseUsage, SplitCategory, SplitTableOptions
```

Methods:

- <code title="post /split">client.split.<a href="./src/reducto/resources/split.py">run</a>(\*\*<a href="src/reducto/types/split_run_params.py">params</a>) -> <a href="./src/reducto/types/split_response.py">SplitResponse</a></code>
- <code title="post /split_async">client.split.<a href="./src/reducto/resources/split.py">run_job</a>(\*\*<a href="src/reducto/types/split_run_job_params.py">params</a>) -> <a href="./src/reducto/types/split_run_job_response.py">SplitRunJobResponse</a></code>
- <code title="post /split">client.split.<a href="./src/reducto/resources/split.py">run</a>(\*\*<a href="src/reducto/types/split_run_params.py">params</a>) -> <a href="./src/reducto/types/shared/split_response.py">SplitResponse</a></code>
- <code title="post /split_async">client.split.<a href="./src/reducto/resources/split.py">run_job</a>(\*\*<a href="src/reducto/types/split_run_job_params.py">params</a>) -> <a href="./src/reducto/types/shared/async_split_response.py">AsyncSplitResponse</a></code>

# Edit

Types:

```python
from reducto.types import BoundingBox, EditOptions, EditResponse, EditWidget, EditRunJobResponse
from reducto.types import BoundingBox, EditOptions, EditWidget
```

Methods:

- <code title="post /edit">client.edit.<a href="./src/reducto/resources/edit.py">run</a>(\*\*<a href="src/reducto/types/edit_run_params.py">params</a>) -> <a href="./src/reducto/types/edit_response.py">EditResponse</a></code>
- <code title="post /edit_async">client.edit.<a href="./src/reducto/resources/edit.py">run_job</a>(\*\*<a href="src/reducto/types/edit_run_job_params.py">params</a>) -> <a href="./src/reducto/types/edit_run_job_response.py">EditRunJobResponse</a></code>
- <code title="post /edit">client.edit.<a href="./src/reducto/resources/edit.py">run</a>(\*\*<a href="src/reducto/types/edit_run_params.py">params</a>) -> <a href="./src/reducto/types/shared/edit_response.py">EditResponse</a></code>
- <code title="post /edit_async">client.edit.<a href="./src/reducto/resources/edit.py">run_job</a>(\*\*<a href="src/reducto/types/edit_run_job_params.py">params</a>) -> <a href="./src/reducto/types/shared/async_edit_response.py">AsyncEditResponse</a></code>

# Pipeline

Types:

```python
from reducto.types import PipelineResponse, PipelineSettings, PipelineRunJobResponse
from reducto.types import PipelineSettings
```

Methods:

- <code title="post /pipeline">client.pipeline.<a href="./src/reducto/resources/pipeline.py">run</a>(\*\*<a href="src/reducto/types/pipeline_run_params.py">params</a>) -> <a href="./src/reducto/types/pipeline_response.py">PipelineResponse</a></code>
- <code title="post /pipeline_async">client.pipeline.<a href="./src/reducto/resources/pipeline.py">run_job</a>(\*\*<a href="src/reducto/types/pipeline_run_job_params.py">params</a>) -> <a href="./src/reducto/types/pipeline_run_job_response.py">PipelineRunJobResponse</a></code>
- <code title="post /pipeline">client.pipeline.<a href="./src/reducto/resources/pipeline.py">run</a>(\*\*<a href="src/reducto/types/pipeline_run_params.py">params</a>) -> <a href="./src/reducto/types/shared/pipeline_response.py">PipelineResponse</a></code>
- <code title="post /pipeline_async">client.pipeline.<a href="./src/reducto/resources/pipeline.py">run_job</a>(\*\*<a href="src/reducto/types/pipeline_run_job_params.py">params</a>) -> <a href="./src/reducto/types/shared/async_pipeline_response.py">AsyncPipelineResponse</a></code>

# Classify

Types:

```python
from reducto.types import ClassifyResponse, PageRange
```

Methods:

- <code title="post /classify">client.classify.<a href="./src/reducto/resources/classify.py">run</a>(\*\*<a href="src/reducto/types/classify_run_params.py">params</a>) -> <a href="./src/reducto/types/classify_response.py">ClassifyResponse</a></code>
- <code title="post /classify">client.classify.<a href="./src/reducto/resources/classify.py">run</a>(\*\*<a href="src/reducto/types/classify_run_params.py">params</a>) -> <a href="./src/reducto/types/shared/classify_response.py">ClassifyResponse</a></code>

# Webhook

Expand All @@ -138,7 +154,7 @@ Methods:
Types:

```python
from reducto.types import ExtractResponse, JobGetResponse, JobGetAllResponse
from reducto.types import JobGetResponse, JobGetAllResponse
```

Methods:
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "reductoai"
version = "0.20.0"
version = "0.21.0"
description = "The official Python library for the reducto API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down Expand Up @@ -168,7 +168,7 @@ show_error_codes = true
#
# We also exclude our `tests` as mypy doesn't always infer
# types correctly and Pyright will still catch any type errors.
exclude = ['src/reducto/_files.py', '_dev/.*.py', 'tests/.*']
exclude = ["src/reducto/_files.py", "_dev/.*.py", "tests/.*"]

strict_equality = true
implicit_reexport = true
Expand Down
2 changes: 1 addition & 1 deletion scripts/bootstrap
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -e

cd "$(dirname "$0")/.."

if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then
if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "${SKIP_BREW:-}" != "1" ] && [ -t 0 ]; then
brew bundle check >/dev/null 2>&1 || {
echo -n "==> Install Homebrew dependencies? (y/N): "
read -r response
Expand Down
4 changes: 4 additions & 0 deletions src/reducto/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,10 @@ def _build_request(
files = cast(HttpxRequestFiles, ForceMultipartDict())

prepared_url = self._prepare_url(options.url)
# preserve hard-coded query params from the url
if params and prepared_url.query:
params = {**dict(prepared_url.params.items()), **params}
prepared_url = prepared_url.copy_with(raw_path=prepared_url.raw_path.split(b"?", 1)[0])
if "_" in prepared_url.host:
# work around https://github.com/encode/httpx/discussions/2880
kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")}
Expand Down
46 changes: 42 additions & 4 deletions src/reducto/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
from . import _exceptions
from ._qs import Querystring
from .types import client_upload_params
from ._files import deepcopy_with_paths
from ._types import (
Body,
Omit,
Query,
Headers,
Timeout,
NotGiven,
FileTypes,
Transport,
ProxiesTypes,
RequestOptions,
Expand All @@ -26,6 +28,8 @@
)
from ._utils import (
is_given,
is_mapping_t,
extract_files,
maybe_transform,
get_async_library,
async_maybe_transform,
Expand Down Expand Up @@ -147,6 +151,15 @@ def __init__(
except KeyError as exc:
raise ValueError(f"Unknown environment: {environment}") from exc

custom_headers_env = os.environ.get("REDUCTO_CUSTOM_HEADERS")
if custom_headers_env is not None:
parsed: dict[str, str] = {}
for line in custom_headers_env.split("\n"):
colon = line.find(":")
if colon >= 0:
parsed[line[:colon].strip()] = line[colon + 1 :].strip()
default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})}

super().__init__(
version=__version__,
base_url=base_url,
Expand Down Expand Up @@ -315,7 +328,7 @@ def upload(
self,
*,
extension: Optional[str] | Omit = omit,
file: Optional[str] | Omit = omit,
file: Optional[FileTypes] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
Expand All @@ -335,9 +348,17 @@ def upload(

timeout: Override the client-level default timeout for this request, in seconds
"""
body = deepcopy_with_paths({"file": file}, [["file"]])
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
if files:
# It should be noted that the actual Content-Type header that will be
# sent to the server will contain a `boundary` parameter, e.g.
# multipart/form-data; boundary=---abc--
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
return self.post(
"/upload",
body=maybe_transform({"file": file}, client_upload_params.ClientUploadParams),
body=maybe_transform(body, client_upload_params.ClientUploadParams),
files=files,
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
Expand Down Expand Up @@ -450,6 +471,15 @@ def __init__(
except KeyError as exc:
raise ValueError(f"Unknown environment: {environment}") from exc

custom_headers_env = os.environ.get("REDUCTO_CUSTOM_HEADERS")
if custom_headers_env is not None:
parsed: dict[str, str] = {}
for line in custom_headers_env.split("\n"):
colon = line.find(":")
if colon >= 0:
parsed[line[:colon].strip()] = line[colon + 1 :].strip()
default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})}

super().__init__(
version=__version__,
base_url=base_url,
Expand Down Expand Up @@ -618,7 +648,7 @@ async def upload(
self,
*,
extension: Optional[str] | Omit = omit,
file: Optional[str] | Omit = omit,
file: Optional[FileTypes] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
Expand All @@ -638,9 +668,17 @@ async def upload(

timeout: Override the client-level default timeout for this request, in seconds
"""
body = deepcopy_with_paths({"file": file}, [["file"]])
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
if files:
# It should be noted that the actual Content-Type header that will be
# sent to the server will contain a `boundary` parameter, e.g.
# multipart/form-data; boundary=---abc--
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
return await self.post(
"/upload",
body=await async_maybe_transform({"file": file}, client_upload_params.ClientUploadParams),
body=await async_maybe_transform(body, client_upload_params.ClientUploadParams),
files=files,
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
Expand Down
Loading