Python Requests Post - Additional field is not recognized for file upload - python-3.x

I have to post a file using Multipart upload to a company-internal REST service. The endpoint needs the file as property "file" and it needs an additional property "DestinationPath". Here is what I do:
url = r"http://<Internal IP>/upload"
files = {
"DestinationPath": "/some/where/foo.txt",
"file": open("test.txt", "rb")
}
response = requests.post(url, files=files)
The server complains that it can't get the "DestinationPath". Full error message I receive is:
{'errors': {'DestinationPath': ['The DestinationPath field is required.']},
'status': 400,
'title': 'One or more validation errors occurred.',
'traceId': '00-1993fbc53ab2ee418b683915dd7a440a-2338bd9cf34d414a-00',
'type': 'https://tools.ietf.org/html/rfc7231#section-6.5.1'}
The file upload works in curl, thus it must be python specific.

You might want to try using the data argument instead of files.
response = requests.post(url, data=files)

Thanks to #etemple1 I found the solution to my question:
url = r"http://<Internal IP>/upload"
data = {
"DestinationPath": "/some/where/foo.txt",
}
with open("test.txt", "rb") as content:
files = {
"file": content.read(),
}
response = requests.post(url, data=data, files=files)
The data for the multipart upload needed to be divided between "data" and "files". They are later combined in the body of the http post by the requests library.

Related

PYTHON FLASK - request.files displays as file not found eventhough it exits

I am trying to trigger an external api from postman by passing the uploadFile in the body as form-data. Below code throws me an error as 'FileNotFoundError: [Errno 2] No such file or directory:'
Note: In postman, uploadFile takes file from my local desktop as input. have also modified the postman settings to allow access for files apart from working directory
Any help would be highly appreciable.
Below is the Code:
#app.route('/upload', methods=['POST'])
#auth.login_required
def post_upload():
payload = {
'table_name': 'incident', 'table_sys_id': request.form['table_sys_id']
}
files = {'file': (request.files['uploadFile'], open(request.files['uploadFile'].filename,
'rb'),'image/jpg', {'Expires': '0'})}
response = requests.post(url, headers=headers, files=files, data=payload)
return jsonify("Success- Attachment uploaded successfully ", 200)
Below code throws me an error as 'FileNotFoundError: [Errno 2] No such file or directory:
Have you defined UPLOAD_FOLDER ? Please see: https://flask.palletsprojects.com/en/latest/patterns/fileuploads/#a-gentle-introduction
i am passing the attribute (upload file) in body as form-data, can this be passed as raw json
You cannot upload files with JSON. But one hacky way to achieve this is to base64 (useful reference) encode the file before sending it. This way you do not upload the file instead you send the file content encoded in base64 format.
Server side:
import base64
file_content = base64.b64decode(request.data['file_buffer_b64'])
Client side:
-> Javascript:
const response = await axios.post(uri, {file_buffer_b64: window.btoa(file)})
-> Python:
import base64
with open(request.data['uploadFile'], "rb") as myfile:
encoded_string = base64.b64encode(myfile.read())
payload = {"file_buffer_b64": encoded_string}
response = requests.post(url, data=payload)

Using local image for Read 3.0, Azure Cognitive Service, Computer Vision

I am attempting to use a local image in my text recognition script, the documentation has the following example (https://learn.microsoft.com/en-us/azure/cognitive-services/computer-vision/quickstarts/python-hand-text):
But when I change the image_url to a local file path, it sends a HTTPError: 400 Client Error: Bad Request for url. I have tried following other tutorials but nothing seems to work.
Any help would be greatly appreciated :)
The Cognitive services API will not be able to locate an image via the URL of a file on your local machine. Instead you can call the same endpoint with the binary data of your image in the body of the request.
Replace the following lines in the sample Python code
image_url = "https://raw.githubusercontent.com/MicrosoftDocs/azure-docs/master/articles/cognitive-services/Computer-vision/Images/readsample.jpg"
headers = {'Ocp-Apim-Subscription-Key': subscription_key}
data = {'url': image_url}
response = requests.post(
text_recognition_url, headers=headers, json=data)
with
headers = {'Ocp-Apim-Subscription-Key': subscription_key,'Content-Type': 'application/octet-stream'}
with open('YOUR_LOCAL_IMAGE_FILE', 'rb') as f:
data = f.read()
response = requests.post(
text_recognition_url, headers=headers, data=data)
And replace the following line:
image = Image.open(BytesIO(requests.get(image_url).content))
with
image = Image.open('./YOUR_LOCAL_IMAGE_FILE.png')

Django DRF Post with files and data works in Postman, not Python. No TemporaryUploadedFile

