Having trouble uploading files with Box.com API - python

I am new to programming and learning python, so please bear with me, I appreciate the help....
I am working on a project where I need to upload files to storage services and I am currently trying to use the box API. I am trying to work with the code on this page:
how to use python's Request library to make an API call with an attachment and a parameter
import requests
import json
#the user access token
access_token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
#the name of the file as you want it to appear in box
filename = 'box_file'
#the actual file path
src_file = "C:\Python\Wildlife.wmv"
#the id of the folder you want to upload to
parent_id = '0'
headers = { 'Authorization: Bearer {0}'.format(access_token)}
url = 'https://upload.box.com/api/2.0/files/content'
files = { 'filename': (filename, open(src_file,'rb')) }
data = { "parent_id": parent_id }
response = requests.post(url, data, files, headers)
file_info = response.json()
I have tried a number of different things that really haven't gotten me any closer, so I am posting my slight adaptation of their code. Currently I am getting this error:
Traceback (most recent call last):
File "transfer2.py", line 18, in <module>
response = requests.post(url, data, files, headers)
TypeError: post() takes from 1 to 3 positional arguments but 4 were given
I have also had issues with the file_info = response.json()" in some of my other experiments. If someone could help me to get this working I would greatly appreciate it.
I am using python 3 if that helps.
edit 4/6
As requested, I changed this line:
response = requests.post(url, data=data, files=files, headers=headers)
This is the error I now get:
Traceback (most recent call last):
File "transfer2.py", line 18, in <module>
response = requests.post(url, data=data, files=files, headers=headers)
File "C:\Python34\lib\site-packages\requests\api.py", line 108, in post
return request('post', url, data=data, json=json, **kwargs)
File "C:\Python34\lib\site-packages\requests\api.py", line 50, in request
response = session.request(method=method, url=url, **kwargs)
File "C:\Python34\lib\site-packages\requests\sessions.py", line 450, in request
prep = self.prepare_request(req)
File "C:\Python34\lib\site-packages\requests\sessions.py", line 381, in prepare_request
hooks=merge_hooks(request.hooks, self.hooks),
File "C:\Python34\lib\site-packages\requests\models.py", line 305, in prepare
self.prepare_headers(headers)
File "C:\Python34\lib\site-packages\requests\models.py", line 410, in prepare_headers
self.headers = CaseInsensitiveDict((to_native_string(name), value) for name, value in headers.items())
AttributeError: 'set' object has no attribute 'items'

In the requests library for request.post(), headers and files are both keyword arguments only, I would also make data a keyword argument, e.g.:
response = requests.post(url, data=data, files=files, headers=headers)

from boxsdk import Client, OAuth2
oauth = OAuth2( client_id="dlpjkcxxxxxxxxxxxxxxxxxxxxcom",client_secret="xxxxxxxxxxxxxxxxxxxxxxxxx", access_token="xxxxxxxxxxxxxxxxxxxxxxxxxxx", )
client = Client(oauth)
shared_folder = client.folder(folder_id='0',).create_subfolder('sxxxx')
uploaded_file = shared_folder.upload('/root/xxxxxx.txt')

Related

requests.get() throws an exception in aws lambda

I'm not able to make HTTP calls from python based lambda function hosted on AWS and managed through Serverless framework.
I've tried using botocore.vendored requests module but it shows deprecation warning and suggested to use the requests module itself.
url = V2_URL + '/api/analytics/validate/' + smId
headers = {
'Content-Type':'application/json',
'Authorization': token
}
response = requests.get(url, headers=headers)
print('Result: ')
print(response.content)
In Cloudwatch, I see this stack trace:
[ERROR] UnboundLocalError: local variable 'response' referenced before assignment
Traceback (most recent call last):
File "/var/task/serverless_sdk/__init__.py", line 97, in wrapped_handler
return user_handler(event, context)
File "src/authorize.py", line 21, in validate
principal_id = verify_token(whole_auth_token, event['pathParameters']['smId'])
File "src/authorize.py", line 38, in verify_token
response = requests.get(url, headers=headers)
File "/var/task/requests/api.py", line 75, in get
return request('get', url, params=params, **kwargs)
File "/var/task/requests/api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
File "/var/task/requests/sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "/var/task/requests/sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "/var/task/requests/adapters.py", line 449, in send
timeout=timeout
File "/var/task/serverless_sdk/__init__.py", line 384, in wrapper
if response:
As #blhsing and #Mark A pointed out, there was a bug in version 3.1.1 of #serverless/enterprise-plugin package. Upgrading it to version 3.1.2 solved the issue for me. All I had to do was npm i -g serverless and it took care of itself.
Details of issue here: https://github.com/serverless/serverless/issues/6801

