Skip to content

Commit 6404f34

Browse files
k223kimnateprewitt
andauthored
Fix prepare_body stream detection for __getattr__-based file wrappers (#7433)
--------- Co-authored-by: Nate Prewitt <nate.prewitt@gmail.com>
1 parent 0b401c7 commit 6404f34

2 files changed

Lines changed: 18 additions & 3 deletions

File tree

src/requests/models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -596,9 +596,9 @@ def prepare_body(
596596
if not isinstance(body, bytes):
597597
body = body.encode("utf-8")
598598

599-
if isinstance(data, Iterable) and not isinstance(
600-
data, (str, bytes, list, tuple, Mapping)
601-
):
599+
# data that proxies attributes to underlying objects needs hasattr
600+
is_iterable = isinstance(data, Iterable) or hasattr(data, "__iter__")
601+
if is_iterable and not isinstance(data, (str, bytes, list, tuple, Mapping)):
602602
try:
603603
length = super_len(data)
604604
except (TypeError, AttributeError, UnsupportedOperation):

tests/test_requests.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2073,6 +2073,21 @@ def __iter__(self):
20732073

20742074
assert "Unable to rewind request body" in str(e)
20752075

2076+
def test_getattr_proxy_stream_follows_redirect(self, httpbin):
2077+
"""Ensure stream wrappers that don't implement __iter__ directly are still detected."""
2078+
2079+
class AttrProxy:
2080+
def __init__(self):
2081+
self._file = io.BytesIO(b"data")
2082+
2083+
def __getattr__(self, name):
2084+
return getattr(self._file, name)
2085+
2086+
r = requests.post(
2087+
httpbin("redirect-to?url=/post&status_code=307"), data=AttrProxy()
2088+
)
2089+
assert r.json()["data"] == "data"
2090+
20762091
def _patch_adapter_gzipped_redirect(self, session, url):
20772092
adapter = session.get_adapter(url=url)
20782093
org_build_response = adapter.build_response

0 commit comments

Comments
 (0)