Python requests POST file with multipart form and cookies
I need to upload a file with some information about the file using cookies. A command line as below works fine:
curl -v -X -POST -F file=@"path_to_file/my_file.xml; type=text/xml" -F rowData='{"fileVersion":"1.0", "owner":"xyz", "fileName":"my_file.xml"}' https://x.x.x.x:xxxx/path_to_receiving_point -H 'Cookie: my_cookie_goes_here'
I want to convert that command to Python using requests
.
import requests
#First I get the cookies with a POST
#please assume this part works and I get a <RequestsCookieJar> output below
req = requests.POST(...)
cookies = req.cookies
#Then I construct the actual request to upload file
address = "https://x.x.x.x:xxxx/path_to_receiving_point"
rowData = {"fileVersion":"1.0", "owner":"xyz", "fileName":"my_file.xml"}
#files = {'file': ("path_to_file/my_file.xml", open("path_to_file/my_file.xml", 'rb'), 'type=text/xml', rowData)}
files = {'file': ('my_file.xml', open("path_to_file/my_file.xml", 'rb'), 'type=text/xml', rowData)}
upload_req = requests.post(address, files=files, cookies=cookies)
print(upload_req.json())
Is this the correct way? Because I receive this error:
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
For the cookies
, this is how it looks like:
<RequestsCookieJar[<Cookie userData=%7B%22access_token%22%3A%2288fcdfb8-451f-4607-9517-9ecae16c9285%22%2C%22role%22%3A%5B1%2C5%2C32%5D%2C%22authType%22%3A%22LOCAL%22%2C%22user%22%3A%22admin%22%2C%22password_regex%22%3A%22%28%28%3F%3D.*%5BA-Z%5D%29%28%3F%3D.*%5Ba-z%5D%29%28%3F%3D.*%5C%5Cd%29%28%3F%3D.*%5B__special%5D%29.%7B15%2C%7D%29%22%2C%22special_chars%22%3A%22%21%5C%22%23%24%25%26%27%28%29*%2B%2C-.%2F%3A%3B%3C%3D%3E%3F%40%5B%5D%5E_%60+%7B%5C%5C%7C%7D%7E%22%7D for x.x.x.x/path_to_login/login>]>
Update: just to confirm I am able to verify the cookies
part is correct. My suspicion now is that the files
dict is not in the right format. If someone could advise on that?
Update 2: I edited the files
dict to exclude the first file name as above. Now the error I got is:
return request('post', url, data=data, json=json, **kwargs)
File "/home/username/.local/share/virtualenvs/proj-zrz-666L/lib/python3.9/site-packages/requests/api.py", line 61, in request
return session.request(method=method, url=url, **kwargs)
File "/home/username/.local/share/virtualenvs/proj-zrz-666L/lib/python3.9/site-packages/requests/sessions.py", line 528, in request
prep = self.prepare_request(req)
File "/home/username/.local/share/virtualenvs/proj-zrz-666L/lib/python3.9/site-packages/requests/sessions.py", line 456, in prepare_request
p.prepare(
File "/home/username/.local/share/virtualenvs/proj-zrz-666L/lib/python3.9/site-packages/requests/models.py", line 319, in prepare
self.prepare_body(data, files, json)
File "/home/username/.local/share/virtualenvs/proj-zrz-666L/lib/python3.9/site-packages/requests/models.py", line 512, in prepare_body
(body, content_type) = self._encode_files(files, data)
File "/home/username/.local/share/virtualenvs/proj-zrz-666L/lib/python3.9/site-packages/requests/models.py", line 166, in _encode_files
rf.make_multipart(content_type=ft)
File "/home/username/.local/share/virtualenvs/proj-zrz-666L/lib/python3.9/site-packages/urllib3/fields.py", line 268, in make_multipart
self._render_parts(
File "/home/username/.local/share/virtualenvs/proj-zrz-666L/lib/python3.9/site-packages/urllib3/fields.py", line 226, in _render_parts
parts.append(self._render_part(name, value))
File "/home/username/.local/share/virtualenvs/proj-zrz-666L/lib/python3.9/site-packages/urllib3/fields.py", line 206, in _render_part
return self.header_formatter(name, value)
File "/home/username/.local/share/virtualenvs/proj-zrz-666L/lib/python3.9/site-packages/urllib3/fields.py", line 117, in format_header_param_html5
value = _replace_multiple(value, _HTML5_REPLACEMENTS)
File "/home/username/.local/share/virtualenvs/proj-zrz-666L/lib/python3.9/site-packages/urllib3/fields.py", line 90, in _replace_multiple
result = pattern.sub(replacer, value)
TypeError: expected string or bytes-like object
This error seems to say the XML file is not read into string
or ```bytes-like```` object.
Update 3:
So I digged further into this file
/home/usernme/.local/share/virtualenvs/proj-zrz-666L/lib/python3.9/site-packages/urllib3/fields.py
particularly, function:
def _replace_multiple(value, needles_and_replacements):
def replacer(match):
return needles_and_replacements[match.group(0)]
pattern = re.compile(
r"|".join([re.escape(needle) for needle in needles_and_replacements.keys()])
)
result = pattern.sub(replacer, value)
return result
Apparently, this function takes an argument value
which is supposed to be string
or byte-type
. But in this POST, it is a tuple. Why such an error?
Solution 1:
You can deserialize the response with upload_req.json()
only when your service is serializing the data with some JSON serializer. clearly, your response Content-type
is not JSON
Before directly writing print(upload_req.json())
you can simply check the response with print(upload_req.text) or print(upload_req.__dict__)
and this way you can see everything present in the response including response headers and then you can make a decision on parsing
it properly.