How to configure flask uploads properly to upload files - python

I'm trying to build a flask app where I can upload a JSON file. I followed the official flask tutorials; this is my code:
import os
from flask import Flask, flash, request, render_template, url_for
from flask_restful import Resource, Api
from flask_uploads import UploadSet, configure_uploads, DATA
app = Flask(__name__)
app.config['UPLOADED_FILES_DEST'] = os.getcwd()
file = UploadSet('SecretKey', DATA)
configure_uploads(app, file)
#app.route('/')
def my_form():
return render_template('upload.html')
#app.route('/checkUpload', methods=['POST'])
def my_form_post():
if request.method == 'POST' and 'file' in request.files:
keyFile = file.save( request.files['keyfile'] )
# ...
My directory structure looks like this:
folder - >
app.py
templates - > uploads.html
When I run the application , I get this error:
RuntimeError: no destination for set SecretKey
I understand that I need to set a destination to the file that's being uploaded,
but I can't figure out how to properly do that; I can't understand why the way I'm currently setting the destination directory is wrong. Ideally, I don't want to store this file anywhere, I just want to take this file, check some credentials from it and then start a session if the credentials are valid. Any help is much appreciated. Thank you for your time in advance.
P.S: Please ignore the spacing of the code , and I've also looked into some other SO questions related to these:
1) Flask Upload Issue
2) Flask Upload Issue
but they didn't exactly had the same issue as I did, so I'm creating a new thread.

You didn't set destination to UploadSet. flask_uploads doesn't know where to store a files. Just set destination:
file = UploadSet('SecretKey', DATA, default_dest=lambda x: 'SecretKey')
Hope this helps.

Related

'502 Bad Gateway nginx' error for browsing Flask app in GCP

I have this problem on my Google App Engine app. When I run the app with gcloud app browse the page gives me the following error message:
'502 Bad Gateway
nginx'
I am using a Flask application.
Here is the code:
import os
from flask_uploads import UploadSet, configure_uploads, IMAGES, patch_request_class
from uuid import uuid4
from flask import Flask, request, render_template, send_from_directory
import io
from google.cloud import vision
from google.cloud.vision import types
app = Flask(__name__)
app.config['UPLOADED_PHOTOS_DEST'] = os.getcwd()
photos = UploadSet('photos', IMAGES)
configure_uploads(app, photos)
patch_request_class(app)
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
os.environ["GOOGLE_APPLICATION_CREDENTIALS"]="json_key.txt"
vision_client = vision.ImageAnnotatorClient()
#app.route('/', methods=['GET', 'POST'])
def upload_file():
labels = ''
file_url1 = ''
filename = ''
file_url = ''
target = os.path.join(APP_ROOT, '/')
if request.method == 'POST' and 'photo' in request.files:
filename = photos.save(request.files['photo'])
file_url = photos.url(filename)
with io.open(filename, 'rb') as image_file:
content = image_file.read()
image = types.Image(content=content)
response = vision_client.label_detection(image=image)
labels = response.label_annotations
return render_template('index.html', thelabels=labels,image_name=file_url)
"""#app.route('/<filename>')
def send_image(filename):
#return render_template('index.html', filename=filename)
return send_from_directory("/", filename)"""
if __name__ == '__main__':
app.run()
This is the app.yaml file:
runtime: python37
And I am not using a requirements.txt file !?
To deploy an App Engine Application you need at least 3 minimum files.
App.yaml file with the desired configuration of your setup
Main.py with your actual code
Requirements.txt in order to import the required libraries
As an alternative you can include the libraries files with your files when you are deploying your App engine Application but this isn't a recommended approach since you will have longer deployment times and longer start up time when you application is scaling.
Here you can see an example of your desired requirements.txt
uwsgi==2.0.18
flask==1.1.1
google-cloud==0.34.0
google-cloud-vision==0.39.0
uuid==1.30.0
Flask-Uploads==0.2.1
You can also get your required files running the command pip freeze > requirements.txt but keep in mind that you should run this command ONLY inside of a test virtual environment because if you do a pip freeze in your working environment you will get a really long list with many unneeded dependencies that will slow a lot your app deployment

Python flask URL mapping issue, returning 404

-->project
--->run.py
--->config.py
--->readme.md
--->app
--->__init__.py
--->controllers
--->__init__.py
--->test_controller.py
--->model
--->__init__.py
--->test_model1.py
--->test_model2.py
run.py
from app import app
app.run(host = '0.0.0.0', port = 8080, debug = True)
config.py - All configuration variable
app/__init__.py
from flask import Flask
app = Flask(__name__)
controllers/__init__.py - Empty
controllers/test_controller.py
#app.route('/test', methods=['POST'])
def test():
return "Hello world"
When I start my server form run.py the server gets started.
But when I try the URL http://locahost:8080/test, it returns 404.
But if the route is configured in app/___init__.py it is working.
Can anyone please guide me what is incorrect here in configuration.
I want to keep the above structure, please let me know of any issues.
Unless you import the file containing the #app.route decorator, it won't be registered. Flask won't import and register all .py files automagically for you.
At the end of your __init__.py file in app/, import projectname.controllers, and import test_controller in the __init__.py file in the controllers module.

