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:])