feat(python-sdk): move template build-context uploads onto pyqwest - #1603
feat(python-sdk): move template build-context uploads onto pyqwest#1603mishushakov wants to merge 5 commits into
Conversation
🦋 Changeset detectedLatest commit: ada7677 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
PR SummaryMedium Risk Overview Content-Length framing for streamed archive bodies is unchanged (required so S3 does not get chunked encoding). The default 1-hour upload timeout now applies to the whole request, not per socket write. Upload regression tests normalize header names to lowercase because pyqwest/hyper lowercases them where httpcore title-cased them. Reviewed by Cursor Bugbot for commit ada7677. Bugbot is set up for automated code reviews on this repo. Configure here. |
Package ArtifactsBuilt from 7ef7a31. Download artifacts from this workflow run. JS SDK ( npm install ./e2b-2.38.1-migrate-template-uploads-to-pyqwest.0.tgzCLI ( npm install ./e2b-cli-2.16.2-migrate-template-uploads-to-pyqwest.0.tgzPython SDK ( pip install ./e2b-2.37.0+migrate.template.uploads.to.pyqwest-py3-none-any.whl |
6288fe5 to
a6fdb80
Compare
a6fdb80 to
08cacf7
Compare
08cacf7 to
fa0a167
Compare
fa0a167 to
ccab1da
Compare
Volume/AsyncVolume file operations join the API client on the ApiPyqwestTransport + connection-retry stack; transport caches become process-global keyed by proxy. httpx.Proxy values reduce to plain proxy URLs; stream_idle_timeout is accepted but a no-op at this point (bounded by the transport in the next commits). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n a dedicated transport reqwest's read timer keeps ticking while a request body is sent and while waiting for the response head, so a shared read_timeout would kill slow uploads; streamed reads get their own transport with read_timeout=60s (JS SDK parity), uploads and unary calls stay unbounded-per-read. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ead_file asyncio.wait_for around each read (response head and every chunk); explicit values run on the regular transport so values above the 60s transport bound aren't capped and 0 disables idle bounding. Sync keeps the parameter but ignores it — it cannot interrupt a blocking read into the Rust transport. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… alias Follows the control-plane PR in dropping the runtime import of httpx's private `_types` module: the volume connection config and the `Volume`/`AsyncVolume` constructors take the `ProxyTypes` alias `e2b.connection_config` now owns. The volume client factories needed no change — they key their transports by `ProxyConfig` and no longer name the input union at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
build_api.upload_file uses a one-off pyqwest transport; Content-Length framing verified at the wire level for both the spooled sync archive and the async-iterator body (S3 rejects chunked encoding). The upload-file regression tests compare header names case-insensitively since hyper lowercases them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ccab1da to
ada7677
Compare
What
Stacked on #1602 (which is stacked on #1601). Migrates the template build-context uploads (streaming the build archive to S3 presigned URLs in
build_api.upload_file) onto pyqwest via its httpx-compatible transport adapter.Originally deferred from #1601 because S3 presigned URLs reject chunked transfer encoding and Content-Length framing through reqwest was unverified. Verified at the wire level (raw-socket capture server): httpx's Content-Length — derived from the spooled archive (sync) or set explicitly on the async-iterator body (async) — is forwarded by the adapter and reqwest keeps Content-Length framing for streamed bodies, no chunked fallback.
Note
Rebased onto #1601, which maps
httpx.Proxyonto pyqwest'sProxyobject and therefore requires pyqwest 0.8 (released, and locked in #1601). The only change here is following the rename — this PR builds its transport fromproxy_to_config(...)instead ofproxy_to_url(...).How
e2b/template_sync/build_api.py/template_async/build_api.py:upload_fileuses a one-off pyqwest transport (ApiPyqwestTransportfrom feat(python-sdk): move the REST API client onto pyqwest's httpx transport adapter #1601) instead of the generated client's httpx transport.verify_ssl=Falseon the generated client is no longer honored for uploads (pyqwest has no insecure-TLS option), andhttp2=Falseis gone (S3 negotiates HTTP/1.1 via ALPN anyway).Testing
tests/{sync,async}/*/test_upload_file.py(the [JS SDK] uploadFile uses chunked transfer encoding, causing 501 NotImplemented on S3 presigned PUT URLs #1243 regression tests — Content-Length present and equal to the body, no chunked encoding) pass through pyqwest; the capture handlers now compare header names case-insensitively since hyper lowercases them where httpcore title-cased.ruff), typecheck (ty), unit suite: green.Usage example
No API changes — template builds upload their context exactly as before:
🤖 Generated with Claude Code