Your application is probably going to require a lot of software to function properly. If it doesn’t at least require the Flask package, you may be reading the wrong book. Your application’s environment is essentially all of the things that need to be around when it runs. Lucky for us, there are a number of things that we can do to make managing our environment much less complicated.
virtualenv is a tool for isolating your application in what is called a virtual environment. A virtual environment is a directory that contains the software on which your application depends. A virtual environment also changes your environment variables to keep your development environment contained. Instead of downloading packages, like Flask, to your system-wide — or user-wide — package directories, we can download them to an isolated directory for our current application. This makes it easy to specify which Python binary to use, which dependencies want to have available on a per project basis.
Virtualenv also lets you use different versions of the same package for different projects. This flexibility may be important if you’re working on an older system with several projects that have different version requirements.
When using virtualenv, you'll generally have only a few Python packages installed globally on your system. One of these will be virtualenv itself:
$ pip install virtualenv
Then, when you are inside your project directory, you'll create a new virtual environment with virtualenv:
$ virtualenv venv
This creates a new directory where the dependencies will be installed.
{ NOTE: The argument passed to virtualenv
is the destination directory of the virtual environment. It can be anything you'd like. }
Once the new virtual environment has been created, you must activate it by sourcing the bin/activate
script that was created inside the virtual environment:
$ source venv/bin/activate
This script makes some changes to your shell's environment variables so that everything points to the new virtual environment instead of your global system. You can see the effect by running which python
; “python” now refers to the Python binary in the virtual environment. When a virtual environment is active, dependencies installed with Pip will be downloaded to that virtual environment instead of the global system.
You may notice that your shell prompt has been changed too. virtualenv prepends the name of the currently activated virtual environment, so you know that you're not working on the global system.
You can deactivate your virtual environment by running the deactivate
command.
(venv)$ deactivate
$
I didn't want to mention virtualenvwrapper until you had seen the basics of virtualenv. I wanted to make that you understand what virtualenvwrapper is improving upon, so that you’ll understand why you’d want to use it.
The virtual environment directory adds clutter to your project repository. You only interact with it directly when activating the virtual environment. It shouldn’t even be in version control. The solution to this clutter is to use virtualenvwrapper. This package keeps all of your virtual environments out of the way in a single directory, usually ~/.virtualenvs/
.
To install virtualenvwrapper, follow the instructions in the documentation [http://virtualenvwrapper.readthedocs.org/en/latest/].
{ WARNING: Make sure that you've deactivated all virtual environments before installing virtualenvwrapper. You want it installed globally, not in a pre-existing environment. }
Now, instead of running virtualenv
to create an environment, you’ll run mkvirtualenv
:
$ mkvirtualenv rocket
New python executable in rocket/bin/python
Installing setuptools............done.
Installing pip...............done.
mkvirtualenv
creates a directory in your virtual environments folder, e.g. ~/.virtualenvs
, and activates it for you. Just like with plain old virtualenv
, python
and pip
now point to that virtual environment instead of the global system. To activate a particular environment, use the command: workon [environment name]
. deactivate
still deactivates the environment.
As a project grows, you’ll find that the list of dependencies grows with it. It’s not uncommon to need dozens of Python packages installed before you can even run a Flask application. The easiest way to manage these is with a simple text file. Pip can generate a text file listing all installed packages. It can also read in this list to install each of them on a new system, or in a freshly minted environment.
requirements.txt is a text file used by many Flask applications to list all of the packages needed to run an application. It is generated by running pip freeze > requirements.txt
. The list can be installed later using pip install -r requirements.txt
.
{ Warning: Make sure that you are operating in the correct virtual environments when freezing and installing dependencies. }
As your project grows, you may find that certain packages listed by pip freeze
aren’t actually needed to run the application. You’ll have packages that are installed for development only. pip freeze
doesn’t discriminate; it just lists the packages that are currently installed. As a result you may want to manually track your depencies as you add them. You can separate those packages need to run your application and those needed to develop your application into require_run.txt and require_dev.txt respectively.
Pick a version control system and use it. I recommend Git. From what I've seen, Git is the most popular choice for projects these days. Being able to delete code without worrying about making a critical mistake is invaluable. You’ll be able to keep your project free of massive blocks of commented out code, because you can delete it now and revert that change later should the need arise. Plus, you’ll have backup copies of your entire project on GitHub, Bitbucket, or your own Gitolite server.
I usually keep a file out of version control for one of two reasons. Either it’s clutter, or it’s a secret. Compiled files, e.g. .pyc
files and virtual environments (if you’re not using virtualenvwrapper for some reason) are examples of clutter. They don’t need to be in version control because they can be generated from .py
files and requirements.txt
respectively. API keys, application secret keys, and database credentials are examples of secrets. They shouldn’t be in version control because their exposure would be a massive breach of security.
{ NOTE: When making security related decisions, I assume that my repository will become public at some point. This means keeping secrets out, and never assuming that a security hole won’t be found because, “Who’s going to guess that they could do that?” }
When using Git, you can create a special file called .gitignore in your repository. In it, list regular expression patterns to match against filenames. Any filename that matches one of the patterns will be ignored by Git. I recommend ignoring *.pyc
and /instance
to get you started. Instance folders are used to make secret configuration variables available to your application.
{ .gitignore: *.pyc instance/ }
{ SEE ALSO:
- You can read more about .gitignore here: http://git-scm.com/docs/gitignore
- The Flask docs have a good section on instance folders: http://flask.pocoo.org/docs/config/#instance-folders }
Flask comes with a handy feature called "debug mode." To turn it on, you just have to set debug = True
in your development configuration. When it's on, the server will reload on code changes and errors will come with a stack trace and an interactive console.
{ WARNING: Take care not to enable debug mode in production. The interactive console enables arbitrary code execution and would be a massive security vulnerability if it was left on in the live site. }
{ SEE MORE:
- Take a look at the quick start section on debug mode: http://flask.pocoo.org/docs/quickstart/#debug-mode
- There is some good information on handling errors, logging and working with other debuggers here: flask.pocoo.org/docs/errorhandling }
Flask-DebugToolbar is another great tool for debugging problems with your application. In debug mode, it overlays a side-bar onto every page in your application. The side bar gives you debug information about SQL queries, logging, versions, templates, configuration and other fun stuff.
- Use virtualenv to keep your application’s dependencies together.
- Use virtualenvwrapper to keep your virtual environments together.
- Keep track of dependencies with one or more text files.
- Use a version control system. I recommend Git.
- Use .gitignore to keep clutter and secrets out of version control.
- Debug mode can give you information about problems in development.
- The Flask-DebugToolbar extension will give you even more of that information.