Python/Flask Rest API not passing preflight w/CORS

I am trying to get the simplest rest api up that I can in python and I am having trouble. I'm not sure what I am doing wrong, but I think it has something to do with CORS. This is frustrating, as I have used the flask_cors package in order to fix this and it does not appear to work.
In my main.py file i have the following
from flask import Flask
from flask_cors import CORS, cross_origin
app = Flask(__name__)
CORS(app)
import routes.login
if __name__ == '__main__':
app.run(debug=True)
For my project I have this as my folder structure:
main.py
__init__.py
routes
__init__.py
login.py
And i have the following code in login.py
from flask import Flask
from flask_cors import CORS, cross_origin
from main import app
CORS(app)
#app.route('/login', methods=['POST', 'GET'])
#cross_origin()
def login(name, password):
if request.method == 'POST':
print('inside login POST')
if request.method == 'GET':
print('inside login GET')
I'm currently getting this error:
xhr.js:178 OPTIONS http://localhost:5000/login 404 (NOT FOUND)
dispatchXhrRequest # xhr.js:178
xhrAdapter # xhr.js:12
dispatchRequest # dispatchRequest.js:52
:3000/pictureswapper:1 XMLHttpRequest cannot load http://localhost:5000/login.
Response for preflight has invalid HTTP status code 404
There is some sort of CORS error, but I really don't know what's going wrong. Any ideas?
EDIT: The only place in the documentation that has anything to say about preflight is here (https://flask-cors.readthedocs.io/en/v1.3.1/index.html?highlight=preflight). If I add
#cross_origin(headers=['Content-Type']) # Send Access-Control-Allow-Headers
It doesn't break the application, but neither does it fix the error.
Revisiting this after a few months.
One of the nasty gotchas in python/flask appears to be that the compiled code will get cached, so if you change something at the entrypoint of the app (ie main.py), and don't delete the binaries that flask export creates then every time you run flask export and recompile it may be using old code!
Make sure to delete (in atom they are the purple 1/0 files -if you have file icons enabled- labeled .pyc) these files if you are getting spooky output.
Add OPTIONS to the methods keyword of your route decorator, or remove that keyword altogether.

Flask access request data when uploading file with angular

I'm uploading a file using angular and try to access the uploaded file in flask.
This is no problem and works fine. However, when I add more request parameters I cannot seem to find them in the flask request object.
For example, uploading a file using ngFileUpload (https://github.com/danialfarid/ng-file-upload) I can specify more meta-information like this:
$scope.upload = function (file) {
Upload.upload({
url: '/api/upload',
data: {file: file, 'username': $scope.username}
})
};
where username is extra meta-information.
Here's the flask code (using Flask-Restful):
from flask import Flask, request, Response
from flask.ext.restful import Api, Resource
ALLOWED_EXTENSIONS = {'csv'}
def allowed_file(fn):
return '.' in fn and fn.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
app = Flask(__name__)
api = Api(app)
class Upload(Resource):
def post():
file = request.files['file']
fn = file.filename
if file and allowed_file(fn):
try:
# code for saving file
return Response(status=200)
except:
return Response(status=500)
return Response(status=500)
api.add_resource(Upload, '/api/upload')
In flask I can access the file through request.files['file'], but the username information/variable is nowhere to be found.
Is this not possible in flask, am I missing something, or what's going on here?
I actually think #ciacicode was right to ask you about your python code.
You are probably running into a CORS violation with Angular calling Python.
Add an import
See Flask-CORS: http://flask-cors.corydolphin.com/en/latest/index.html
from flask.ext.cors import CORS
Add CORS to your app
Simple addition to your code:
app = Flask(__name__)
cors = CORS(app)
api = Api(app)
Adding CORS made your code sample run for me.
If the CORS is not doing anything for you, then use request.values['username']

REST service by Flasks servers different images from different paths for each url request?

I am trying to implement very basic REST service on Flask. I hve differnt images in my computer located at different file paths and I like to show them to client for each different url address. For instance;
www.bla.com/get_image_A # returns image_A.png from path/to/file1
www.bla.com/get_image_B # returns image_B.png from path2/to/file2
Antoher concern is to hide full path from the client so if the image at completely another location then the flask root then I dont want to show my full path to file against possible hacker guys.
Is it possible to implement it in Flask?
I tried to do like this
from flask import Flask, render_template, send_from_directory, request, redirect, url_for
app = Flask(__name__)
app.config['IMAGES_1_STATIC_PATH'] = '/Common/path/to/some/images'
#app.route('/<path:filename>')
def ml_reports_path(filename):
return send_from_directory(app.config['IMAGES_1_STATIC_PATH'] , filename)
#app.route('/get_some_images')
def tff_predictions():
return render_template('get_some_images.html')
if __name__ == '__main__':
app.run(debug=True, port=4999, host='0.0.0.0')
get_seom_images.html
<img src="{{ url_for('ml_reports_path', filename = 'image1.png') }}">
This does not work and the file path is show /image1.png at browser.

Categories