Flask debug=True does not work when going through uWSGI - python

I call app.run(debug=True) in my flask file.
and I have it deployed with uWSGI and nginx (I followed these instructions)
uwsgi -s /tmp/uwsgi.sock -w flask_file_name:app -H /path/to/virtual/env --chmod-socket 666
But when I get an error, I don't get any debug information in the browser or in the uWSGI log.
Any ideas?
flask_file_name.py:
from flask import Flask, make_response, Response, jsonify
import json
app = Flask(__name__)
app.debug = True
#app.route("/")
def hello():
return "Hello World!"
if __name__ == '__main__':
app.run()

This question is old, but I'll post this for future reference...
If you want to get the werkzeug error page to work with uwsgi, try using werkzeug's DebuggedApplication middleware:
from werkzeug.debug import DebuggedApplication
app.wsgi_app = DebuggedApplication(app.wsgi_app, True)
That should do the trick but DO NOT FORGET to do this ONLY in development environments.

According to the Flask mailing list you cannot use Flask's debug option with uWSGI, because it's not to be used in a forking environment.
You see 502 because flask/werkzeug do not send any data to the webserver,
so nginx will returns a 502.
You can emulate the debugger using --catch-exceptions option in uWSGI
(but please do not do it in production)
So, the reason you're seeing 502s will be because of that. The fix would be to add --catch-exceptions to uWSGI on execution.

The problem is uwsgi does not call app.run(). It calls app(). So instead you can do this:
from flask import Flask
app = Flask(__name__)
app.debug = True

For me it only worked after I combined the two answers above like this:
from flask import Flask
app = Flask(__name__)
from werkzeug.debug import DebuggedApplication
app.wsgi_app = DebuggedApplication(app.wsgi_app, True)
app.debug = True

Related

Why SocketIO and SSLify not working together?

I built a very simple flask app that uses socketIo in order to make a simple chatapp, where you can write messages.
In my js file i built a function that every few seconds sends the current location of the user using geolocation.
Because im using the geolocation, i need my to use https instead of http that the flask created.
I found out about SSLify and tried it, but because im using also the socketIo it ran on http and not on https. In apps without socketIo it works, what is the problem?
this is my flask app:
from flask import Flask, render_template
from flask_socketio import SocketIO
from flask_sslify import SSLify
app = Flask(__name__)
app.config['SECRET_KEY'] = 'jsbcfsbfjefebw237u3gdbdc'
socketio = SocketIO(app)
sslify = SSLify(app)
#app.route('/')
def index():
return render_template('./ChatApp.html')
def messageRecived():
print('message was received!!!')
#socketio.on('my event')
def handle_my_custom_event(json):
print('recived my event: ' + str(json))
socketio.emit('my response', json, callback=messageRecived)
if __name__ == '__main__':
socketio.run(app, debug=True, host='0.0.0.0')
The reason it does not work is that Flask-SSLify is applied to your Flask application (the app instance), and not to Socket.IO (the socketio instance).
To my knowledge there is no equivalent to Flask-SSLify for the Socket.IO server, so you will need to either build it yourself as a WSGI middleware, or else implement the HTTP to HTTPS redirection in a reverse proxy that sits above your Python server, such as nginx or Apache.

404 for all routes with Flask on uWSGI/Gunicorn

