Thanks to visit codestin.com
Credit goes to www.pythonmorsels.com

Using pip requirements files PREMIUM

Trey Hunner smiling in a t-shirt against a yellow wall
Trey Hunner
5 min. read 3 min. video Python 3.10—3.14
Python Morsels
Watch as video
03:03

How can you document which third-party Python packages your code depends on?

Problem: we don't know what requirements our code has

Here we have a program called pstorpdt.py:

from datetime import datetime
from textwrap import dedent

from flask import Flask, redirect, url_for
from dateutil.tz import gettz

app = Flask(__name__)


timezone = gettz("America/Los_Angeles")


@app.route("/")
def home():
    return page_for_date(datetime.now(timezone))


@app.route("/<int:year>-<int:month>-<int:day>")
def date(year, month, day):
    try:
        date = datetime(year, month, day, 6, 0, tzinfo=timezone)  # 6am
    except ValueError:
        return redirect(url_for("home"))
    return page_for_date(date)


def page_for_date(date):
    timezone_name = date.tzname()
    return dedent(f"""\
    <!DOCTYPE html>
    <title>It's {timezone_name}</title>
    <style>
    :root {{ --size: min(30vh, 40vw); }}
    header {{ text-align: center; margin-top: 20vh; font-size: var(--size); }}
    </style>
    <header>{timezone_name}</header>
    """)


if __name__ == "__main__":
    app.run(debug=True)

This is a web application that tells us whether we're currently observing Pacific Daylight Time or Pacific Standard Time in the US Pacific timezone.

If we run this application, we'll get an error:

~/pstorpdt $ python3 pstorpdt.py
Traceback (most recent call last):
  File "/home/trey/pstorpdt/pstorpdt.py", line 4, in <module>
    from flask import Flask, redirect, url_for
ModuleNotFoundError: No module named 'flask'

We get an error because we don't currently have Flask installed globally on our machine, and this code depends on Flask to run.

Instead of installing Flask globally, we'll make a new virtual environment for this project:

~/pstorpdt $ python3 -m venv .venv --prompt=pstorpdt

Then we'll activate that virtual environment and install Flask within it (using pip):

~/pstorpdt $ source .venv/bin/activate
(pstorpdt) ~/pstorpdt $ python3 -m pip install flask
Collecting flask
  Using cached Flask-2.1.2-py3-none-any.whl (95 kB)
...
Installing collected packages: Werkzeug, MarkupSafe, itsdangerous, click, Jinja2, flask
Successfully installed Jinja2-3.1.2 MarkupSafe-2.1.1 Werkzeug-2.1.2 click-8.1.3 flask-2.1.2 itsdangerous-2.1.2

After this, we'll hope that our code works. I say we'll "hope that our code works" because we don't know whether we installed the correct version of Flask or whether even whether Flask is the only third-party requirement we need.

As it turns out, Flask isn't the only package we need:

(pstorpdt) ~/pstorpdt $ python3 pstorpdt.py
Traceback (most recent call last):
  File "/home/trey/pstorpdt/pstorpdt.py", line 5, in <module>
    from dateutil.tz import gettz
ModuleNotFoundError: No module named 'dateutil'

We also depend on the python-dateutil module:

(pstorpdt) ~/pstorpdt $ python3 -m pip install python-dateutil
Collecting python-dateutil
  Using cached python_dateutil-2.8.2-py2.py3-none-any.whl (247 kB)
Collecting six>=1.5
  Using cached six-1.16.0-py2.py3-none-any.whl (11 kB)
Installing collected packages: six, python-dateutil
Successfully installed python-dateutil-2.8.2 six-1.16.0

So once we've installed Flask and python-dateutil, our code actually works (we could visit that http://127.0.0.1:5000 URL on our machine to see a working webpage):

(pstorpdt) ~/pstorpdt $ python3 pstorpdt.py
 * Serving Flask app 'pstorpdt' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 889-707-721

Our code works at this point. But what should we do after we switch to a new computer? Or what should we do if someone else started working on this project with us?

