Python .whl files, or wheels, are a little-discussed part of Python, but they’ve been a boon to the installation process for Python packages. If you’ve installed a Python package using pip, then chances are that a wheel has made the installation faster and more efficient.
Wheels are a component of the Python ecosystem that helps to make package installs just work. They allow for faster installations and more stability in the package distribution process. In this tutorial, you’ll dive into what wheels are, what good they serve, and how they’ve gained traction and made Python even more of a joy to work with.
In this tutorial, you’ll learn:
- What wheels are and how they compare to source distributions
- How you can use wheels to control the package installation process
- How to create and distribute wheels for your own Python packages
You’ll see examples using popular open source Python packages from both the user’s and the developer’s perspective.
Free Bonus: Click here to get a Python Cheat Sheet and learn the basics of Python 3, like working with data types, dictionaries, lists, and Python functions.
Setup
To follow along, activate a virtual environment and make sure you have the latest versions of pip, wheel, and setuptools installed:
$ python -m venv env && source ./env/bin/activate
$ python -m pip install -U pip wheel setuptools
Successfully installed pip 20.1 setuptools-46.1.3 wheel-0.34.2
That’s all you need to experiment with installing and building wheels!
Python Packaging Made Better: An Intro to Python Wheels
Before you learn how to package a project into a wheel, it helps to know what using one looks like from the user’s side. It may sound backward, but a good way to learn how wheels work is to start by installing something that isn’t a wheel.
You can start this experiment by installing a Python package into your environment just as you might normally do. In this case, install uWSGI version 2.0.x:
1$ python -m pip install 'uwsgi==2.0.*'
2Collecting uwsgi==2.0.*
3 Downloading uwsgi-2.0.18.tar.gz (801 kB)
4 |████████████████████████████████| 801 kB 1.1 MB/s
5Building wheels for collected packages: uwsgi
6 Building wheel for uwsgi (setup.py) ... done
7 Created wheel for uwsgi ... uWSGI-2.0.18-cp38-cp38-macosx_10_15_x86_64.whl
8 Stored in directory: /private/var/folders/jc/8_hqsz0x1tdbp05 ...
9Successfully built uwsgi
10Installing collected packages: uwsgi
11Successfully installed uwsgi-2.0.18
To fully install uWSGI, pip progresses through several distinct steps:
- On line 3, it downloads a TAR file (tarball) named
uwsgi-2.0.18.tar.gzthat’s been compressed with gzip. - On line 6, it takes the tarball and builds a
.whlfile through a call tosetup.py. - On line 7, it labels the wheel
uWSGI-2.0.18-cp38-cp38-macosx_10_15_x86_64.whl. - On line 10, it installs the actual package after having built the wheel.
The tar.gz tarball that pip retrieves is a source distribution, or sdist, rather than a wheel. In some ways, a sdist is the opposite of a wheel.
Note: If you see an error with the uWSGI installation, you may need to install the Python development headers.
A source distribution contains source code. That includes not only Python code but also the source code of any extension modules (usually in C or C++) bundled with the package. With source distributions, extension modules are compiled on the user’s side rather than the developer’s.
Source distributions also contain a bundle of metadata sitting in a directory called <package-name>.egg-info. This metadata helps with building and installing the package, but user’s don’t really need to do anything with it.
From the developer’s perspective, a source distribution is what gets created when you run the following command:
$ python setup.py sdist
Now try installing a different package, chardet:
1$ python -m pip install 'chardet==3.*'
2Collecting chardet
3 Downloading chardet-3.0.4-py2.py3-none-any.whl (133 kB)
4 |████████████████████████████████| 133 kB 1.5 MB/s
5Installing collected packages: chardet
6Successfully installed chardet-3.0.4
You can see a noticeably different output than the uWSGI install.
Installing chardet downloads a .whl file directly from PyPI. The wheel name chardet-3.0.4-py2.py3-none-any.whl follows a specific naming convention that you’ll see later. What’s more important from the user’s perspective is that there’s no build stage when pip finds a compatible wheel on PyPI.
From the developer’s side, a wheel is the result of running the following command:
$ python setup.py bdist_wheel
Why does uWSGI hand you a source distribution while chardet provides a wheel? You can see the reason for this by taking a look at each project’s page on PyPI and navigating to the Download files area. This section will show you what pip actually sees on the PyPI index server:
- uWSGI provides only a source distribution (
uwsgi-2.0.18.tar.gz) for reasons related to the complexity of the project. - chardet provides both a wheel and a source distribution, but
pipwill prefer the wheel if it’s compatible with your system. You’ll see how that compatibility is determined later on.
Another example of the compatibility check used for wheel installation is psycopg2, which provides a wide set of wheels for Windows but doesn’t provide any for Linux or macOS clients. This means that pip install psycopg2 could fetch a wheel or a source distribution depending on your specific setup.
To avoid these types of compatibility issues, some packages offer multiple wheels, with each wheel geared toward a specific Python implementation and underlying operating system.
So far, you’ve seen some of the visible distinctions between a wheel and sdist, but what matters more is the impact those differences have on the installation process.