Python Flask Decorators and Apache mod_wsgi - python

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.

Related

Flask not updating webpage to reflect changes in application.py

I'm running this very simple application.py file, in debug mode, on my Mac.
import os
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config["SECRET_KEY"] = "secret"
socketio = SocketIO(app)
#app.route("/")
def index():
return "hello"
if __name__ == '__main__':
socketio.run(app, debug=True)
It shows up on 127.0.0.1:5000. When I change return "hello" to return "goodbye" and refresh the page, nothing happens. When I try to return render_template(goodbye.html) from my templates directory, nothing happens. I even changed the route from '/' to '/bbbb' and nothing changed. I see a bunch of GET requests in my terminal, each with a status code of 200.
I've never had this problem with Flask, that is until I tried to use sockets.io. Any thoughts on what is happening?

Combining 2 Flask apps using DispatcherMiddleware instance results in 404 for second app

Sorry for ambiguous question, I'm not sure how better I can put it. So let me do the explanation of my problem.
I've the Flask application libindic, which has 2 Flask application one is frontend and other is api. So I've wsgi.py as follows
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware
from silpa import api, frontend
import os
conffile = os.path.join(os.path.dirname(__file__), "etc", "silpa.conf")
application = DispatcherMiddleware(frontend.create_app(conffile),
{'/api': api.create_app(conffile)})
if __name__ == "__main__":
run_simple('0.0.0.0', 5000, application,
use_reloader=True, use_debugger=True)
The front end access works properly but when I hit /api/JSONRPC I get 404 error returned. This rule is defined as follows in silpa/api/jsonrpc.py
bp = Blueprint('api_jsonrpc', __name__, url_prefix='/api')
#route(bp, '/JSONRPC', methods=['POST'])
def handle_jsonrpc_call():
...
And when I print value of application and application.app and application.mounts in python interpreter I see folllowing
>>> application.app
<Flask 'silpa.frontend'>
>>> application.mounts
{'/api': <Flask 'silpa.api'>}
I'm unable to figure out why /api/JSONRPC results in 404. I'm not sure how can I debug it. I did check the app.url_map for api application and I can see rule for /api/JSONRPC registered there.
If some one can tell me what I might be doing wrong it would be a great help.
OK after debugging and stepping through Flask code I figured out the reason for the problem. The following line actually caused the problem
bp = Blueprint('api_jsonrpc', __name__, url_prefix='/api')
url_prefix should not be present in code because I'm already mounting this app at /api. Adding a /api url_prefix will result in following url instead /api/api/JSONRPC. Removing the above line fixed the issue.
So if you are mouting your app at different mount point than / using DispatcherMiddleware you should not url_prefix in blueprint.

No response from a Flask application using Apache server

I have created a flask application and am hosting it on a Ubuntu server. I know that my apache config is correct since I am able serve the example flask application. However, this one seems to be giving me trouble. The code is below:
from flask import Flask, render_template, request, url_for
import pickle
import engine
import config
# Initialize the Flask application
app = Flask(__name__)
model = pickle.load(open(config.MODEL_PATH, "rb"))
collection = engine.Collection(config.DATABASE_PATH)
search_engine = engine.SearchEngine(model, collection)
#app.route('/')
def form():
return render_template('index.html')
#app.route('/search/', methods=['POST'])
def search():
query = request.form['query']
results = search_engine.query(query)
return render_template('form_action.html', query=query, results=results)
#app.route('/retrieve/<int:item_number>', methods=['GET'])
def retrieve(item_number):
item = engine.Product(item_number, collection.open_document(str(item_number)))
return render_template('document.html', item=item)
if __name__ == '__main__':
app.run()
When running the file directly through the python interpreter, it works fine and I can access. However, when starting through apache and wsgi, I get no response from the server. It just hangs when making a request and nothing is available on the logs.
I suspect that my issue may have something to do with the three objects I initialize at the beginning of the program. Perhaps it gets stuck running those?
Update: I have tried commenting out certain parts of the code to see what is causing it to stall. Tracing it out to the engine module, importing NearestNeighbors seems to be causing the issue.
import sqlite3
import config
from sklearn.neighbors import NearestNeighbors
from preprocessor import preprocess_document
from collections import namedtuple

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.

Flask debug=True does not work when going through uWSGI

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

Categories

Resources