How to send GET/POST request on a flask based local website? - python

I have a website which takes a .txt file as input through an upload button. The backend model processes this text file and output a new .txt file. My website is working perfectly with the UI. But I was trying to send GET/POST request to my file using the curl command:
curl -F 'file=#CNN.txt' http://127.0.0.1:5000/
The output was that my whole html file got printed (as a cat command does) in the terminal.
I want to know how can I get the processed file using the curl command itself? I think to get the file, I need to return some kind of JSON object too. I am completely new to this stuff. Please bare with me.. My appy.py file is:
#app.route('/', methods = ['GET','POST'])
def hello():
if(request.method == 'POST'):
if('file' not in request.files):
return 'NO FILE'
file = request.files['file']
if(file.filename == ''):
print('NO FILES')
return redirect(request.url)
if(file and allowed_file(file.filename)):
uploadedFile = file.filename
file.save(os.path.join(UPLOAD_FOLDER, file.filename))
if(uploadedFile != ''):
neural_code_sum.starter(uploadedFile)
return render_template('index.html', message='success')
return render_template('index.html', message='NOT UPLOADED (ONLY .TXT FILES ALLOWED)')
#app.route('/download')
def download_file():
global uploadedFile
doc = os.path.dirname(os.path.realpath(__file__))+'/output.txt'
return send_file(doc,as_attachment=True,cache_timeout=0)

Just add GET above:
#app.route('/download', methods = ['GET'])
def download_file():
global uploadedFile
doc = os.path.dirname(os.path.realpath(__file__))+'/output.txt'
return send_file(doc,as_attachment=True,cache_timeout=0)
The first send the file: curl -F 'file=#CNN.txt' http://127.0.0.1:5000/
Then download it: curl http://127.0.0.1:5000/download -o output.txt
That's it! All the best.

#app.route('/download',methods=['**GET'**])
def download_file():
global uploadedFile
doc = os.path.dirname(os.path.realpath(__file__))+'/output.txt'
return send_file(doc,as_attachment=True,cache_timeout=0)
Add the method by which you want to send the request in the methods field.

Related

Send update messages to HTML mid process in Python Flask

I have a python project in PythonAnywhere where the user uploads a file, it gets processed, and then it gets downloaded again by the user.
The file gets processed using a RandomForestRegressor model.
So far, it works perfectly. The user uploads and a new output file is generated. What I want to do is that the results of the model be returned in the website.
A message like this:
Accuracy of model on test set: 0.90
mse of model on train set: 0.08
The HTML is like this:
<html>
<body>
{% for comment in comments %}
<div class="row">
{{ comment }}
</div>
{% endfor %}
</body>
</html>
I was trying to add a comment after the proccess_data function is called. I added the render_template with the comment variable but it doesnt work. I even added it at the end of the def index() as a return but it just doesnt work.
output_file = process_data(filename)
comments = 'File processed succesfully'
render_template("main_page.html", comments=comments)
The python script is like this:
comments = []
#app.route('/', methods=["GET","POST"])
def index():
if request.method == "GET":
return render_template("main_page.html")
if request.method == 'POST':
#comments.append(request.form["contents"])
#check if the post request has the file part
if 'input_file' not in request.files:
#TODO
return redirect(request.url)
file = request.files['input_file']
#if the user does not select a file, the browser submits
#empty file without a filename
if file.filename == '':
#TODO
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
output_file = process_data(filename)
comments = 'File processed succesfully'
render_template("main_page.html", comments=comments)
si = io.StringIO()
output_file.to_csv(si,index=False, encoding='UTF8')
#-----Save dataframe to folder-----
filepath = os.path.join(app.config['UPLOAD_FOLDER'], 'results.csv')
output_file.to_csv(filepath)
response = make_response(si.getvalue())
response.headers["Content-Disposition"] = "attachment; filename=results.csv"
response.headers["Content-type"] = "text/csv"
return response
return
I don't work with python but I see you basically want to send two responses in one request and most likely at different times?
HTTP does not work like that. You can't send one response "mid process" and then some other after a while. It's always one request - one response. And a new tcp connection opens and closes immediately each time.
So if you want to notify user about the results of backend process some time before you actually send him the "final data", you have these options:
Divide this flow into multiple individual requests.
Use WebSockets.

Using flask to run a python script