I found and forked the following Flask/SQLAlchemy/Marshmallow example project:
https://github.com/summersab/RestaurantAPI
It works like a charm, and I used it to build a custom API. It runs flawlessly with:
python run.py
Then, I tried to run it on a proper webserver:
uwsgi --http localhost:5000 --wsgi-file run.py --callable app
However, I get 404 for all routes except /, /api, and /api/v1.0. I tried it on Gunicorn with the same results leading me to believe that the problem is with the code, not the webserver config.
All of the following posts have the same problem, but from what I could tell, none of them had solutions that worked for me (I may have missed something):
Flask on nginx + uWSGI returns a 404 error unless the linux directory exists
Unexplainable Flask 404 errors
Nginx+bottle+uwsgi Server returning 404 on every request
Flask application with Blueprints+uWSGI+nginx returning 404's (no routing?)
Flask Blueprint 404
Could someone look at the code in my repo and help me figure out what's wrong?
EDIT:
Per the response from #v25, I changed my run.py to the following:
from flask import Flask, redirect, render_template
from app import api_bp
from model import db, redis_cache
from config import DevelopmentConfig, TestingConfig, BaseConfig, PresentConfig
app = Flask(__name__)
t = 0
def create_app(config_filename):
app.config.from_object(config_filename)
global t
if t == 0:
app.register_blueprint(api_bp, url_prefix='/api/v1.0')
t = 1
if config_filename != TestingConfig:
db.init_app(app)
redis_cache.init_app(app)
return app
#app.route('/')
#app.route('/api/')
#app.route('/api/v1.0/')
def availableApps():
return render_template('availableApp.html')
PresentConfig = BaseConfig
app = create_app(PresentConfig)
if __name__ == "__main__":
app.run(use_debugger=False, use_reloader=False, passthrough_errors=True)
I then ran this with uwsgi, and it works as expected:
uwsgi --http localhost:5000 --wsgi-file run.py --callable app
Thanks for your help!
This could quickly be solved by creating a new file wsgi.py, with the following contents:
import run
PresentConfig = run.BaseConfig
app = run.create_app(PresentConfig)
Then execute with:
uwsgi --http localhost:5000 --wsgi-file wsgi.py --callable app
or...
gunicorn --bind 'localhost:5000' wsgi:app
Why does this work...
If you have a look inside the run.py file, and note what's happening when you launch that directly with python:
if __name__ == "__main__":
PresentConfig = BaseConfig
app = create_app(PresentConfig)
app.run(use_debugger=False, use_reloader=False, passthrough_errors=True)
you can see that app is being created, based on the return value of the create_app function which is passed a config. Note also that the create_app function registers the "other URLs" as part of the api_bp blueprint.
However the code inside this if clause is never executed when the app is executed with uwsgi/gunicorn; instead the app object which is imported is one without the other URLs registered.
By creating the wsgi.py file above, you're doing all of this in a manner which can then be improted by the wsgi/gunicorn executable.
With that in mind, another way to fix this would be to change the last four lines of run.py to look more like:
PresentConfig = BaseConfig
app = create_app(PresentConfig)
if __name__ == "__main__":
app.run(use_debugger=False, use_reloader=False, passthrough_errors=True)
You could then execute this with your original wsgi command.
It's worth noting this may break other code which does from run import app and expects app not to be the return value of create_app (unlikely in this case).
Let me know if you need clarification on anything.

How do I view errors my Flask App is returning?

I've started to make an app using Python 3 with the Flask framework. I mostly followed this tutorial. I'm currently using a free-tier AWS Ubuntu-16.04 server to host the app on while trying to develop it.
How am I meant to see the errors that my Flask App is returning? - as most of the time I receive a 500 Internal Server Error in my browser. Also is there an easier setup I should be using to develop and debug the app.
Thanks
Edit 1:
#!/usr/bin/python
from flask import Flask, render_template, request
app = Flask(__name__)
app.debug = True
#app.route('/table')
def current_return():
data = ['one', 'two', 'three']
return render_template("current.html",data = data)
if __name__ == "__main__":
app.run()
You should enable debugging for your app.
app = Flask(__name__)
app.debug = True
That will output the traceback on the error pages, instead of just a generic 'Server error' page.

Why isn't Flask giving me an interactive debugger?

Here's a simple Flask app with a syntax error (it should be sys.version, not sys.version()
from flask import Flask, url_for, request, render_template
import sys
app = Flask(__name__)
app.config.from_object(__name__)
#app.route('/')
def index():
version = sys.version()
return "This is the index page. Python version info: {}".format(version)
if __name__ == '__main__':
app.run(debug=True)
When I run it locally and try to access http://localhost:5000, I get the nice Werkzeug debugger:
but when I run it on a remote server (Apache 2.4.17, mod_wsgi 4.4.21), I only get a generic 500 error page:
I've tried various things to make this work:
set app.debug = True right after app = Flask(__name__)
based on this link, I tried adding this code as well:
from werkzeug.debug import DebuggedApplication
application = DebuggedApplication(app, True)
but nothing seems to help.
I know that the debugger doesn't work in forked environments, but according to this link, the default mode for mod_wsgi is to not be forked. My Apache config is:
WSGIDaemonProcess flasktest user=david group=devgrp threads=1 python-path=/apps/www/80/wsgi-scripts/FlaskTest:/apps/.virtualenvs/flasktest/lib/python3.4/site-packages
So why can't I get the pretty debugger?
EDIT: Here's the modified file with my additions (that aren't working)
from flask import Flask
import sys
app = Flask(__name__)
app.config.from_object(__name__)
app.debug = True
from werkzeug.debug import DebuggedApplication
application = DebuggedApplication(app, True)
#app.route('/')
def index():
version = sys.version()
return "This is the index page. Python version info: {}".format(version)
if __name__ == '__main__':
app.run(debug=True)
To add WSGI middleware to a Flask app, wrap and replace the app's wsgi_app attribute. In the case of the debug middleware, set app.debug = True as well so that Flask doesn't convert exceptions to 500 responses.
app.debug = True
app.wsgi_app = DebuggedApplication(app.wsgi_app, evalex=True)
It is a security risk to run the debugger on a public server. Despite the recent change requiring a PIN before running code, the debugger may still be insecure in unforseen ways. Typically, you get information about errors in production by using logging. This answer is a good basic summary of how to set that up.
Your method would probably work if you had replaced app rather than calling it application. mod_wsgi was probably picking up app before application, so it was still running the original app. It's still recommended to wrap app.wsgi_app though.

