Repository navigation
feat(boxsdk): Replace requests-toolbelt with streaming MultipartStream encoder - #1606
Merged
Merged
Conversation
…m encoder Back the legacy boxsdk MultipartStream with the streaming encoder from box_sdk_gen.networking.multipart_stream, keeping its (data, files) constructor and data-before-files ordering. Seekable file streams are now sent with an exact Content-Length. This removes the requests-toolbelt dependency from the combined SDK. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
requests-toolbelt with streaming MultipartStream encoder
The format-check job installs the latest black, which now wraps this yield statement. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Coverage Report for CI Build 37449479995Warning No base build found for commit Coverage: 97.185%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsRequires a base build to compare against. How to fix this → Coverage Stats
💛 - Coveralls |
… in MultipartStream Sync the generated encoder and its tests with box/box-codegen#995: - text streams such as io.StringIO are encoded as UTF-8 and sent chunked - a length the stream reports through __len__ or len is used before seeking to its end, like requests and requests-toolbelt The legacy functional tests upload through a mocked file that reports a length but can't seek, which was measured as empty and sent no content. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…d length in MultipartStream" This reverts commit c3cfa44. The generated files come to combined-sdk through the box/box-codegen#995 sync PR instead. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Patch out MultipartStream, which sizes file streams itself, so the test checks that the session rewinds file streams before each attempt without depending on how the generated encoder measures them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n#995 Sync the generated encoder and its tests with box/box-codegen#995 (029716b5) to run CI against them. To be reverted once CI passes; the generated files come to combined-sdk through the #995 sync PR. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…x-codegen#995" This reverts commit a891485 now that CI passed with it. The generated files come to combined-sdk through the box/box-codegen#995 sync PR. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lukaszsocha2
approved these changes
Oct 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
boxsdk.util.multipart_stream.MultipartStreamwith the streaming encoder frombox_sdk_gen.networking.multipart_stream, which already replacedMultipartEncoderinbox_sdk_gen(box/box-codegen#994, released in 4.17.0)MultipartStream(data, files)constructor and data-before-files ordering; acceptstr,bytesand stream values, and(file_name, value)/(file_name, value, content_type)tuples (the avatar upload uses the 3-tuple)requests-toolbeltfrominstall_requires; it was only used by this classdocs/boxsdk/usage/files.mdThis class reuses the generated encoder in
box_sdk_gen/networking/multipart_stream.py, which this PR leaves unchanged; it gets the needed fixes through box/box-codegen#995's generated sync PR:io.StringIOare encoded as UTF-8 and sent chunked. 4.17.0's encoder fails on them, which worked withrequests-toolbelt__len__orlenis used before seeking to its end, likerequestsandrequests-toolbeltUntil that sync lands on
combined-sdk,test/boxsdk/functional/test_file_upload_update_download.pyfails here (36 cases): it uploads through a mocked file that reports a length but can't seek, which 4.17.0's encoder measures as empty. With #995's latest encoder temporarily synced into this branch (a891485, reverted ind8fc6b9), all CI checks passed.Behaviour changes (for the changelog)
requests-toolbeltis no longer installed with the SDK. Code that imports it without declaring it as its own dependency needs to add it.Session(network_layer=...)receive thisMultipartStreamasdatafor streamed uploads. It keepsread(),len,content_typeandboundary, but no longer has theMultipartEncoderAPI (fields,to_string(),encoding,boundary_value), and is not aMultipartEncoderinstance.Content-Length, as before. Non-seekable streams still aren't supported by the legacy session, which seeks every file stream before each attempt; that's unchanged.Testing
requests-toolbeltuninstalled (confirmed not importable)test/boxsdk/unit): 6403 passed, 2 xfailed (baseline 6400 passed, 3 xfailed)test_multipart_stream.py: replaced the toolbelt-onlyto_string()withread(), dropped the "Encoder does not support empty fields" xfail since empty input now works, added tests for the exact rendered body (including the content-type tuple) and lazy readingtest_session.py: the streaming upload test asserts the rendered body andContent-Typeheader;test_box_session_seeks_file_after_retrypatches outMultipartStream, so it counts only the session's rewinds before each attempt, independent of how the generated encoder sizes streamstest/boxsdk/functional): 195 passed, 11 xfailed (same ascombined-sdk)pytest --disable-pytest-warnings): 6627 passed, 13 xfailedbox_sdk_gennetwork tests: 81 passedSessionto a local HTTP server: exactContent-Length,attributesbeforefile, non-ASCII JSON attributes intact, 1 MB file byte-identicaltest_jwt_auth.py: formatted with black 26.10, which CI now installs and which flagged this untouched fileblack --preview --skip-string-normalization --checkclean🤖 Generated with Claude Code