Uploading an image from python client to a flask server - python

I am using requests and requests_toolbelt to send an image to the cloud and so far I have something like this
import requests
import json
from requests_toolbelt import MultipartEncoder
m = MultipartEncoder(
fields={"user_name":"tom", "password":"tom", "method":"login",
"location":"landing", "cam_id":"c00001", "datetime":"hammaTime!"
,'image': ('filename', open('image.jpg', 'rb'))}
)
r = requests.post(url, data=m)
print r.text
After it gets to the server, how to I get back a dictionary of something usable? The toolbelt docs show only how to post, not how to handle it on the other end. Any advice?

You can see a working example of Flask server which accepts POSTS like the on you're trying to make on HTTPbin. If you do something like:
m = MultipartEncoder(fields=your_fields)
r = requests.post('https://httpbin.org/post', data=m, headers={'Content-Type': m.content_type})
print(r.json()['form'])
You'll see that everything in your post should be in that dictionary.
Using HTTPBin's source, you can then see that the form section is generated from request.form. You can use that to retrieve the rest of your data. Then you can use request.files to access the image you wish to upload.
The example Flask route handler would look like:
#app.route('/upload', methods=['POST'])
def upload_files():
resp = flask.make_response()
if authenticate_user(request.form):
request.files['image'].save('path/to/file.jpg')
resp.status_code = 204
else:
resp.status_code = 411
return resp
You should read into Uploading Files documentation though. It is really invaluable when using common patterns like this in Flask.

requests-toolbelt can only send the file to the server but it is up to you to save that on the server side and then return meaningful result. You can create a flask endpoint to handle the file upload, return the desired result dictionary as a JSON and then convert the JSON back to dict on the client side with json.loads.
#app.route('/upload', methods=['POST'])
def upload_file():
if request.method == 'POST':
f = request.files['image']
f.save('uploads/uploaded_file')
# do other stuff with values in request.form
# and return desired output in JSON format
return jsonify({'success': True})
See flask documentation for more info on file uploading.
Also, you need to specify the mime-type while including the image in MultipartEncoder and content-type in the header while making the request. (I'm not sure you if you can even upload images with MultipartEncoder. I was successful with only the text files.)
m = MultipartEncoder(
fields={"user_name":"tom", "password":"tom", "method":"login",
"location":"landing", "cam_id":"c00001", "datetime":"hammaTime!"
,'image': ('filename', open('file.txt', 'rb'), 'text/plain')} # added mime-type here
)
r = requests.post(url, data=m, headers={'Content-Type': m.content_type}) # added content-type header here

Related

POST method adds a header to an xlsx file which corrupts it

I'm trying to send an xlsx file using Python requests library. My request looks like this:
import requests
url_attachment = "http://127.0.0.1:5000/api/attachment"
payload={}
files=[('file',(filename, open(filename,'rb'),'application/octet-stream'))
]
headers = {}
requests.request("POST", url_attachment, headers=headers, data=payload, files=files)
and my mock server looks like this:
import flask
from flask import request
app = flask.Flask(__name__)
app.config["DEBUG"] = True
#app.route('/', methods=['GET'])
def home():
return "<h1>Hello World</h1>"
#app.route('/api/attachment', methods=['POST'])
def get_file():
data = request.files['file']
data.save('the-file.xlsx')
return "ok"
app.run()
The mock server works fine, and the file gets sent correctly.
However, when I call the actual API (that I have no access to), the file gets corrupted. The person who owns the API sent me the corrupted file, and after inspection I can see that the content got wrapped in this:
-------------------------------28947758029299
Content-Disposition: form-data; name="the-file.xlsx"; filename="the-file.xlsx"
Content-Type: application/octet-stream
//content
-------------------------------28947758029299--
Does someone have an idea why this is happening? What can I change in my function to stop this from happening? I have also tried changing the Content-Type to application/vnd.openxmlformatsofficedocument.spreadsheetml.sheet but apparently this results in the same problem.
This has been resolved now. If anyone comes across a similar issue in the future, the cause was the receiving method in the API considering content as 'multi-part form data'.

Telegram Bot SendDocument pdf

I am having a real headache with the way of sending a pdf file to a Telegram Bot.
Apparently I am following the documentation but never get it sent.
I am using the url: https://api.telegram.org/botBOTID/sendDocument?chat_id=CHATID&document=/home/lix/Downloads/2.pdf
It is a pdf file storaged locally, but I think it is just the way I am presenting it.
The error getting is:
{"ok":false,"error_code":400,"description":"Bad Request: URL host is empty"}
Does anybody knows how to send a pdf local file?
Many thanks
You should send a POST request, with the PDF as a payload, using the Python Requests library, your code should look something like this:
import requests
# Url with bot token + user id
url = "https://api.telegram.org/bot<MY-BOT-TOKEN>/sendDocument?chat_id=<MY_CHAT_ID>"
# Create payload with PDF file
payload = {}
files = [
('document', open('/home/lix/Downloads/2.pdf','rb'))
]
headers= {}
# Request
response = requests.request("POST", url, headers=headers, data = payload, files = files)
# Log reponse as UTF-8
print(response.text.encode('utf8'))

How do I send an attachment through REST response using Python Flask

I'm building a REST API, and it has to send a file in the response. I do not want to include the file content in the response body. Can we attach files to response ?
If I understood you right, you want to send a file with Content-Disposition header set to 'attachment'. Which instructs the browser to download/save the file, instead of displaying its contents inline on the page.
If that's what you want, then you'll have to do something like this:
from flask import make_response
#app.route('/txt')
def attachment():
resp = make_response('my text file')
resp.headers['Content-Type'] = 'text/plain;charset=UTF-8'
resp.headers['Content-Disposition'] = 'attachment;filename=SmartFileName.txt'
return resp

Serve an ical feed with Flask

I've got a small flask website, and I want to serve an ical feed from it.
I've already created an ics-file, which gets frequently updated, however I can't figure out how to serve it from the website.
I've tried doing it through Response and serve_file, but they just display the text in the file.
You need to set the the correct content disposition header of the response. In your case the header would be something like the following:
Content-Disposition: attachment; filename=calender.ics;
In your Flask route your code should look something like the following:
from flask import make_response
app = Flask(__name__)
# ...
#app.route('/calendar/')
def calendar():
# Get the calendar data
_calendar = make_calendar()
# turn calendar data into a response
response = make_response(_calendar)
response.headers["Content-Disposition"] = "attachment; filename=calendar.ics"
return response

Send an image with flask by using urllib2

I'm new to Flask and I want to send an image to a client that was previously received from a external server with urllib2. Here is my example code for sending the google logo to the client:
import urllib2
from flask import Flask, send_file
app = Flask(__name__)
#app.route('/getTestImage')
def getTestImage():
url = "https://www.google.de/images/srpr/logo11w.png"
response = urllib2.urlopen(url)
img = response.read()
response.close()
return img
if __name__ == '__main__':
app.run()
When I open 127.0.0.1:5000/getTestImage with a browser ( e.g. Firefox) I just get binary code. How do I send the png file so that the browser display the image? I found send_file from Flask but I don't realy know how to use the function with the received image data from urllib2.
Edit: I figured it out. Simply return Response(img, mimetype="image/png").
You see binary data because you're returning the image data directly. Flask wraps text returned from a view in its default Response object, which sets the mimetype to text/plain. Since you're not returning plain text data, you need to create a response that describes the correct mimetype.
return app.response_class(img, mimetype='image/png')

Categories

Resources