- Published on
Better Python Development Workflow with Pipenv
- Authors
- Name
- Martin Valentino
- @martinlabs_eth
In my previous post, I have briefly describe my current python development workflow using a combination of virtualenv
, pyenv
, and pyenv-virtualenv
. It's been great for me and serve my workflow very well. But recently, my colleague at work, introduce me with a package call pipenv
. I look into the website and, it seems promising in terms of makes my workflow more convenient.
As per its website says, the problem that pipenv trying to solve is [1]:
- You no longer need to use pip and virtualenv separately. They work together.
- Managing a requirements.txt file can be problematic, so Pipenv uses Pipfile and Pipfile.lock to separate abstract dependency declarations from the last tested combination.
- Hashes are used everywhere, always. Security. Automatically expose security vulnerabilities.
- Strongly encourage the use of the latest versions of dependencies to minimize security risks arising from outdated components.
- Give you insight into your dependency graph (e.g. $ pipenv graph).
- Streamline development workflow by loading .env files.
This post is basically an updated version from my previous one. In this post I will describe the process to integrate pipenv into your python development workflow, and hopefully can make you more productive with it. I assume you have pyenv
and version of python installed in your machine. (I suggests to install python from pyenv, because it can save you with any issue related to priviledge access).
Install pipenv
Installing pipenv is pretty straightforward (:fingercross).
$ pip install pipenv
Even though at their website, for OSX they using homebrew, I found out that it can't find python installation from pyenv
and it tried to install python again. The other thing that I found is, when you install pipenv, it will also install virtualenv
for you.
Use pipenv for your package management
New Project
If you start with clean project pipenv
usage will be straight forward. For example, let say you want to create a new django project.
$ mkdir YourAwesomeProject
$ cd YourAwesomeProject
$ pipenv install django
When you run above command on terminal:
- pipenv first will create virtualenv with name convention
YourAwesomeProject-<random string>
- Create
Pipfile
for the project - install django package and generate
Pipfile.lock
You'll most likely see a result like below:
Creating a virtualenv for this project…
Pipfile: <root folder>/YourAwesomeProject/Pipfile
Using <root folder>/.pyenv/versions/3.6.6/bin/python3.6 (3.6.6) to create virtualenv…
⠇Already using interpreter <root folder>/.pyenv/versions/3.6.6/bin/python3.6
Using base prefix '<root folder>/.pyenv/versions/3.6.6'
New python executable in <root folder>/.virtualenvs/YourAwesomeProject-ensK0QMs/bin/python3.6
Also creating executable in <root folder>/.virtualenvs/YourAwesomeProject-ensK0QMs/bin/python
Installing setuptools, pip, wheel...done.
Virtualenv location: <root folder>/.virtualenvs/YourAwesomeProject-ensK0QMs
Creating a Pipfile for this project…
Installing django…
Collecting django
Downloading https://files.pythonhosted.org/packages/d1/e5/2676be45ea49cfd09a663f289376b3888accd57ff06c953297bfdee1fb08/Django-2.1.3-py3-none-any.whl (7.3MB)
Collecting pytz (from django)
Using cached https://files.pythonhosted.org/packages/f8/0e/2365ddc010afb3d79147f1dd544e5ee24bf4ece58ab99b16fbb465ce6dc0/pytz-2018.7-py2.py3-none-any.whl
Installing collected packages: pytz, django
Successfully installed django-2.1.3 pytz-2018.7
Adding django to Pipfile's [packages]…
Pipfile.lock not found, creating…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Updated Pipfile.lock (85c883)!
Installing dependencies from Pipfile.lock (85c883)…
🐍 ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 2/2 — 00:00:00
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
If you look at Pipfile
, you'll see something like below:
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
Django = "*"
[dev-packages]
[requires]
python_version = "3.6"
That *
version in Django package will make sure that you use the latest version. Pipenv will make sure that it will always compatible with all of packages associated with Django
Existing Project
If you have a python project that previously using requirements.txt
, pipenv also provide an easy way to migrate from it. You only need to run this command: pipenv install -r requirements.txt
. The command above, will read requirements.txt
file and generate Pipfile
with Pipfile.lock
.
If you look at your Pipfile
, you'll see something like this.
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
Django = "==2.1.3"
[dev-packages]
[requires]
python_version = "3.6"
That version of django will similar to the one you have in requirements.txt
file. I recommend to change it to *
, so it will always get the latest one and let pipenv handle all of the dependencies.
Install package only for development
Without pipenv
, I usually have several requirements.txt
file to differentiate between development and production environment. I usually have:
- common.txt # all of package that is common on dev and prod
- requirements.txt # common package + package only for production
- requirements-dev.txt # common package + package only for development
With pipenv
I can easily install package that only exist for development and everything still manageable with Pipfile
. Let say I want to have pytest
for running my unittest.
$ pipenv install pytest --dev
That command line argument --dev
above will install pytest
package only when you specify that argument.
Pipenv for development
After you setup your project for pipenv, the next thing is easy.
$ pipenv shell # activate the virtualenv
$ exit # if you have finished and want to exit virtualenv
Conclusion
That's all then. I have been used it for a couple of months and it's improve the way I manage my python project package since then.