How to get Python dictionary via Flask request files attribute [duplicate] - python

This question already has answers here:
Read file data without saving it in Flask
(8 answers)
Opening a file that has been uploaded in Flask
(2 answers)
Closed 4 years ago.
With server.py running:
from flask import Flask, request, Response
app = Flask(__name__)
#app.route('/test', methods=['GET','POST'])
def route():
print('got files: %s' % request.files)
return Response()
if __name__ == '__main__':
app.run('0.0.0.0', 5000)
send a request using client.py:
import json, requests
dictionary_1 = {"file": {"url": "https://bootstrap.pypa.io/get-pip.py"}}
files = [('dictionary_1', ('get-pip.py', json.dumps(dictionary_1), 'application/json'))]
response = requests.post('http://127.0.0.1:5000/test', files=files)
Server logs that it received a request:
got files: ImmutableMultiDict([('dictionary_1', <FileStorage: u'get-pip.py' ('application/json')>)])
Apparently, the dictionary_1 was received as FileStorage object.
How to turn the received FileStorage into the Python dictionary?
edited later
The possible duplicate post does not clarify how to send and unpack the Python dictionary object sent via requests(files=list())

This is happening because you're posting files instead of data. This should work:
import flask
app = flask.Flask(__name__)
#app.route('/test', methods=['GET','POST'])
def route():
print('got data: {}'.format(flask.request.json))
return Response()
if __name__ == '__main__':
app.run('0.0.0.0', 5000)
and then send data to your app by
import requests
dictionary_1 = {"file": {"url": "https://bootstrap.pypa.io/get-pip.py"}}
response = requests.post('http://127.0.0.1:5000/test', json=dictionary_1)
In your example there's no need to post the file unless I'm misunderstanding something

Solution # 1:
from flask import Flask, request, Response
import StringIO, json
app = Flask(__name__)
#app.route('/test', methods=['GET','POST'])
def route():
print('got files: %s' % request.files)
for key, file_storage in request.files.items():
string_io = StringIO.StringIO()
file_storage.save(string_io)
data = json.loads(string_io.getvalue())
print('data: %s type: %s' % (data, type(data)) )
return Response()
if __name__ == '__main__':
app.run('0.0.0.0', 5000)
Solution # 2:
from flask import Flask, request, Response
import tempfile, json, os, time
app = Flask(__name__)
#app.route('/test', methods=['GET','POST'])
def route():
print('got files: %s' % request.files)
for key, _file in request.files.items():
tmp_filepath = os.path.join(tempfile.mktemp(), str(time.time()))
if not os.path.exists(os.path.dirname(tmp_filepath)):
os.makedirs(os.path.dirname(tmp_filepath))
_file.save(tmp_filepath)
with open(tmp_filepath) as f:
json_data = json.loads(f.read())
print type(json_data), json_data
return Response(json_data)
if __name__ == '__main__':
app.run('0.0.0.0', 5000)

Related

Flask issue with python: The browser (or proxy) sent a request that this server could not understand

New to Flask and API development, but I'm trying to figure out what's wrong here.
This is my code in my koho-flask.py
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
import new_model_zero_shot as model
app = Flask(__name__)
api = Api(app)
#create new user_palette object
user = model.user_palette(model.cold_start(), 1)
dish_list = model.dish_list
#user.recommend_meal(['chicken', 'rice'], query_type = ['our_dbs', dish_list], name_csv = None)
# argument parsing
parser = reqparse.RequestParser()
parser.add_argument('query')
# we already have a way to package the output to user
class GetRecipes(Resource):
def get(self):
# use parser and find the user's query
args = parser.parse_args()
user_query = args['query']
recs = (user.recommend_meal(user_query,
query_type = ['our_dbs', dish_list], name_csv = None))
return recs
class Hello(Resource):
def get(self):
return {'data': "Hello wassup!"}
#recipe search endpoint
api.add_resource(GetRecipes, '/')
api.add_resource(Hello, '/')
#%%
if __name__ == '__main__':
app.run(debug=False)
When I run app.run(debug=False), the server starts.
After, I open a test.py file in the same directory and run this.
import requests
url = 'http://127.0.0.1:5000/'
params ={'query': 'chicken'}
response = requests.get(url, params)
a = response.json()
My "a" variable returns a dictionary with the value "The browser (or proxy) sent a request that this server could not understand". This happens whether I test out my dummy "Hello" endpoint or my real "GetRecipes" endpoint.
What am I doing incorrectly?

Shopify Webhook HMAC Validation With Flask

I'm trying to verify that the Webhook received is coming from Shopify. They have this doc, but it doesn't work (getting type errors).
Here's what I have so far. It produces no errors, but the verify_webhook function always returns false.
from flask import Flask, request, abort
import hmac
import hashlib
import base64
app = Flask(__name__)
SECRET = '...'
def verify_webhook(data, hmac_header):
digest = hmac.new(SECRET.encode('utf-8'), data, hashlib.sha256).digest()
genHmac = base64.b64encode(digest)
return hmac.compare_digest(genHmac, hmac_header.encode('utf-8'))
#app.route('/', methods=['POST'])
def hello_world(request):
print('Received Webhook...')
data = request.get_data()
hmac_header = request.headers.get('X-Shopify-Hmac-SHA256')
verified = verify_webhook(data, hmac_header)
if not verified:
return 'Integrity of request compromised...', 401
print('Verified request...')
if __name__ == '__main__':
app.run()
What am I doing wrong?
Answer:
from flask import Flask, request, abort
import hmac
import hashlib
import base64
app = Flask(__name__)
SECRET = '...'
def verify_webhook(data, hmac_header):
digest = hmac.new(SECRET.encode('utf-8'), data, hashlib.sha256).digest()
genHmac = base64.b64encode(digest)
return hmac.compare_digest(genHmac, hmac_header.encode('utf-8'))
#app.route('/', methods=['POST'])
def hello_world(request):
print('Received Webhook...')
data = request.data # NOT request.get_data() !!!!!
hmac_header = request.headers.get('X-Shopify-Hmac-SHA256')
verified = verify_webhook(data, hmac_header)
if not verified:
return 'Integrity of request compromised...', 401
print('Verified request...')
if __name__ == '__main__':
app.run()
Issue was in the data = request.get_data() line.

