Conversation
6c2b6c5 to
a594c75
Compare
85e4dfe to
1322c80
Compare
2bb4c49 to
7e69125
Compare
7cdfb0a to
ca310cd
Compare
fix(client): mark some request bodies as optional
3bdb00f to
3ad7f25
Compare
1be6ce9 to
97b7254
Compare
35a4088 to
bc25b84
Compare
ef0d130 to
08062c4
Compare
9257acd to
b41543a
Compare
df1d708 to
69a44e3
Compare
cf36bae to
bba1424
Compare
e0b03f0 to
3d90dff
Compare
84a0625 to
db19786
Compare
359644d to
21a20b3
Compare
| line-length = 120 | ||
| output-format = "grouped" | ||
| target-version = "py37" | ||
| target-version = "py38" |
There was a problem hiding this comment.
Ruff target-version inconsistent with minimum Python version
Low Severity
The ruff target-version was changed from "py37" to "py38", but the project's requires-python was updated to ">= 3.9" and pyright's pythonVersion is set to "3.9". The ruff target should be "py39" to match. This inconsistency means ruff applies formatting/linting rules for Python 3.8 compatibility even though the project no longer supports it — for example, the FA102 rule may unnecessarily flag missing from __future__ import annotations in files that only need 3.9+ support.
Additional Locations (2)
| request = self._build_request(options, retries_taken=retries_taken) | ||
| self._prepare_request(request) | ||
| retries_taken = 0 | ||
| for retries_taken in range(max_retries + 1): |
There was a problem hiding this comment.
Iterative retry loop breaks math.inf unlimited retries
Medium Severity
The refactored retry logic uses range(max_retries + 1) which crashes with TypeError when max_retries is math.inf, since range() requires integer arguments. The old recursive approach handled this correctly because it only compared remaining_retries > 0. The error message in __init__ still explicitly recommends math.inf for unlimited retries, making this a documented-but-broken feature.
Additional Locations (2)
| return o.isoformat() | ||
| if isinstance(o, pydantic.BaseModel): | ||
| return model_dump(o, exclude_unset=True, mode="json", by_alias=True) | ||
| return super().default(o) |
There was a problem hiding this comment.
Custom JSON encoder handles datetime but not date
Low Severity
The new _CustomEncoder handles datetime serialization via isinstance(o, datetime) but does not handle date objects. Since datetime is a subclass of date (not the other way around), pure date values will fall through to super().default(o) and raise a TypeError. Given the stated goal of "extended type support," omitting date while including datetime appears to be an oversight. If any date objects survive the transform pipeline and reach openapi_dumps, serialization will fail.
| # mypy can't narrow the type | ||
| return extras["cls"] # type: ignore[no-any-return] | ||
|
|
||
| return None |
There was a problem hiding this comment.
Missing "definitions" schema handling in extra fields type resolution
Low Severity
_get_extra_fields_type doesn't handle the "definitions" schema wrapper type, unlike _extract_field_schema_pv2 which was updated in the same PR to unwrap it. For models with forward references or self-referential types (whose core schema is wrapped in "definitions"), the function returns None instead of the actual extras type, causing extra fields to skip type-aware construction.
Additional Locations (1)
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| kwargs["files"] = files | ||
| else: | ||
| headers.pop("Content-Type", None) | ||
| kwargs.pop("data", None) |
There was a problem hiding this comment.
JSON body silently dropped when files present
Low Severity
When a request includes both json_data (body) and files but the Content-Type header is not multipart/form-data, the new body-handling logic silently drops json_data. The elif not files guard on line 558 skips setting content from json_data when files are present, and no other path forwards the JSON data to httpx. The old code passed both json and files to httpx (which would error on the conflict), making the issue explicit rather than a silent data loss.
|
Closing stale PR |


Automated Release PR
4.1.0 (2026-02-25)
Full Changelog: v4.0.0...v4.1.0
Features
NotGivenfor body (#67) (3ad7f25)X-Stainless-Read-Timeoutheader (#63) (a594c75)Bug Fixes
model_dumpandmodel_dump_jsonfor Pydantic v1 (898ca7b)Chores
httpx-aiohttpversion to 0.1.9 (7aeb4c8)actions/github-script(bdad5ed)api.mdfiles (034e708)--fixargument to lint script (0b1e68e)test_proxy_environment_variablesmore resilient (f79d30c)test_proxy_environment_variablesmore resilient to env (08e33e4)pyproject.tomlfile (f87b268)actions/checkoutversion (54d6bd9)get_platformtest (ef07d85)Documentation
This pull request is managed by Stainless's GitHub App.
The semver version number is based on included commit messages. Alternatively, you can manually set the version number in the title of this pull request.
For a better experience, it is recommended to use either rebase-merge or squash-merge when merging this pull request.
🔗 Stainless website
📚 Read the docs
🙋 Reach out for help or questions
Note
High Risk
Touches core HTTP client request/response handling (serialization, retries, streaming, headers, new transport), which can change runtime behavior across all API calls. Also raises the minimum supported Python version and updates dependency/tooling pins, potentially impacting downstream environments.
Overview
Bumps the SDK to
4.1.0and updates the generated API/docs, including changingworkers.deployments.voicemethods to returnVoiceDeploymentand refreshing changelog/manifest metadata.Extends the client with an optional
aiohttp-backed async HTTP client (DefaultAioHttpClient+aiohttpextra), raw/binary request body support via a newcontentparameter, and a custom JSON serializer (openapi_dumps) to handle additional types (e.g.,datetime,pydantic.BaseModel). Streaming/SSE handling is hardened to ensure responses are closed even if not fully consumed.Reworks request plumbing: adds
follow_redirectsper-request option, sendsX-Stainless-Read-Timeout, avoids sendingContent-Typeon GETs, improves pagination to support JSON-body pagination, refactors retry logic to a loop with stable idempotency keys, and broadens JSON content-type detection.Modernizes project/infra: drops Python 3.8 (now
>=3.9), updates typing/tooling configs (moves mypy settings intopyproject.toml, updates ruff/pyright, runs pytest in parallel), refreshes lockfiles, and updates CI/devcontainer setup (Rye0.44.0, newbuildjob + artifact upload, job timeouts, branch filters, and optional Homebrew installs).Written by Cursor Bugbot for commit 7039a1a. This will update automatically on new commits. Configure here.