Why pipenv over venv for Python projects?

By default, every Python project on your system will use these same directories to store and retrieve site packages (third party libraries).
But you would have probably discovered that it’s quite painful to manage different projects with different dependencies targeting different Python versions on your local machine.
At such situations, the concept of virtual environment comes to our aid.
If you haven’t used or don’t know about Virtual Environments in Python, let me first define it for you.
A virtual environment is a tool that helps to keep dependencies required by different projects separate by creating isolated Python virtual environments for them.
So, basically the Python(parent) installed in your local machine gives birth to another Python(child) on your machine and you can use this environment for a specific project. You can install or uninstall dependencies in this virtual environment without affecting the dependencies installed in your parent Python.
One of the common ways of creating virtual environments is by using venv
. The venv module comes pre-installed with Python 3.5+ versions. Some of the important commands for creating virtual environments using venv are listed below :
Creating Virtual Environment
python -m venv environment_name
Activate Virtual Environment
- For MacOS and Linux users :
venv environment_name/bin/activate
- For Windows users, first change your directory to the newly created environment folder and then run the following command :
..\environment_name\Scripts\activate
Deactivate Virtual Environment
deactivate
Check all dependencies installed in the Virtual Environment
- First activate the virtual environment and then use the following command to see the list of dependencies installed in that virtual environment :
pip freeze
- To generate a requirements.txt file having all the dependencies with their respective versions :
pip freeze > requirements.txt
Install all dependencies from a requirements.txt file
pip install -r requirements.txt
Let’s now move to Pipenv which has now become the recommended way of managing project dependencies. Instead of having a requirements.txt
file in your project, and managing virtual environments, we'll now have a Pipfile
in our project that does all this stuff automatically. If you have ever worked with Node.js, you might be familiar with the package.json and package-lock.json files. The Pipfile and Pipfile.lock files are similar to them in Python.
Install pipenv
Let’s start by installing Pipenv first in our local machine. Use the following command to do so :
pip install pipenv
Using pipenv for the first time
pipenv install
The above command will look for a Pipenv file. If it doesn’t exist, it will create a new environment and activate it. After the above command is run, we’ll find two new files : Pipenv and Pipenv.lock
Activate already created pipenv environment
pipenv shell
Install/Uninstall dependencies
pipenv install djangopipenv uninstall django
Install dev dependencies
pipenv install nose --dev
Install from requirements.txt
pipenv install -r requirements.txt
Check security vulnerabilities
pipenv check
Check dependency graph
pipenv graph
Run custom scripts
Similar to npm, we can also run custom scripts using pipenv. Suppose we are working on a Django project, we have to run the server using the command :python manage.py runserver
. Now we can add this command in our Pipfile, Currently, our Pipfile may look like this :
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"[packages]
django = "*"[dev-packages]
nose = "*"[scripts]
server = "python manage.py runserver"[requires]
python_version = "3.8"
In the above output, we can see we have added our script in the scripts section. So, now we can simply run the below command to run our server :
pipenv run server
Lock the dependencies
pipenv lock -r
A Pipfile.lock file typically looks like this :
{
"_meta": {
"hash": {
"sha256": "627ef89...64f9dd2"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.8"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"django": {
"hashes": [
"sha256:acdcc1...ab5bb3",
"sha256:efbcad...d16b45"
],
"index": "pypi",
"version": "==3.1.1"
},
"pytz": {
"hashes": [
"sha256:a061aa...669053",
"sha256:ffb9ef...2bf277"
],
"version": "==2020.1"
}
},
"develop": {}
}
Conclusion
To be fair, Pipenv performs just like pip when it comes to installing all the required sub-dependencies for your packages. But once you’ve solved the issue, Pipfile.lock keeps track of all of your application’s interdependencies, including their versions, for each environment so you can basically forget about interdependencies.
In practice, this means you can continue working in development until you’ve got a set of packages/versions that work for you. Now you can simply issue pipenv lock
and Pipenv will lock all the dependencies/interdependencies your project requires, pinning their versions and hashing the results so you can deterministically replicate your build in production.
At the end, my suggestion would be Stop pip installing into your virtual environments and start pipenv installing. You won’t regret it, trust me.
I have put some basic commands related to pipenv in a Github Gist. You can take look over them here or visit http://srty.me/pipenv . If you liked the post, support by giving claps or starring the Github Gist. You can contact me on my website.
That’s all from my side, thanks for reading!