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
- Install pipenv using the pip command:
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.