I have a script called output.py
This script takes in 2 inputs, fileA and file B.
I can run it on my terminal by using the command output.py -fileA -fileB. The script will create a new JSON file and save it to the directory.
I want to run this script using Flask. I've defined a bare bones App here but I'm not sure how I'd run this using Flask
from flask import Flask
import output
import scripting
app = Flask(__name__)
#app.route('/')
def script():
return output
if __name__ == '__main__':
app.run()
Can someone help me out here, thanks!
It appears you are new to Flask. Get some basic tutorials (there are many on the web).
There are a couple of options:
Send contents of file A and File b as json payload. Pull the A and B content off the json body and do the processing you need to and return the body.
Send the contents of the file as multipart/form-data (you can send multiple files).
Note: This is not working code - just for illustration.
from flask import Flask, request, make_response
app = Flask(__name__)
def build_response(status=False, error="", data={}, total=0, headers=[], contentType="application/json", expose_headers=["X-Total-Count"], retcode=400, additional_data=None):
resp = {"success": status, "error": error, "data": data}
resp = make_response(json.dumps(resp))
for item in headers:
resp.headers[item] = headers[item]
resp.headers['Content-Type'] = contentType
resp.headers.add('Access-Control-Expose-Headers', ','.join(expose_headers))
resp.status_code = retcode
return resp
#app.route('/run-script', methods=['POST'])
def run_script():
# check if the post request has the file part
try:
# Note: THis code is just to illustrate the concept.
# Option-1 (content type must be application/json)
json_dict = request.get_json()
fileA = json_dict["fileA"]
fileB = json_dict["fileB"]
# Option-2 (Note: fileA/fileB are objects, put a pdb and check it out)
fileA = request.files['fileA']
fileB = request.files['fileA']
resp = process(fileA, fileB)
return build_response(status=True, data=resp, retcode=200)
except Exception as e:
msg = f"Error - {str(ec)}"
return build_response(status=False, error=msg, retcode=400)

cloudinary.exceptions.Error: Empty file using Flask

Im using cloudinary for upload file from my flask app.
I followed this basic sample code by pycloudinary for flask : https://github.com/cloudinary/pycloudinary/tree/master/samples/basic
but I still get the same error.
cloudinary.exceptions.Error
cloudinary.exceptions.Error: Empty file
My file post request with multipart-form and key name "image".
Before this, I already successfully upload file to static folder.
What should I do ?
def upload_files():
upload_result = None
file_to_upload = request.files['image']
if file_to_upload:
upload_result = upload(file_to_upload)
return "Success!"
else:
return "Failed!"
Should file_to_upload = request.files['image'] be
file_to_upload = request.files['file']?
request.files is a ImmutableMultiDict() that file is the key and not image.
Best,
Mo

Flask to read and write to same csv

I have a flask app that was created using a csv file. Using html forms, I give the user the option to input new data, and then I write changes to the csv (using a custom function) and download it. This downloads just fine and saves to my desktop. Is there any way to tweak the code to save it in the same project directory and overwrite the csv that serves the flask app? This way the app might update upon refresh. Thanks!
#app.route('/csv/')
def download_csv():
model_id=request.args['textid']
client_id = session['client_id']
# return response
df=recommender.update_history(client_id, model_id)
df= recommender.get_csv()
resp = make_response(df.to_csv(encoding='iso-8859-1',index=False))
resp.headers["Content-Disposition"] = "attachment; filename=export.csv"
resp.headers["Content-Type"] = "text/csv"
return resp
The comment above is correct. I didn't need the make_response function. Here's what worked:
#app.route('/csv/')
def download_csv():
model_id=request.args['textid']
client_id = session['client_id']
# return response
df=recommender.update_history(client_id, model_id)
df= recommender.get_csv()
path=r'data/file_name.csv'
resp = df.to_csv(path, encoding='iso-8859-1',index=False)
return render_template('index.html')

How to test send_file flask

I have a small flask application which takes some images for upload and converts them into a multipage tiff. Nothing special.
But how do I test the upload of multiple files and the file download?
My Testclient:
class RestTestCase(unittest.TestCase):
def setUp(self):
self.dir = os.path.dirname(__file__)
rest = imp.load_source('rest', self.dir + '/../rest.py')
rest.app.config['TESTING'] = True
self.app = rest.app.test_client()
def runTest(self):
with open(self.dir + '/img/img1.jpg', 'rb') as img1:
img1StringIO = StringIO(img1.read())
response = self.app.post('/convert',
content_type='multipart/form-data',
data={'photo': (img1StringIO, 'img1.jpg')},
follow_redirects=True)
assert True
if __name__ == "__main__":
unittest.main()
The application sends back the file with
return send_file(result, mimetype='image/tiff', \
as_attachment=True)
I want to read the file sent in the response and compare it with another file. How do I get the file from the response object?
I think maybe the confusion here is that response is a Response object and not the data downloaded by the post request. This is because an HTTP response has other attributes that are often useful to know, for example http status code returned, the mime-type of the response, etc... The attribute names to access these are listed in the link above.
The response object has an attribute called 'data', so response.data will contain the data downloaded from the server. The docs I linked to indicate that data is soon to be deprecated, and the get_data() method should be used instead, but the testing tutorial still uses data. Test on your own system to see what works.Assuming you want to test a round trip of the data,
def runTest(self):
with open(self.dir + '/img/img1.jpg', 'rb') as img1:
img1StringIO = StringIO(img1.read())
response = self.app.post('/convert',
content_type='multipart/form-data',
data={'photo': (img1StringIO, 'img1.jpg')},
follow_redirects=True)
img1StringIO.seek(0)
assert response.data == imgStringIO.read()

Categories

Resources