How to upload a file using requests in Python - python

I am trying to upload a file via Python requests and i receive an error code 400 (Bad request)
#Update ticket with upload of CSV file
header_upload_file = {
'Authorization': 'TOKEN id="' + token + '"',
'Content-Type': 'multipart/form-data'
}
files = {
'name': 'file',
'filename': open(main_path + '/temp/test.txt', 'rb'),
'Content-Disposition': 'form-data'
}
response = requests.post(baseurl + '/incidents/number/' + ticket_number + '/attachments/', headers=header_upload_file, data=files, verify=certificate)
If i try via Postman this is successfull using following code.
url = "https://<url>"
payload = "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"file\"; filename=\"C:\\Users\\<filename>\"\r\nContent-Type: text/csv\r\n\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--"
headers = {
'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
'Authorization': "TOKEN id="3e9d095d-a47b-48b5-a0b8-ae8b8ad9ae74"",
'cache-control': "no-cache",
'Postman-Token': "bb155176-b1b8-47a6-8fb3-46f5740cf9e0"
}
response = requests.request("POST", url, data=payload, headers=headers)
print(response.text)
What do i wrong?

You should use the files parameter instead. Also, don't explicitly set Content-Type in the header so that requests can set it for you with a proper boundary:
header_upload_file = {
'Authorization': 'TOKEN id="' + token + '"'
}
response = requests.post(
baseurl + '/incidents/number/' + ticket_number + '/attachments/',
headers=header_upload_file,
files={'file': ('file', open(main_path + '/temp/test.txt', 'rb'), 'text/csv')},
verify=certificate
)

Related

Pinterst api: not able to get access token - Stuck in Oauth flow

Using v5 of the pinterest api and stuck on the authentication flow: https://developers.pinterest.com/docs/getting-started/authentication/
Completed the first step and got the access code.
However, I get the below error when I try to use this code to get the access token.
{"code":1,"message":"Missing request body"}
Here is my code:
client_id= 'my_client_id'
client_secret = 'my_client_secret'
data_string = f'{client_id}:{client_secret}'
token = base64.b64encode(data_string.encode())
headers = {
'Authorization': 'Basic ' + token.decode('utf-8'),
'Content-Type': 'application/x-www-form-urlencoded',
}
url = "https://api.pinterest.com/v5/oauth/token"
code = "my_code_that_i_got_in_the_first_step"
params = {
'grant_type':'authorization_code',
'code': code,
'redirect_url':'https://my_redirect_uri'
}
r = requests.post(url, headers=headers, params=params)
print(r.json())
Below is the correct way to get the access token:
client_id= 'my_client_id'
client_secret = 'my_client_secret'
data_string = f'{client_id}:{client_secret}'
token = base64.b64encode(data_string.encode())
headers = {
'Authorization': 'Basic ' + token.decode('utf-8'),
'Content-Type': 'application/x-www-form-urlencoded',
}
url = "https://api.pinterest.com/v5/oauth/token"
code = "my_code_that_i_got_in_the_first_step"
data= {
'grant_type':'authorization_code',
'code': code,
'redirect_uri':'https://my_redirect_uri'
}
r = requests.post(url, headers=headers, data=data)
print(r.json())
In my question, I had mistyped redirect_uri as redirect_url. Also, when sending a POST, you should use data instead of params. See the comment by Amos Baker.

"unsupported_grant_type" when using Google's urlfetch to get an oauth token from PayPal. Using "requests" works

