Pipenv: The New Packaging Tool For Python

pipenv

Whenever we write some kind of program, we also make use of external libraries and packages to avoid reinventing the wheel. We also need to make sure that the program is executed correctly in different environments. Thus, we need some kind of configuration file that manages the requirements in an organized way.

What is pipenv?

Pipenv is the recommended way to install Python packages and use a virtual environment. This is because when we use the pip package manager that’s bundled with Python, all packages are installed globally.

We don’t have encapsulated environments for our Python projects like creating web apps with Django, Flask or some other machine learning project.

Pipenv allows us to isolate the packages in specific environments.

Conventionally, programmers create a virtual environment and install packages inside it with pip. But pipenv automatically creates and manages a virtual environment and allows us to add and remove packages using a Pip file which is similar to various package managers like npm, yarn, composer, etc.

It also generates the ever-important Pipfile.lock. This is used to produce a deterministic build which means that for each specific project, the same version of packages that are listed in the Pip File will be used for that specific project.

There are no breaking changes if the project runs in any other place like in the production environment OR on a cloud OR a different machine.

Some common issues that pipenv seeks to solve

  • We no longer have to use pip and virtualenv separately.
  • requirements.txt file, was cumbersome to manage and also error-prone in some cases. Pipfile and Pipfile.lock used by pipenv is more user-friendly, easily managed, and mitigates errors.
  • Pipenv exposes the security vulnerabilities automatically and on top of that, hashed values are used everywhere by pipenv.
  • It provides insight into our dependency graph for all the packages.
  • Streamlines the dev workflow by loading .env files.
  • It also encourages making use of the latest versions of dependencies to minimize the security risks arising from outdated components.

Also Read: Conda vs Pip: Choosing your Python package manager

Working with pipenv

pip install pipenv

Look for all the packages using pip

pip freeze

Output:

certifi==2022.6.15
distlib==0.3.5
filelock==3.7.1        
pep8==1.7.1
pipenv==2022.8.5       
platformdirs==2.5.2    
PySimpleGUI==4.60.3    
virtualenv==20.16.3    
virtualenv-clone==0.5.7

Create and activate a virtual environment using pipenv

pipenv shell

This creates a Pipfile that contains all our dependencies. Let’s look into our Pipfile.

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

[packages]

[dev-packages]

[requires]
python_version = "3.10"
  • Check our project home information
pipenv --where  # Output: D:\Python
  • Check virtualenv information
pipenv --venv   # Output: C:\Users\Username\.virtualenvs\Python-hSRNNotQ

Installing a package with pipenv

pipenv install flask

Our Pipfile got updated with the package, flask. The “*’’ represents the latest version for flask.

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

[packages]
flask = "*"

[dev-packages]

[requires]
python_version = "3.10"

We can also see a Pipfile.lock file which contains all the dependencies and also the hashed values for the same. Here is a glimpse of the lock file.

{
    "_meta": {
        "hash": {
            "sha256": "458ff3b49ddcf0963535dd3aea79b000fa2015d325295d0b04883e31a7adf93e"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3.10"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "click": {
            "hashes": [
                "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e",
                "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"
            ],
            "markers": "python_version >= '3.7'",
            "version": "==8.1.3"
        },

  • Installing a package with a specific version
pipenv install Django==2.1.1 

Our Pipfile now

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

[packages]
flask = "*"
django = "==2.1.1"

[dev-packages]

[requires]
python_version = "3.10"

Uninstalling a package with pipenv

pipenv uninstall Django

Development dependencies for a project

While writing a program, we require some packages that are used in the development phase. While in production, these packages are no longer required and are ignored later. nose is a test automation framework in Python which we will be installing as a dev dependency.

pipenv install nose --dev

Our Pipfile now

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

[packages]
flask = "*"
django = "==2.1.1"

[dev-packages]
nose = "*"

[requires]
python_version = "3.10"

Checking for security vulnerabilities in installed packages

It also has a dedicated command to check for security vulnerabilities and display them in our terminal, so that they can be resolved. Thus, making the code more robust.

pipenv check

Displaying currently-installed dependency graph information

This command shows all the dependencies for each of the packages as well all the dependencies of the dependencies.

pipenv graph

Output:

Django==2.1.1
  - pytz [required: Any, installed: 2022.1]
Flask==2.2.2
  - click [required: >=8.0, installed: 8.1.3]
    - colorama [required: Any, installed: 0.4.5]      
  - itsdangerous [required: >=2.0, installed: 2.1.2]  
  - Jinja2 [required: >=3.0, installed: 3.1.2]        
    - MarkupSafe [required: >=2.0, installed: 2.1.1]  
  - Werkzeug [required: >=2.2.2, installed: 2.2.2]    
    - MarkupSafe [required: >=2.1.1, installed: 2.1.1]
nose==1.3.7

Set lockfile before project deployment

This ensures the usage of whatever dependencies have been provided in the Pipfile.lock  for the current project and also ignores the Pipfile

# Setup before deployment
pipenv lock

# Ignore Pipfile
pipenv install –-ignore-pipfile
  • Exit the current environment
exit

Summary

In this article, we went through the common workflow for setting up a virtual environment and using packages to configure a custom Python project using pipenv.

We also looked into some core commands and the ways they modified or provided information about our setup. We require different configurations for different projects. We managed our packages efficiently so that it does not throw any errors while being used at different places. Pipenv ensures the stability of our program and helps us to provide a robust structure to our code.

Reference

Official Documentation