You can pass in either a dict
, or a sequence of two-value tuples.
And OrderedDict
is trivially converted to such a sequence:
r = requests.post("https://instructure-uploads.s3.amazonaws.com/", files=payload.items())
However, because the collections.OrderedDict()
type is a subclass of dict
, calling items()
is exactly what requests
does under the hood, so passing in an OrderedDict
instance directly Just Works too.
As such, something else is wrong. You can verify what is being posted by posting to http://httpbin/post
instead:
import pprint
pprint.pprint(requests.post("http://httpbin.org/post", files=payload.items()).json())
Unfortunately, httpbin.org
does not preserve ordering. Alternatively, you can create a dedicated HTTP post bin at http://requestb.in/ as well; it'll tell you in more detail what goes on.
Using requestb.in, and by replacing '@log.txt'
with an open file object, the POST from requests is logged as:
POST /tlrsd2tl HTTP/1.1
User-Agent: python-requests/1.1.0 CPython/2.7.3 Darwin/11.4.2
Host: requestb.in
Content-Type: multipart/form-data; boundary=7b12bf345d0744b6b7e66c7890214311
Content-Length: 1601
Connection: close
Accept-Encoding: gzip, deflate, compress
Accept: */*
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="content-type"; filename="content-type"
Content-Type: application/octet-stream
text/plain
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="success_action_redirect"; filename="success_action_redirect"
Content-Type: application/octet-stream
https://ian.test.instructure.com/api/v1/files/30652543/create_success?uuid=<opaque_string>
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="Signature"; filename="Signature"
Content-Type: application/octet-stream
<opaque_string>
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="Filename"; filename="Filename"
Content-Type: application/octet-stream
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="acl"; filename="acl"
Content-Type: application/octet-stream
private
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="Policy"; filename="Policy"
Content-Type: application/octet-stream
<opaque_string>
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="key"; filename="key"
Content-Type: application/octet-stream
account_95298/attachments/30652543/log.txt
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="AWSAccessKeyId"; filename="AWSAccessKeyId"
Content-Type: application/octet-stream
<opaque_string>
--7b12bf345d0744b6b7e66c7890214311
Content-Disposition: form-data; name="file"; filename="log.txt"
Content-Type: text/plain
some
data
--7b12bf345d0744b6b7e66c7890214311--
showing that ordering is preserved correctly.
Note that requests
does not support the Curl-specific @filename
syntax; instead, pass in an open file object:
'file': open('log.txt', 'rb')
You may also want to set the content-type
field to use title case: 'Content-Type': ..
.
If you still get a 500 response, check the r.text
response text to see what Amazon thinks is wrong.