Monday, March 5, 2018

Revisiting Python Packaging With Pipenv

Revisiting Python Packaging With Pipenv

Overview

Python is one of the friendliest yet most powerful languages out there. It is easy for beginners to pick up, yet packs a strong punch and is used extensively in diverse domains such as scientific programming, web application programming, and DevOps. But one of the weakest points of Python has been its support for packaging complex applications and their dependencies. 

Over the years, there have been many efforts to improve the situation. In August 2017, I wrote a tutorial on the state of the art in Python packaging: How to Write, Package and Distribute a Library in Python

It's been only four months, and there is a new player in town. Pipenv is now the officially recommended tool for packaging by PyPA (Python Packaging Authority). In this tutorial you'll learn why Pipenv significantly improves the state of packaging and overall development workflow for Python developers and how to use it effectively.

Python Dev Workflow for Humans

The goal of Pipenv is to improve the development workflow of Python developers when it comes to managing dependencies and virtual environments. It is another fine library from the industrious Kenneth Reitz, who is known mostly for the requests package (HTTP for humans), but wrote a few other excellent packages. 

Do We Need Yet Another Packaging Tool?

Yes, we do! Pipenv takes a page from modern package management practices and imports them into the Python world. 

Installing Pipenv

You can install Pipenv with pip install pipenv. You'll get a nice output with emojis:

You'll have to do it just once. If you don't have pip installed, you can use this bootstrap command: $ curl https://github.com/pypa/pipenv/blob/master/get-pipenv.py | python

Pipfile and Pipfile.lock

Pipenv can create an empty virtual environment for you. Here is a quick demo: 

This will create an empty Pipfile with no dependencies. But since you'll probably want to install some packages for your project, you can just use pipenv to install a package and it will create the virtual environment automatically. For example:

The level of detail is excellent, and it uses nice colors too. Here is the resulting Pipfile:

The Pipfile keeps track of your project's top-level dependencies—here, just requests = "*". It uses TOML as its format, which is a popular choice these days for configuration files (Rust's Cargo, Python's PEP-518). 

The Pipefile.lock file, on the other hand, is a JSON file that specifies some metadata and the exact versions (including hashes) of all the recursive dependencies (top-level dependencies and their dependencies). Here is the Pipfile.lock file:

If you want to see a graph of all your dependencies, type: pipenv graph

Using Installed Packages With Pipenv

Once you've installed a package with Pipenv, it is accessible in your virtual environment just like a standard package (the same as if you pip installed it). The only precaution is that you must use your virtual environment interpreter. Pipenv provides two helpful commands: run and shell

You use pipenv run python <your program>.py to run your program, and you use pipenv shell to start a new shell with your virtual environment Python interpreter. Here is how to use the shell command to start an interactive Python session that uses the installed requests package to get a quote of the day from a REST API. The virtual environment is activated, and launching Python uses the right interpreter where requests is available.

Importing From requirements.txt

If you want to migrate an existing project with a requirements.txt, Pipenv has got you covered. Simply: pipenv install -r <path/to/requirements.txt>.

All your dependencies will be imported into the Pipfile. To actually install the dependencies and generate the Pipfile.lock, you need to pipenv install. Once you've verified that everything works as expected, you can delete your requirements.txt file.

If your requirements.txt exists in the same directory that you create the virtual environment then Pipenv will automatically generate the Pipfile. But beware that if your requirements.txt file contained pinned versions then they will be pinned in the Pipfile too. In the Pipenv world, pinning should happen in the Pipfile.lock file. Pipenv will give a friendly reminder. See below:

Here is the pinned version in the Pipfile that is recommended to change to "*":

Let's install the dependencies now:

Editable Dependencies

You can tell Pipenv to install a path as editable. This is useful when you depend on packages you're developing and want to depend on your source package without actually installing them every time you make a change. In particular, it's useful for the current directory when you're actively working in it. To do that, use the -e and --dev flags:

You need to have a proper setup.py file.

Managing Your Environment With Pipenv

You've already seen a lot of what Pipenv can do for you. Let's dig deeper into some additional commands and options.

Installing Packages

The pipenv install command supports several options:

  • --dev: Install both develop and default packages from Pipfile.lock.
  • --system: Use the system pip command rather than the one from your virtualenv.
  • --ignore-pipfile: Ignore the Pipfile and install from the Pipfile.lock.
  • --skip-lock: Ignore the Pipfile.lock and install from the Pipfile. In addition, do not write out a Pipfile.lock reflecting changes to the Pipfile. 

Depending on your workflow and preferences, you may want to use one or more of these options at different times.

Uninstalling Packages

To uninstall a dependency, type: pipenv uninstall <package name>. For example:

Note that I didn't have to specify "requests==2.8.14" when uninstalling, even though it was pinned in the Pipfile.

Locking Dependencies

If you want to generate a snapshot of your current dependencies (e.g. before a release), use the lock command. This is the key to deterministic and repeatable builds: pipenv lock --pre.

Removing the Virtual Environment

Pipenv is awesome, but you may clean up some of your virtual environments from time to time. It's as simple as pipenv --rm.

Security

Pipfile.lock takes advantage of some great new security improvements in pip. By default, the Pipfile.lock will be generated with the sha256 hashes of each downloaded package. This will allow pip to guarantee you’re installing what you intend to when on a compromised network or downloading dependencies from an untrusted PyPI endpoint.

In addition, Pipenv provides the check command, which checks for compliance with PEP 508 -- Dependency specification for Python Software Packages as well as package safety:

Conclusion

Pipenv finally brings Python packaging to the forefront of modern software development. It takes inspiration from other successful dependency management systems like Rust's Cargo and Javascript's Yarn. 

It marries virtual environments and package management and provides a superior experience with beautiful and colorful informational messages, and implicit best practices! I highly recommend that you start using Pipenv to manage your Python projects.

Additionally, don’t hesitate to see what we have available for sale and for study in the Envato Market, and don't hesitate to ask any questions and provide your valuable feedback using the feed below.


No comments:

Post a Comment