Using Flask to reproduce an audio using json

i'm trying to make an app in flask-python that using a json post send an audio using the gtts google library as the answer, but my method doesn't work. My code is the following.
from gtts import gTTS
from flask import Flask, send_file, request
app = Flask(__name__)
#app.route("/")
def t2s():
text = request.get_json()
obj = gTTS(text = text, slow = False, lang = 'en')
obj.save('audio.wav')
return send_file('audio.wav')
if __name__ == "__main__":
app.run(port=3000 , debug=True, use_reloader=True, host='0.0.0.0')
any suggestions?, i'm using postman.
Thanks a lot for the possible help
Flask as default doesn't get POST requests and you have to use methods=['POST', 'GET']
from gtts import gTTS
from flask import Flask, send_file, request
app = Flask(__name__)
#app.route("/", methods=['POST', 'GET'])
def t2s():
text = request.get_json()
print(text)
obj = gTTS(text = text, slow = False, lang = 'en')
obj.save('audio.wav')
return send_file('audio.wav')
if __name__ == "__main__":
app.run(host='0.0.0.0', port=3000)
And test (using mplayer on Linux):
import requests
import os
data = 'Hello World'
r = requests.post('http://127.0.0.1:3000/', json=data)
open('output.wav', 'wb').write(r.content)
os.system('mplayer output.wav')

Update json file by curl command

I'm trying to make an app which writes and make updates in a json file by accepting data from the curl utility. Right now my code looks like:
import os
import flask import Flask, url_for, json, request, jsonify
database = "./meeting_rooms.json"
#app.route('/book_room', methods = ['POST'])
def api_book_room():
if request.headers['Content-Type'] == 'application/json':
if os.stat(database).st_size == 0:
with open(database, 'w') as f:
data = request.get_json()
json.dump (data, f, indent=4)
return "OK\n", 200
else:
with open(database,'r+') as f:
data = json.load(f)
data.update(request.get_json())
json.dump(data, f, indent=4)
return "OK\n", 200
curl usage:
curl -H "Content-type: application/json" -X POST http://127.0.0.1:5000/book_room -d '{"4":{"room":"602","date":"2 days ago","booked_by":"HR"}} '
But all I got is
json.decoder.JSONDecodeError: Expecting value: line 2 column 1 (char 1)**. json file is empty.
What I'm doing wrong considering I have no real-world python experience?
A solution that catch error at json decode time. it check file existence and file typo.
import os
from flask import Flask, url_for, json, request, jsonify
from path import Path
app = Flask(__name__)
database = "./meeting_rooms.json"
#app.route('/book_room', methods = ['POST'])
def api_book_room():
if request.headers['Content-Type'] == 'application/json':
try:
tmp = json.load(open(database, 'r'))
except (ValueError, FileNotFoundError):
# FileNotFoundError: raised if file don't exist
# ValueError: raised if json is not able to decode
tmp = {}
for k, v in request.get_json().items():
tmp[k] = v
with open(database,'w') as f:
json.dump(tmp, f, indent=4)
return "OK\n", 200
return "FAIL\n", 200
app.run(host='0.0.0.0', port=8080, debug=True)
Edit: Update keys instead of append it.

Python Flask: Send file and variable

I have two servers where one is trying to get a file from the other. I am using Flask get requests to send simple data back and forth (strings, lists, JSON objects, etc.).
I also know how to send just a file, but I need to send an error code with my data.
I'm using something along the following lines:
Server 1:
req = requests.post('https://www.otherserver.com/_download_file', data = {'filename':filename})
Server 2:
#app.route('/_download_file', methods = ['POST'])
def download_file():
filename = requests.form.get('filename')
file_data = codecs.open(filename, 'rb').read()
return file_data
Server 1:
with codecs.open('new_file.xyz', 'w') as f:
f.write(req.content)
...all of which works fine. However, I want to send an error code variable along with file_data so that Server 1 knows the status (and not the HTTP status, but an internal status code).
Any help is appreciated.
One solution that comes to my mind is to use a custom HTTP header.
Here is an example server and client implementation.
Of course, you are free to change the name and the value of the custom header as you need.
server
from flask import Flask, send_from_directory
app = Flask(__name__)
#app.route('/', methods=['POST'])
def index():
response = send_from_directory(directory='your-directory', filename='your-file-name')
response.headers['my-custom-header'] = 'my-custom-status-0'
return response
if __name__ == '__main__':
app.run(debug=True)
client
import requests
r = requests.post(url)
status = r.headers['my-custom-header']
# do what you want with status
UPDATE
Here is another version of the server based on your implementation
import codecs
from flask import Flask, request, make_response
app = Flask(__name__)
#app.route('/', methods=['POST'])
def index():
filename = request.form.get('filename')
file_data = codecs.open(filename, 'rb').read()
response = make_response()
response.headers['my-custom-header'] = 'my-custom-status-0'
response.data = file_data
return response
if __name__ == '__main__':
app.run(debug=True)

Categories

Resources