How to fix Python code returning TypeError: 'str' object is not callable?

i've been trying to send a POST HTTP request using Python (first time using it) and it keeps returning a TypeError: 'str' object is not callable
My code:
import requests
import json
c100 = "100";
url ="http://api.orange.com/smsmessaging/v1/outbound/tel+21654614211/requests"
payload = {
"outboundSMSMessageRequest": {
"address": "tel+21653424499",
"outboundSMSTextMessage": {
"message": "Capteur "+ c100 +" est en incendie"
},
"senderAddress": "tel+21654614211",
"senderName": "GCI"
}
}
headers = {'content-type': 'application/json'}
r = requests.post(url, auth=('Basic <omitted>'), data=json.dumps(payload), headers=headers)
output:
Traceback (most recent call last):
File "main.py", line 18, in <module>
r = requests.post(url, auth=('Basic U0cwUE1aeGZmZ0JLbUkzWUV2ZWlsM0xBdEt0UVZ4Q1k6SVRqWXQxRU5nWlV4SGM5OQ=='), data=payload, headers=headers)
File "/usr/lib/python3/dist-packages/requests/api.py", line 88, in post
return request('post', url, data=data, **kwargs)
File "/usr/lib/python3/dist-packages/requests/api.py", line 44, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 433, in request
prep = self.prepare_request(req)
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 371, in prepare_request
hooks=merge_hooks(request.hooks, self.hooks),
File "/usr/lib/python3/dist-packages/requests/models.py", line 291, in prepare
self.prepare_auth(auth, url)
File "/usr/lib/python3/dist-packages/requests/models.py", line 470, in prepare_auth
r = auth(self)
TypeError: 'str' object is not callable
your Authentication is wrong, and also the question is: do You need authentication at all?
Basic Authentication Many web services that require authentication accept HTTP Basic Auth. This is the simplest kind, and Requests
supports it straight out of the box.
Making requests with HTTP Basic Auth is very simple:
>>> from requests.auth import HTTPBasicAuth
>>> requests.get('https://api.github.com/user', auth=HTTPBasicAuth('user', 'pass'))
<Response [200]>
In fact, HTTP Basic Auth is so common that Requests provides a handy
shorthand for using it:
>>> requests.get('https://api.github.com/user', auth=('user', 'pass'))
<Response [200]>
Providing the credentials in a tuple like this is exactly the same as
the HTTPBasicAuth example above.
NOTE:
if you have token probably you need something like:
import requests
auth_token='sdasadadsadas'
head = {'Authorization': 'Bearer ' + auth_token}
payload = {
"outboundSMSMessageRequest": {
"address": "tel+21653424499",
"outboundSMSTextMessage": {
"message": "Capteur "+ c100 +" est en incendie"
},
"senderAddress": "tel+21654614211",
"senderName": "GCI"
}
}
url = 'http://api.orange.com/smsmessaging/v1/outbound/tel+21654614211/requests'
response = requests.post(url, json = payload, headers=head)
The authentication parameter in your original code is wrong. If you remove it, it will work.
r = requests.post(url, data=json.dumps(payload), headers=headers)

Uploading files using Python requests module

