Allow str content for multipart upload files (#2400)

This commit is contained in:
Tom Christie 2022-10-06 17:53:51 +01:00 committed by GitHub
parent 770d4f2254
commit 0ebe9259ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 8 deletions

View File

@ -122,8 +122,14 @@ class FileField:
# requests does the opposite (it overwrites the header with the 3rd tuple element)
headers["Content-Type"] = content_type
if isinstance(fileobj, (str, io.StringIO)):
raise TypeError(f"Expected bytes or bytes-like object got: {type(fileobj)}")
if "b" not in getattr(fileobj, "mode", "b"):
raise TypeError(
"Multipart file uploads must be opened in binary mode, not text mode."
)
if isinstance(fileobj, io.StringIO):
raise TypeError(
"Multipart file uploads require 'io.BytesIO', not 'io.StringIO'."
)
self.filename = filename
self.file = fileobj

View File

@ -80,7 +80,7 @@ ResponseExtensions = Dict[str, Any]
RequestData = Mapping[str, Any]
FileContent = Union[IO[bytes], bytes]
FileContent = Union[IO[bytes], bytes, str]
FileTypes = Union[
# file (or bytes)
FileContent,

View File

@ -339,18 +339,37 @@ def test_multipart_encode_files_allows_bytes_content() -> None:
assert content == b"".join(stream)
def test_multipart_encode_files_raises_exception_with_str_content() -> None:
files = {"file": ("test.txt", "<bytes content>", "text/plain")}
def test_multipart_encode_files_allows_str_content() -> None:
files = {"file": ("test.txt", "<str content>", "text/plain")}
with mock.patch("os.urandom", return_value=os.urandom(16)):
boundary = os.urandom(16).hex()
with pytest.raises(TypeError):
encode_request(data={}, files=files) # type: ignore
headers, stream = encode_request(data={}, files=files)
assert isinstance(stream, typing.Iterable)
content = (
'--{0}\r\nContent-Disposition: form-data; name="file"; '
'filename="test.txt"\r\n'
"Content-Type: text/plain\r\n\r\n<str content>\r\n"
"--{0}--\r\n"
"".format(boundary).encode("ascii")
)
assert headers == {
"Content-Type": f"multipart/form-data; boundary={boundary}",
"Content-Length": str(len(content)),
}
assert content == b"".join(stream)
def test_multipart_encode_files_raises_exception_with_StringIO_content() -> None:
files = {"file": ("test.txt", io.StringIO("content"), "text/plain")}
with mock.patch("os.urandom", return_value=os.urandom(16)):
with pytest.raises(TypeError):
encode_request(data={}, files=files) # type: ignore
def test_multipart_encode_files_raises_exception_with_text_mode_file() -> None:
with tempfile.TemporaryFile(mode="w") as upload:
files = {"file": ("test.txt", upload, "text/plain")}
with pytest.raises(TypeError):
encode_request(data={}, files=files) # type: ignore