Posted by Steve Shanks on December 05, 2020 | python

Pipenv is a tool for managing your Python project’s dependencies, which aims to solve one of the problems with requirements.txt files. This post will get you started using Pipenv for dependency management, as well as show you how to use Pyenv to work with multiple versions of Python.

Pipenv

Installing dependencies

First, make sure you have Pipenv installed by following the instructions.

Now let’s build a simple Hello World API using Flask.

pipenv install flask

This will create our virtual environment, and install Flask as a dependency. You won’t see a venv directory - Pipenv stores each virtual environment outside the project folder, and uses the correct one automatically.

You will see a couple of new files in your directory - Pipfile and Pipefile.lock. We’ll take a look at them shortly.

Because we’re responsible developers, we’re also going to write a test for our API, so let’s install pytest. Since we won’t be deploying our tests to production, we can use --dev to install pytest as a dev dependency.

pipenv install --dev pytest

Pipfile and Pipfile.lock

Let’s take a closer look at our Pipfile.

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
flask = "*"

[dev-packages]
pytest = "*"

[requires]
python_version = "3.8"

Much like NPM’s package.json, it keeps track of our dependencies, dev dependencies, and required language version. Pipfile.lock will keep track of the exact versions installed. If we commit both these files to version control, then another developer can download our repo, and run:

pipenv install --dev

This will give them exactly the same versions of each dependency.

Creating our app

We’ll create our app in main.py:

from flask import Flask


app = Flask(__name__)

@app.route("/hello/<name>")
def hello_world(name):
    return {"message": f"Hello, {name.title()}!"}

and our test in test_main.py:

from main import app


def test_hello_world():
    with app.test_client() as client:
        response = client.get("/hello/your%20name")
        assert response.status_code == 200
        assert response.json == {"message": "Hello, Your Name!"}

Running our code

To run code using Pipenv, we don’t need to activate a virtual environment - we can just pass our command to pipenv run. So to run the tests, we’d use:

pipenv run pytest

and Pipenv will run the code in the correct environment. Similarly, to run our new API we’d use:

FLASK_APP=main pipenv run flask run

You should now be able to see the API in action using:

curl http://localhost:5000/hello/your%20name

Pyenv

Installing multiple Python versions

Pyenv lets you install and easily work with different versions of Python on your machine, and it works with Pipenv.

Start by installing Pyenv following the instructions - there’s a little more setup involved than when installing Pipenv, make sure not to miss the pyenv init step!

Pipenv works by adding a shim to your PATH, so that whenever you run e.g. python, it will actually run the shim, which will then decide which Python executable to run.

Let’s try it out by installing Python 3.9:

pyenv install 3.9.0

We can then tell Pyenv to use a specific Python version for code within the current directory. This is great if you work on multiple projects, or just want to try out the latest version of Python.

pyenv local 3.9.0

This will create a .python-version file in the current directory, which Pyenv will check next time you run code from that directory.

Using Pipenv with Pyenv

Finally, let’s tell Pipenv to use this new version of Python. Remove the existing virtual environment, and recreate it, specifying the Python version we want to use:

pipenv --rm
pipenv install --dev --python=$(pyenv which python)

Your code should now be running with the latest version of Python!

Resources