I need to load a file using a soap endpoint url...When I use the below code to load it the files are getting loaded but they are not in a readable format...When I load using SOAPUI tool it loads properly...
import requests
xml = '''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:v1="http://s.sa.com/services/Attachment/v1.0">
<soapenv:Header/>
<soapenv:Body>
<v1:attachment>
<filename>FUZZY.csv</filename>
<data>cid:138641430598</data>
</v1:attachment>
</soapenv:Body>
</soapenv:Envelope>'''
target_url = 'https://s.sa.com:443/soatest/FileAttachmentService'
headers = {'Content-Type': 'text/xml','charset':'utf-8'}
r = requests.post(target_url,data=xml,headers=headers,auth=('3user1',''))
print 'r.text = ', r.text
print 'r.content = ', r.content
print 'r.status_code = ', r.status_code
New changes:-
files = {'file':open('./FUZZY.csv','rb')}
print files
r = requests.post(target_url,files=files,data=xml,headers=headers,auth=('p3user1',''))
Error:
Traceback (most recent call last):
File "soapcall_python.py", line 18, in <module>
r = requests.post(target_url,files=files,data=xml,headers=headers,auth=('p3user1',''))
File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/api.py", line 88, in post
return request('post', url, data=data, **kwargs)
File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/api.py", line 44, in request
return session.request(method=method, url=url, **kwargs)
File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/sessions.py", line 418, in request
prep = self.prepare_request(req)
File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/sessions.py", line 356, in prepare_request
hooks=merge_hooks(request.hooks, self.hooks),
File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/models.py", line 297, in prepare
self.prepare_body(data, files)
File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/models.py", line 432, in prepare_body
(body, content_type) = self._encode_files(files, data)
File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/models.py", line 109, in _encode_files
raise ValueError("Data must not be a string.")
ValueError: Data must not be a string.
You aren't sending the contents of the file anywhere. You're just sending a reference to a file that doesn't exist anywhere that the server can see.
As the docs for SOAP references to attachments explains, the way you do this is to send a MIME-multipart message. If you're using the CID reference mechanism, that cid isn't some arbitrary string, it has to match the Content-ID header of a message in the MIME envelope.
The requests docs for POST a Multipart-Encoded File explain how to send the contents of a file as a message within a MIME request; briefly:
with open('FUZZY.csv', 'rb') as f:
files = {'file': f}
r = requests.post(target_url,
data=xml, headers=headers, auth=('3user1',''),
files=files)
However, this simple method doesn't give you access to the Content-ID that will be generated under the covers for your message. So, if you want to use the CID reference mechanism, you will need to generate the MIME envelope manually (e.g., by using email.mail.MIMEMultipart) and sending the entire thing as a data string.

Can't POST file attachment and data parameters with Python requests lib