I've been trying (and failing miserably) to use google's urlfetch module (python within app engine's local server) to retrieve a token from paypal. It works as follows using the "requests" module outside of app engine:
url = base + "/v1/oauth2/token"
payload = {
'grant_type': 'client_credentials',
}
auth_encoded = APP_CLIENT_ID + ":" + APP_SECRET
auth_encoded = base64.b64encode(auth_encoded)
##headers = {'Content-Type': 'application/json', 'Authorization': 'Basic ' + auth_encoded}
headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic ' + auth_encoded}
r = requests.post(url,headers=headers,params=payload)
print r.text
... but I get this message when trying the same thing with urlfetch:
{"error":"unsupported_grant_type","error_description":"Grant Type is NULL"}
... here's the code that I'm using:
url = base + "/v1/oauth2/token"
payload = {"grant_type": "client_credentials"}
auth_encoded = APP_CLIENT_ID + ":" + APP_SECRET
auth_encoded = base64.b64encode(auth_encoded)
headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic ' + auth_encoded}
result = urlfetch.fetch(
url=url,
method=urlfetch.POST,
headers=headers,
payload = payload
)
... I've tried everything that I can think of. Should be a simple thing.
This API call is formatted as application/x-www-form-urlencoded , not JSON.
Therefore:
payload = "grant_type=client_credentials"
or
import urllib
payload = urllib.urlencode({"grant_type": "client_credentials"})

POST file in request body to API

I'm trying to upload a file in an API that just says:
REQUEST
The request body should contain the contents of the file.
https://developer.fortnox.se/documentation/resources/inbox/
What I've tried so far:
headers = {
"Access-Token": settings.FORTNOX_ACCESS_TOKEN,
"Client-Secret": settings.FORTNOX_CLIENT_SECRET,
"Content-Type": "multipart/form-data",
"Accept": "application/json",
}
file = open(invoice.file.path, 'rb').read()
r = requests.post("https://api.fortnox.se/3/inbox", data=file, headers=headers)
This gives me an error:
Ingen fil var uppladdad. (No file was uploaded)
headers = {
"Access-Token": settings.FORTNOX_ACCESS_TOKEN,
"Client-Secret": settings.FORTNOX_CLIENT_SECRET,
"Content-Type": "multipart/form-data",
"Accept": "application/json",
}
h = httplib2.Http()
file = open(invoice.file.path, 'rb').read()
resp, content = h.request('https://api.fortnox.se/3/inbox', "POST", body=file, headers=headers)
This gives me the same error:
Ingen fil var uppladdad. (No file was uploaded)
Are there any other ways to add the file to the request body, or am I doing something wrong here?
Thanks for any help.
I finally got it working, based on the answer by mee. This did the trick:
multipart_data = MultipartEncoder(
fields={
'file': (invoice.file.path, open(invoice.file.path, 'rb'), 'text/plain')
}
)
headers = {
"Access-Token": settings.FORTNOX_ACCESS_TOKEN,
"Client-Secret": settings.FORTNOX_CLIENT_SECRET,
"Content-Type": multipart_data.content_type,
"Accept": "application/json",
}
r = requests.post("https://api.fortnox.se/3/inbox", headers=headers, data=multipart_data)
In my case, I was able to upload file from put request like this:
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
def upload_localfile(filepath,server_data):
multipart_data = MultipartEncoder(
fields={
'file': (filepath, open(filepath, 'rb'), 'text/plain')
}
)
response=requests.put(
server_data,
data=multipart_data,
headers={'Content-Type': multipart_data.content_type}
)
You should use this implementation for fortnox:
files = [
('file', ('somename.pdf', data.file -> NamedTemporaryFile in my case))
]
response = requests.post(
url,
headers={"Authorization": f"Bearer {token}",}
data={},
files=files,
)

Patch Request File Upload

I have a REST API that I am trying to upload data to , which is basically this : https://learn.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/update
Now, since the only option I have is PATCH, what are the options for me to have an optimized data load. I have been able to upload files by using the data parameter and using the read() function, but I don't think it's optimal as the entire file is read into memory I guess. I have tried using the files parameter (the multipaprt form encoding) and also looked at the toolbelt package but that does not seem to work for PATCH
This is the Sample Code that works but is not optimal
files={'file':('Sample',open('D:/FilePath/Demo.txt','rb'))}
length=os.stat('D:/FilePath/Demo.txt')
filesize=str(length.st_size)
with open('D:/File|Path/Demo.txt','rb') as f:
file_data = f.read()
leng=len(file_data)
header = {
'Authorization': "Bearer " + auth_t
}
header_append = {
'Content-Length': filesize,
'Authorization': "Bearer " + auth_t
#'If-None-Match': "*" #Conditional HTTP Header
}
header_flush = {
'Content-Length': '0',
'Authorization': "Bearer " + auth_t
}
header_read = {
'Authorization': "Bearer " + auth_t
}
try:
init_put=requests.put('https://adlstorageacc.dfs.core.windows.net/adobe/2019/02/DemoStreamFile4.txt?resource=file&recursive=True', headers=header_flush, proxies=proxies,verify=False)
init_write=requests.patch('https://adlstorageacc.dfs.core.windows.net/adobe/2019/02/DemoStreamFile4.txt?action=append&position=0', headers=header_append, proxies=proxies,verify=False,data=file_data)
flush_url='https://adlstorageacc.dfs.core.windows.net/adobe/2019/02/DemoStreamFile4.txt?action=flush&position=' + str(leng)
init_flush=requests.patch(flush_url, headers=header_flush, proxies=proxies,verify=False)
Problem is the line
init_write=requests.patch('https://adlstorageacc.dfs.core.windows.net/adobe/2019/02/DemoStreamFile4.txt?action=append&position=0', headers=header_append, proxies=proxies,verify=False,data=file_data)
It only seems to take take the data parameter. If I change it to
init_write=requests.patch('https://adlstorageacc.dfs.core.windows.net/adobe/2019/02/DemoStreamFile4.txt?action=append&position=0', headers=header_append, proxies=proxies,verify=False,file=files)
I get an empty file.
Same is the case when I use the requestToolbelt package.
Does patch not recognize the file parameter? Nothing on the requests documents says any of it.
Also, if data parameter is the only way out, what is the best way to loading a file without doing a f.read() or iteratively specifying number of characters to read using f.read(n). Isn't there a better way?
After also looking through Postman, was able to find the problem. Here's the solution. Problem was the with open statement and particularly the position parameter for the flush part, because the Content Length was overridden automatically, so had to get the Content Length from the request of the response.
files={'file':('Sample',open('D:/FilePath/Demo.txt','rb'))}
length=os.stat('D:/FilePath/Demo.txt')
filesize=str(length.st_size)
header = {
# 'Content-Type': 'text/plain',
'Authorization': "Bearer " + auth_t
#'If-None-Match': "*" #Conditional HTTP Header
}
header_append = {
'Content-Length': filesize,
'Authorization': "Bearer " + auth_t
#'If-None-Match': "*" #Conditional HTTP Header
}
header_flush = {
'Content-Type': "application/x-www-form-urlencoded",
'Content-Length': '0',
'Authorization': "Bearer " + auth_t,
#'If-None-Match': "*" #Conditional HTTP Header
}
header_read = {
# 'Content-Type': 'text/plain',
'Authorization': "Bearer " + auth_t,
#'Range': 'bytes=300000-302591'
#'If-None-Match': "*" #Conditional HTTP Header
}
try:
init_put=requests.put('https://adlstorageacc.dfs.core.windows.net/adobe/2019/02/DemoStreamFile4.txt?resource=file&recursive=True', headers=header_flush, proxies=proxies,verify=False)
init_write=requests.patch('https://adlstorageacc.dfs.core.windows.net/adobe/2019/02/DemoStreamFile4.txt?action=append&position=0', headers=header_append, proxies=proxies,verify=False,files=files)
flush_length=init_write.request.headers['Content-Length']
flush_url='https://adlstorageacc.dfs.core.windows.net/adobe/2019/02/DemoStreamFile4.txt?action=flush&position=' + str(flush_length)
init_flush=requests.patch(flush_url, headers=header_flush, proxies=proxies,verify=False)
except Exception as e:
print("In Error")
print(e)

Can upload photo when using the Google Photos API

I am trying to upload a photo (jpg image) using the new Google Photos API.
I am able to get an uploadToken but when I try to create the media item I get the following error:
{
"newMediaItemResults": [
{
"uploadToken": "CAIS+QIAkor2Yr4JcvYMMx..... ",
"status": {
"code": 3,
"message": "NOT_IMAGE: There was an error while trying to create this media item."
}
}
]
}
Here is a snippet of my code:
import sys
import json
import requests
pic = 'image.jpg'
fname = 'read_write_token_creds.json'
with open(fname) as f:
data = json.load(f)
tok = data['access_token']
# Step 1 get an upload token
URL = 'https://photoslibrary.googleapis.com/v1/uploads'
headers = {
'Content-type': 'application/octet-stream',
'X-Goog-Upload-File-Name': pic,
'X-Goog-Upload-Protocol': 'raw',
'Authorization': 'Bearer ' + tok,
}
files = {'file': open(pic, 'rb')}
r = requests.post(URL, headers=headers, files=files)
upload_token = r.text
# Step 2
album_id = 'AG.....7u'
URL = 'https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate'
header = {
'Content-type': 'application/json',
'Authorization': 'Bearer ' + tok
}
payload = {
'albumId': album_id,
'newMediaItems': [
{
'description': 'Desc.',
'simpleMediaItem': { 'uploadToken': upload_token }
}
]
}
r = requests.post(URL, headers=header, data=json.dumps(payload))
When I look at r.text from the requests module, I receive the error message which was given at the top of he message.
This worked for me.
How to authenticate user see here https://developers.google.com/photos/library/guides/upload-media
def upload(service, file):
f = open(file, 'rb').read();
url = 'https://photoslibrary.googleapis.com/v1/uploads'
headers = {
'Authorization': "Bearer " + service._http.request.credentials.access_token,
'Content-Type': 'application/octet-stream',
'X-Goog-Upload-File-Name': file,
'X-Goog-Upload-Protocol': "raw",
}
r = requests.post(url, data=f, headers=headers)
print '\nUpload token: %s' % r.content
return r.content
def createItem(service, upload_token, albumId):
url = 'https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate'
body = {
'newMediaItems' : [
{
"description": "test upload",
"simpleMediaItem": {
"uploadToken": upload_token
}
}
]
}
if albumId is not None:
body['albumId'] = albumId;
bodySerialized = json.dumps(body);
headers = {
'Authorization': "Bearer " + service._http.request.credentials.access_token,
'Content-Type': 'application/json',
}
r = requests.post(url, data=bodySerialized, headers=headers)
print '\nCreate item response: %s' % r.content
return r.content
# authenticate user and build service
upload_token = upload(service, './path_to_image.png')
response = createItem(service, upload_token, album['id'])

Categories

Resources