Managing dependencies in Python projects can be a a really painful experience.
Getting your virtual environments set up and installing dependencies under the correct version of Python are just two of the challenges that a newcomer to the ecosystem might face. As I've been working with Python more, I've definitely forgotten to activate my virtual environment or run into versioning issues, like trying to run Django 2.x but only having Django 1.x available in my environment.
Additionally, different development communities within the Python ecosystem tend to have their own way of managing environments and dependencies. So when I was learning data science, I used Anaconda for my environments and it would often conflict with virtualenv. I once updated the
requirements.txt file for a Django project and included everything that comes with a fresh Anaconda environment (pandas, numpy, etc) and didn't realize for a couple of commits.
Pipenv is the solution - it works like other bundlers and dependency managers (so like you'd expect it to work) and it works really well.
Pipenv uses a
Pipfile.lock so you can manage your dependencies (including development dependencies) and have deterministic builds. It still manages your dependencies in a virtual environment, but it makes creating and activating virtual environments easy and straightforward.
The first step is to install
Pipenv, which you can do with homebrew:
brew install pipenv
Now that it's installed, you can use it to install modules and setup a virtual environment for a project. Let's create a Django project and manage our dependencies for it with
Make a directory called
hello_django/ somewhere on your computer:
mkdir hello_django cd hello_django
Now install Django, like so:
pipenv install django
Notice that we started by installing a dependency and not by creating a new environment?
What's really great about
pipenv is that it will automatically set up a new environment for you! When we run the above command,
pipenv will create a virtual environment called
hello_django is the name of our directory and
twf5jxgT is a hash.
This virtual environment will be created inside a
.virtualenvs/ directory at the root of your user directory.
Working with Pipenv
Now that we have Django installed and our virtual environment setup, we can create our Django project:
pipenv run django-admin startproject hello_django .
This is the command for creating a new Django project. We add
. at the end of the command so that the project is created in our current directory (instead of a subdirectory).
Now if we want to start up our new app, we can do so with the following command:
pipenv run python manage.py runserver
pipenv run part of the above two commands is required, unless we run
pipenv shell to activate our virtual environment:
pipenv shell # activate virtual environment python manage.py runserver
Working with Dependencies
We can install another package by using
pipenv install psycopg2-binary
When we run
pipenv install, the
Pipfile gets updated automatically, just like with npm, composer, et al:
[[source]] name = "pypi" url = "https://pypi.org/simple" verify_ssl = true [dev-packages] [packages] django = "*" +psycopg2-binary = "*" [requires] python_version = "3.6"
One of the things that's great about npm and the
package.json file it uses is the ability to create custom scripts for commonly performed tasks. This automation is a great way of speeding up your development workflow.
You can also do this with
pipenv! All scripts go under a
[scripts] heading. Each script needs a name and a string for a command to run:
[scripts] start = "python manage.py runserver"
In this example, our script is
start and our command is
"python manage.py runserver", which is the command for starting our Django server.
To run the above
pipenv script, we do the following:
pipenv run start
start is the name of the command we want to run.
This feels easier than using virtualenvs on a few fronts. I've just covered setting up an environment and installing dependencies. But the
pipenv creates makes managing dependences (and other things, like Python versions) a lot easier than
requirements.txt. For instance, to install a dependency just for your development environment, you run
pipenv install --dev. Notice the same simplicity of working with Node dependencies?
For a next step, I highly recommend checking out the documentation. There are pages on a basic
pipenv workflow to follow and how to migrate from a
requirements.txt file. There are also some cool, advanced features like automatically loading a
.env file and setting up shell completion for