I'm trying to implement a simple Django view that accept a file attachment and some other parameters and proxy the request on a remote API call.
Please note: the proxy is not the point of my question :)
This is how I implemented the view:
def image_upload(request):
token = request.POST['token']
image_file = request.FILES.values()[0]
files = {'file': ('myupload.txt', image_file.read())}
client_id = request.POST['client_id']
folder_id = request.POST['folder_id']
advert_id = request.POST['advert_id']
image_type = request.POST['image_type']
crop_image = request.POST['crop_image']
api_base_url = settings.API_BASE_URL
file_post_data = {'client_id': client_id, 'folder_id': folder_id, 'advert_id': advert_id,
'image_type': image_type, 'crop_image': crop_image}
auth_header = {'Authorization': 'Token ' + token}
r = requests.post(api_base_url + 'assets/image/upload/',
data = json.dumps(file_post_data),
headers = auth_header,
files = files)
return r.json()
The problem is that when I test this view (I use Django Test Client to do it) I get an error on the line "files = files)" that says "ValueError: cannot encode objects that are not 2-tuples".
The complete trace log is this one:
======================================================================
ERROR: test_image_upload (fbx.tests.FbxTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/andrea/Documents/src/fbxapp/onboard/fbx/tests.py", line 18, in test_image_upload
'image_type': 'A', 'crop_image': False, 'attachment': fp})
File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 449, in post
response = super(Client, self).post(path, data=data, content_type=content_type, **extra)
File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 262, in post
return self.request(**r)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 111, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/home/andrea/Documents/src/fbxapp/onboard/fbx/views.py", line 42, in image_upload
files = files)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 88, in post
return request('post', url, data=data, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 44, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 324, in request
prep = req.prepare()
File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 225, in prepare
p.prepare_body(self.data, self.files)
File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 385, in prepare_body
(body, content_type) = self._encode_files(files, data)
File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 99, in _encode_files
fields = to_key_val_list(data or {})
File "/usr/local/lib/python2.7/dist-packages/requests/utils.py", line 136, in to_key_val_list
raise ValueError('cannot encode objects that are not 2-tuples')
ValueError: cannot encode objects that are not 2-tuples
I've also tried a quick test using this to read a file: files = {'file': ('myupload.txt', open('/tmp/mytmp.txt', 'rb'))}
but it doesn't work. Do tou have any idea about how to fix this?
Thanks!
You cannot simultaneously post JSON data and multipart/form-data which is in essence what you're trying to do here. json.dumps returns a string so you're sending a string that looks like
'{"client_id": 1, "folder_id": 2, "advert_id": 3, "image_type": "jpeg", "crop_image": true}'
And then telling requests you want to use that in combination with a multipart/form-data request by sending something in via the files parameter. That is impossible and could possibly raise a better exception.
Either add the file to the JSON data after reading it into memory and send that with the appropriate Content-Type header or send the entire thing as a multipart/form-data request without using json.dumps and simply passing the dictionary you're creating to data. Use one or the other but not both.
That aside, you say that your exception comes from the line that only has files=files) on it, but it is not that line alone that causes the exception. The exception is raised by the function which happens to end on that line. The fact that your exception arises from that too is mere coincidence. This is an wart in Python that may possibly be fixed in Python 3.4. You should upgrade, because 3.4 will be awesome and newer versions of Django support Python 3.x.

Make POST request using Python

I am trying to make a POST request But getting this error :
Traceback (most recent call last):
File "demo.py", line 7, in <module>
r = requests.post(url, data=payload, headers=headers)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 87, in post
return request('post', url, data=data, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 44, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 266, in request
prep = req.prepare()
File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 215, in prepare
p.prepare_body(self.data, self.files)
File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 338, in prepare_body
body = self._encode_params(data)
File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 74, in _encode_params
for k, vs in to_key_val_list(data):
ValueError: too many values to unpack
This is my program :
import requests
url = 'http://www.n-gal.com/index.php?route=openstock/openstock/optionStatus'
payload = {'var:1945,product_id:1126'}
headers = {'content-type': 'application/x-www-form-urlencoded'}
r = requests.post(url, data=payload, headers=headers)
I have tried the same POST request through Advanced rest client using following data :
URL : http://www.n-gal.com/index.php?route=openstock/openstock/optionStatus
payload : var=1945&product_id=1126
Content-Type: application/x-www-form-urlencoded
And it is working fine can anyone help me please...
You have made payload a set, not a dictionary. You forgot to close the string.
Change:
payload = {'var:1945,product_id:1126'}
To:
payload = {'var':'1945','product_id':'1126'}
As it is a set, the request will thus fail.
Try this :
import requests
url = 'http://www.n-gal.com/index.php?route=openstock/openstock/optionStatus'
payload = 'var=1945&product_id=1126'
headers = {'content-type': 'application/x-www-form-urlencoded'}
r = requests.post(url, data=payload, headers=headers)
print r.json()
import requests
import json
url = 'http://www.n-gal.com/index.php?route=openstock/openstock/optionStatus'
payload = {'var:1945,product_id:1126'}
headers = {'content-type': 'application/x-www-form-urlencoded'}
r = requests.post(url, data=json.dumps(payload), headers=headers)
I know this is a really old question, but I had the same problem when using Docker recently, and managed to solve it by including the requests library in the requirements (or just update the library with pip install requests --upgrade).
When using the original version of the requests library, it raised that very same error on Python3.8, which only stopped after upgrading it.

Categories