Useful Flask tips

For the third project in Metis’ Data Science program, I used the Correlates of War data set to build a Random Forest classifier that predicts whether a conflict between two nations will turn violent. To make it interesting, I built a front-end application using Flask and d3.js.

The Correlates of War project has collected a lot of fascinating information about military conflict, and it was interesting to explore the data and think about how to use it to predict which disputes turn violent.

I won’t go into the data exploration, feature extraction or modeling here. That’s all covered pretty well in the Jupyter notebook in my GitHib repo. Here I’ll share a few tips I learned from building the Flask app (in the GitHub repo’s app sub-folder).

One function to route them all

With Flask you use the route() decorator to tell it what to do with a URL. The typical “Hello World!” Flask application looks like this:

import flask
app = flask.Flask(__name__)
@app.route('/')
def hello_world():
    return 'Hello, World!'

Here hello_world() returns a string to display in the browser, but you’ll usually want to return an HTML page stored in a separate file. For example,

import flask
app = flask.Flask(__name__)
@app.route("/")
def home_page():
    """
    Return app's home page.
    """
    with open("index.html", 'r') as input:
        return input.read()

You can simplify this further by using Flask’s send_from_directory() method, to handle reading the file. For example,

import flask
app = flask.Flask(__name__)
@app.route("/")
def home_page():
	return flask.send_from_directory('.', 'index.html')

But, what do you do when your app is composed of multiple URLs, with multiple files in different sub-directories? You could build route() functions for all of them, but there’s a quicker and easier way.

Using the path placeholder and two route() decorators, one function can route all your page requests. Mine looks like this:

@app.route('/', defaults={'path': 'MID_predictor.html'})
@app.route('/<path:path>')
def send_js(path):
    return flask.send_from_directory('.', path)

The app returns MID_predictor.html for the root path '/' and searches the local file system for everything else. When my HTML page requests, data/world-topo-min.json, Flask finds the file in the data sub-folder.

I found this trick helpful because I could add, remove and move files around without having to change the Python code. If you’re concerned about security, you’ll be glad to know Flask doesn’t allow you to use '..' to access files outside the application folder.

Debug mode

There are several ways to run a Flask application. You can use the flask command, Python’s -m switch, or Flask’s run command. Regardless of how you run it, you must stop and restart the server whenever you change your code.

If you enable Flask’s debug mode, it will automatically incorporate changes to Python code files, without you having to stop and restart the server. To enable Debug mode, export the FLASK_DEBUG environment variable, or pass debug=True to the Flask run command.

Debug mode includes an interactive debugger that can execute arbitrary code from the browser, so remember to disable it when you’ve finished testing your application.

I used a command line switch to control whether the app runs in debug mode. For example,

import getopt
import sys
def main(argv):
    try:
        opts, args = getopt.getopt(argv, 'd', ['debug'])
    except getopt.GetoptError:
        sys.exit(2)

    debug = False
    for opt, arg in opts:
        if opt in ['-d', '--debug']:
            debug = True

    app.run(host='0.0.0.0', debug=debug)


if __name__ == '__main__':
    main(sys.argv[1:])
Written on February 19, 2017