Running a Django App locally, i can use Postman to upload a zip file along with some dict data. Breaking the application in 'def Post()' i can see that Postman's successful upload:
request.data = <QueryDict: {'request_id': ['44'], 'status': [' Ready For Review'], 'is_analyzed': ['True'], 'project': ['test value'], 'plate': ['Plate_R0'], 'antigen': ['tuna'], 'experiment_type': ['test'], 'raw_file': [<TemporaryUploadedFile: testfile.zip (application/zip)>]}>
Postman offers the following python code to replicate these results in my python script:
import requests
url = "http://127.0.0.1:8000/api/upload/"
payload = {'request_id': '44',
'status': ' Ready For Review',
'is_analyzed': 'True',
'project': 'test value',
'plate': 'Plate_R0',
'antigen': 'tuna',
'experiment_type': 'test'}
files = [
('raw_file', open(r'C:/testfile.zip','rb'))
]
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
response = requests.request("POST", url, headers=headers, data = payload, files = files)
print(response.text.encode('utf8'))
running this code directly and retrieving the request.data (server side) i see the binary representation of the xlsx file is in the object and the payload data is not there (this is the error in the response).
How do i get my python script to produce the same server-side object as postman? Specifically how do i upload my data such that the file is represented as: <TemporaryUploadedFile: testfile.zip (application/zip)>
Thanks.
Turns out, inspection of the object posted by Postman shows that it was using multipart-form upload. Searching around i found this answer to a related question to describe posting as multi-part: https://stackoverflow.com/a/50595768/2917170 .
The working python is as follows:
from requests_toolbelt import MultipartEncoder
url = "http://127.0.0.1:8000/api/upload/"
zip_file = r'C:/testfile.zip'
m = MultipartEncoder([('raw_file', (os.path.basename(zip_file), open(zip_file, 'rb'))),
('request_id', '44'),
('status', 'Ready For Review'),
('is_analyzed', 'True'),
('project', 'test value'),
('plate', 'Plate_R0'),
('antigen', 'tuna'),
('experiment_type', 'test')])
header = {'content-type': m.content_type}
response = requests.post(url, headers=header, data=m, verify=True)

Looking for approach to post long text to slack through python script

I had written a code in python to fetch the huge set (80 lines) of data from DB, now I would like to post that data in slack through webhook. I tried posting the data directly,but its not working for me, so I decided to save the data in txt/.png file and post it in slack
I tried below code in python after saving my data in report.txt file, but its not helping me
headers = {
'Content-type': 'application/json',
}
data = open('\\results\report.txt')
response = requests.post('https://jjjjjjj.slack.com/services/mywebhook', headers=headers, data=data)
Please share me the Curl command which will fit in python script to post the attachment in slack or please suggest me any better approach to post more than 50 lines for data to slack
I would suggest to upload long text as text file. That way Slack will automatically format it with a preview and users can click on it to see the whole content.
To upload a file you need to use files_upload API method. With it you can also include an initial message with your upload.
Here is an example using the standard Slack library. Here I am reading the data from a file, but you would of course use your data instead:
import slack
import os
# init slack client with access token
slack_token = os.environ['SLACK_TOKEN']
client = slack.WebClient(token=slack_token)
# fetch demo text from file
with open('long.txt', 'r', encoding='utf-8') as f:
text = f.read()
# upload data as file
response = client.files_upload(
content=text,
channels='general',
filename='long.txt',
title='Very long text',
initial_comment='Here is the very long text as requested:'
)
assert response['ok']
The trick is to use content not file to pass the data. If you use file the API will try to load a file from your filesystem.
The below code works fine for me..... :)
headers = { 'Authorization': 'Bearer xxxx-XXXXX-XXXXX', #Bot Token }
files = {
'file': ('LocationOfthefile\report.txt', open('LocationOfthefile\report.txt', 'rb')),
'initial_comment': (None, 'Some Text For Header'),
'channels': (None, 'Channel_Names'),
}
response = requests.post('slack.com/api/files.upload', headers=headers, files=files)

Request too large error making a request to App Engine

I have an app on App Engine Flex using the Python 3 runtime. I get the base64 encoded byte string of a resume file from Google Storage with the code below.
storage_client = storage.Client(project=[MYPROJECT])
bucket = storage_client.get_bucket([MYBUCKET])
blob = bucket.blob([MYKEY])
resume_file = blob.download_as_string()
resume_file = str(base64.b64encode(resume_file))[2:-1]
I send that as part of my request parameters like so:
headers = {'Authorization': 'Bearer {}'.format(signed_jwt),
'content-type': 'application/json'}
params = {'inputtype': 'file',
'resume': resume_file}
response = requests.get(HOST, headers=headers, params=params)
However, I get the following error:
Error 413 (Request Entity Too Large)
Your client issued a request that was too large
That's all we know
App Engine has a file size limit of 32MB. However, my file is only 24KB. How can I fix this error?
I had to change my application to accept POST requests instead of GET requests.
Previously, I was sending the resume as a parameter. I'm now sending it as data:
payload = json.dumps({
'inputtype': inputtype,
'resume': inputresume
})
response = requests.post(HOST, headers=headers, data=payload)
I am using Flask. Previously I was reading in the params using:
request.args.get('resume')
I changed it to:
request.get_json().get('resume')
This is an extension of the question/answer here

Resources