Documenting our pip requirements

We need to document which Python packages our code depend on, including which versions of those packages we depend on.

Python's pip module has a list command that we can use to list all of the packages we have installed in our current virtual environment:

(pstorpdt) ~/pstorpdt $ python3 -m pip list
Package         Version
--------------- -------
click           8.1.3
Flask           2.1.2
itsdangerous    2.1.2
Jinja2          3.1.2
MarkupSafe      2.1.1
pip             22.0.4
python-dateutil 2.8.2
setuptools      58.1.0
six             1.16.0
Werkzeug        2.1.2

This is a human-readable list. We need a computer-readable list.

There's also a pip freeze command which lists the same information in a way that is consumable by pip itself:

(pstorpdt) ~/pstorpdt $ python3 -m pip freeze
click==8.1.3
Flask==2.1.2
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.1
python-dateutil==2.8.2
six==1.16.0
Werkzeug==2.1.2
(pstorpdt) ~/pstorpdt $ python3 -m pip freeze > requirements.txt

It's common to take the output of pip freeze and pipe it into a requirements file, often called requirements.txt:

(pstorpdt) ~/pstorpdt $ python3 -m pip freeze > requirements.txt

This requirements.txt file should list each package that we depend on and the version of those packages that we depend on:

click==8.1.3
Flask==2.1.2
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.1
python-dateutil==2.8.2
six==1.16.0
Werkzeug==2.1.2

These requirements don't have to be an exact version though. For example we can say we'd like a Flask version greater than or equal to 2 and less than 3 like this:

Flask>=2, <3

We can even leave out the version entirely and just hope for the best:

Flask

But it's considered a best practice to pin our version numbers as strictly as we can to make sure our code doesn't break due to an incorrect package version.

Installing all packages from a requirements.txt file

Once we've made a requirements file that lists the packages and package versions that we depend on, we can run pip install with the -r argument to specify the requirements file that pip should use.

(pstorpdt) ~/pstorpdt $ python3 -m pip install -r requirements.txt
Requirement already satisfied: click==8.1.3 in ./.venv/lib/python3.10/site-packages (from -r requirements.txt (line 1)) (8.1.3)
Requirement already satisfied: Flask==2.1.2 in ./.venv/lib/python3.10/site-packages (from -r requirements.txt (line 2)) (2.1.2)
Requirement already satisfied: itsdangerous==2.1.2 in ./.venv/lib/python3.10/site-packages (from -r requirements.txt (line 3)) (2.1.2)
Requirement already satisfied: Jinja2==3.1.2 in ./.venv/lib/python3.10/site-packages (from -r requirements.txt (line 4)) (3.1.2)
Requirement already satisfied: MarkupSafe==2.1.1 in ./.venv/lib/python3.10/site-packages (from -r requirements.txt (line 5)) (2.1.1)
Requirement already satisfied: python-dateutil==2.8.2 in ./.venv/lib/python3.10/site-packages (from -r requirements.txt (line 6)) (2.8.2)
Requirement already satisfied: six==1.16.0 in ./.venv/lib/python3.10/site-packages (from -r requirements.txt (line 7)) (1.16.0)
Requirement already satisfied: Werkzeug==2.1.2 in ./.venv/lib/python3.10/site-packages (from -r requirements.txt (line 8)) (2.1.2)

With the -r option specified, pip will loop over each line in our requirements.txt file and install each package listed (making sure to get the exact versions we noted).

Summary: use a requirements file and pin your package versions

To document which packages your Python code depends on, you can use the pip freeze command to make a requirements file.

Make sure your requirements file pins your versions as strictly as possible to install the exact package versions your code needs to work properly.

Series: Installing Python Packages

Python's standard library includes a lot of helpful modules. But often Python code depends on third-party packages. What are the best practices when working with third party packages in Python?

To track your progress on this Python Morsels topic trail, sign in or sign up.

0%
Python Morsels
Watch as video
03:03
This is a free preview of a premium screencast. You have 2 previews remaining.