Day 38 — What's inside a Python wheel?

Today I read PEP 427 (and other PEPs mentioned in there) to learn more about Python wheel format! There are two types of distribution formats in Python - a source distribution, and a built distribution. The wheel format belongs to the second category in which things are already built, ready to be installed on a user's system. The installer just needs to unpack these things and put them in the site-packages! Yes, unpack. A wheel is just a ZIP archive with a special filename and a .whl extension!

A wheel filename follows the format {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl, where:

The last three components of the filename (before the extension) are called "compatibility tags", as defined in PEP 425.

Let's look at the wheel for conrad!


  $ unzip -l conference_radar-0.8.0-py3-none-any.whl
  Archive:  conference_radar-0.8.0-py3-none-any.whl
    Length      Date    Time    Name
  ---------  ---------- -----   ----
        264  2020-08-01 11:46   conrad/__init__.py
        ...
        273  2020-07-31 00:14   crawlers/__init__.py
        ...
         92  2020-08-01 12:06   conference_radar-0.8.0.dist-info/WHEEL
       5735  2020-08-01 12:06   conference_radar-0.8.0.dist-info/METADATA
       2204  2020-08-01 12:06   conference_radar-0.8.0.dist-info/RECORD
      11343  2020-08-01 12:06   conference_radar-0.8.0.dist-info/LICENSE
         49  2020-08-01 12:06   conference_radar-0.8.0.dist-info/entry_points.txt
         16  2020-08-01 12:06   conference_radar-0.8.0.dist-info/top_level.txt
  ---------                     -------
      60310                     27 files

The root of the archive contains all files to be installed in the site-packages. The .dist-info directory includes WHEEL, METADATA, and RECORD at a minimum. Its structure is defined in PEP 376.

Installation

Installation for a wheel named conference_radar-0.8.0-py3-none-any.whl happens in two phases:

Also, wheels do not contain a setup.py or setup.cfg!

WHEEL

The contents of conference_radar-0.8.0.dist-info/WHEEL look like this:


  Wheel-Version: 1.0
  Generator: bdist_wheel (0.34.2)
  Root-Is-Purelib: true
  Tag: py3-none-any

METADATA

The contents of conference_radar-0.8.0.dist-info/METADATA look like this:


  Metadata-Version: 2.1
  Name: conference-radar
  Version: 0.8.0
  Summary: Track conferences and meetups on your terminal.
  Home-page: https://github.com/vinayak-mehta/conrad
  Author: Vinayak Mehta
  Author-email: vmehta94@gmail.com
  License: Apache 2.0
  Platform: UNKNOWN
  Classifier: License :: OSI Approved :: Apache Software License
  Classifier: Programming Language :: Python :: 3.6
  Classifier: Programming Language :: Python :: 3.7
  Classifier: Programming Language :: Python :: 3.8
  Description-Content-Type: text/markdown
  Requires-Dist: Click (>=7.0)
  ...
  Provides-Extra: dev
  Requires-Dist: Sphinx (>=2.2.1) ; extra == 'dev'
  ...

Package metadata has evolved a lot over the years. You can see the evolution if you go through the following PEPs:

Each PEP shows a summary of differences from the last one. Between PEPs 345 and 566, there was also PEP 426 which defined the Metadata-Version: 2.0.

It was deferred from December 2013 through to March 2017, until it was withdrawn in February 2018 in favour of PEP 566. During those four years, distutils-sig worked through a number of major changes (including the wheel format) which provided additional perspective on which metadata format changes were really needed and which changes could be omitted.

More recently, PEP 639 has been proposed to add support for SPDX license identifiers to the metadata! It defines the Metadata-Version: 2.2.

RECORD

The contents of conference_radar-0.8.0.dist-info/RECORD look like this:


  conrad/__init__.py,sha256=9CLWqIDZ3zdQaWPSE8_MkeYDrkBiMiTRtwvjgH6PMlg,264
  ...
  crawlers/__init__.py,sha256=kjZ6-dgMlTllgh-dgF9oNaSj16zqrkHepkLbRWQnxL4,273
  ...
  conference_radar-0.8.0.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
  conference_radar-0.8.0.dist-info/METADATA,sha256=U3nNq16oYEGW4QXWOEqieH8sLGUHyOi_1wtH36LXHZQ,5735
  conference_radar-0.8.0.dist-info/LICENSE,sha256=Bz1pUCrLkNY-AJBPeFhvBV-nTInGGHl5Omfru8Sfs1M,11343
  conference_radar-0.8.0.dist-info/entry_points.txt,sha256=ksgimi9VMCvimad9n9R7Yd0uSRX1jcd5kIGxylMd7v4,49
  conference_radar-0.8.0.dist-info/top_level.txt,sha256=fKXJ9FYqwcB8otyOU2HQErWf3TcLK3Dqc6rH1qK-Lp0,16
  conference_radar-0.8.0.dist-info/RECORD,,

The RECORD file holds a list of all the installed files, which allows the implementation of an uninstall command! It is a CSV, composed of records, one line per installed file. The csv module is used to read the file, with these options:

Each record is composed of three elements:


There's also PEP 491 which defines version 1.9 of the wheel format, but it is currently deferred, with Python packaging improvements currently focusing on the package build process rather than expanding the wheel format to cover additional use cases.