Python Flask Decorators and Apache mod_wsgi

I have created a fairly strait forward example of the Flask/Python application, and then I have decided to split code to the two files, so I have moved all decorators for Authentication to separate file, like following:
#### test.py
from flask import Flask, request, abort, request, make_response, url_for, jsonify
from flask.ext.httpauth import HTTPBasicAuth
import pypyodbc, json, collections, _db, _sc
from customauth import CustomHTTPBasicAuth
app = Flask(__name__)
app.debug = True
from werkzeug.debug import DebuggedApplication
application = DebuggedApplication(app, evalex=True)
#app.errorhandler(400)
def not_found(error): return make_response(jsonify( { 'error': 'Bad request' } ), 400)
#app.errorhandler(404)
def not_found(error): return make_response(jsonify( { 'error': 'Not found' } ), 404)
auth = CustomHTTPBasicAuth()
#app.route('/hello')
#auth.login_required
def hello_world():
name = request.args.get('name','')
return 'Hello ' + name + '!'
if __name__ == '__main__':
app.run()
#### customauth.py
from flask import Flask, jsonify, make_response, request
from flask.ext.httpauth import HTTPBasicAuth
import md5, socket
class CustomHTTPBasicAuth(HTTPBasicAuth):
def __init__(self):
super(CustomHTTPBasicAuth, self).__init__()
#self.get_password
def get_password(username):
if (md5.new(username).hexdigest() == '0cc175b9c0f1b6a831c399e269772661'): #'0cc175b9c0f1b6a831c399e269772661' is md5('a')
return '0cc175b9c0f1b6a831c399e269772661'
return None
#self.hash_password
def custom_authenticate(password):
return '0cc175b9c0f1b6a831c399e269772661'
#self.error_handler
def unauthorized():
return make_response(jsonify( { 'error': 'Unauthorized access' } ), 401)
#### wsgi.py
import sys
sys.path.insert(0, "c:/testflask/test")
from flask1 import app
application = app
First issues is: this code works fine when executed with the python test.py
Authentication form will popup asking for username and password, after entering 'a','a' authentication will pass and result 'Hello + whatever' will display.
But when executed through Apache mod_wsgi it does not run as expected authentication form will display unlimited number of times.
Please can someone explain this code running under python and not under mod_wsgi, and is there a way to fix this?
I am thinking that I am doing something wrong with the decorators but I am not sure what, also it does not answer why it's running via python and not via mod_wsgi.
Another thing is how to get Debug page via apache mod_wsgi instead of "Internal Server Error" page? I have tried with 'werkzeug.debug' and some other suggested things from the internet but nothing really worked for me.
Thanks,
#
I have found solution for the first bullet it is Apache settings only thing needed is to add WSGIPassAuthorization On in the config file.
Still trying to find solution for debugging...
The Flask debugger will likely not work if it detects that it is running in a multi process configuration as would often be the case for mod_wsgi if you are using embedded mode. Ensure you are using daemon mode of mod_wsgi:
WSGIDaemonProcess mysite
WSGIProcessGroup mysite
Note, do NOT set 'processes=1' to WSGIDaemonProcess. Let it default to 1. Using 'processes' option with any value will cause wsgi.multiprocess to be True which is possibly what is causing the Flask debugger to be disabled.

Categories

Resources