Edit PEP 427 for markup and add missing footer.
This commit is contained in:
parent
0cce3cec68
commit
d45d2e63af
261
pep-0427.txt
261
pep-0427.txt
|
@ -3,136 +3,142 @@ Title: The Wheel Binary Package Format 1.0
|
|||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Daniel Holth <dholth@fastmail.fm>
|
||||
Discussions-To: Distutils SIG
|
||||
Discussions-To: <distutils-sig@python.org>
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created: 20 Sep 2012
|
||||
Created: 20-Sep-2012
|
||||
Post-History:
|
||||
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
This PEP describes a built-package format for Python called wheel.
|
||||
This PEP describes a built-package format for Python called "wheel".
|
||||
|
||||
A wheel is a ZIP-format archive with a specially formatted file name
|
||||
and the ``.whl`` extension. It contains a single distribution nearly
|
||||
as it would be installed according to PEP 376 with a particular
|
||||
installation scheme. A wheel file may be installed by simply
|
||||
unpacking into site-packages with the standard 'unzip' tool, while
|
||||
preserving enough information to spread its contents out onto their
|
||||
final paths at any later time.
|
||||
|
||||
A wheel is a ZIP-format archive with a specially formatted file name and
|
||||
the .whl extension. It contains a single distribution nearly as it would
|
||||
be installed according to PEP 376 with a particular installation scheme.
|
||||
A wheel file may be installed by simply unpacking into site-packages
|
||||
with the standard ‘unzip’ tool, while preserving enough information
|
||||
to spread its contents out onto their final paths at any later time.
|
||||
|
||||
Rationale
|
||||
=========
|
||||
|
||||
Python needs a package format that is easier to install than sdist.
|
||||
Python’s sdist packages are defined by and require the distutils and
|
||||
Python's sdist packages are defined by and require the distutils and
|
||||
setuptools build systems, running arbitrary code to build-and-install,
|
||||
and re-compile, code just so it can be installed into a new virtualenv.
|
||||
This system of conflating build-install is slow, hard to maintain, and
|
||||
hinders innovation in both build systems and installers.
|
||||
and re-compile, code just so it can be installed into a new
|
||||
virtualenv. This system of conflating build-install is slow, hard to
|
||||
maintain, and hinders innovation in both build systems and installers.
|
||||
|
||||
Wheel attempts to remedy these problems by providing a simpler
|
||||
interface between the build system and the installer. The wheel
|
||||
binary package format frees installers from having to know about the
|
||||
build system, saves time by amortizing compile time over many
|
||||
installations, and removes the need to install a build system in the
|
||||
target environment.
|
||||
|
||||
Wheel attempts to remedy these problems by providing a simpler interface
|
||||
between the build system and the installer. The wheel binary package
|
||||
format frees installers from having to know about the build system,
|
||||
saves time by amortizing compile time over many installations, and
|
||||
removes the need to install a build system in the target environment.
|
||||
|
||||
Details
|
||||
=======
|
||||
|
||||
Installing a wheel ‘distribution-1.0.py32.none.any.whl’
|
||||
Installing a wheel 'distribution-1.0.py32.none.any.whl'
|
||||
-------------------------------------------------------
|
||||
|
||||
#. Unpack.
|
||||
|
||||
a. Parse distribution-1.0.dist-info/WHEEL.
|
||||
b. Check that installer is compatible with Wheel-Version. Warn if minor
|
||||
version is greater, abort if major version is greater.
|
||||
c. If Root-Is-Purelib == ‘true’, unpack archive into purelib
|
||||
(site-packages).
|
||||
d. Else unpack archive into platlib (site-packages).
|
||||
a. Parse ``distribution-1.0.dist-info/WHEEL``.
|
||||
b. Check that installer is compatible with Wheel-Version. Warn if
|
||||
minor version is greater, abort if major version is greater.
|
||||
c. If Root-Is-Purelib == 'true', unpack archive into purelib
|
||||
(site-packages).
|
||||
d. Else unpack archive into platlib (site-packages).
|
||||
|
||||
#. Spread.
|
||||
|
||||
a. Unpacked archive includes distribution-1.0.dist-info/ and (if there
|
||||
is data) distribution-1.0.data/
|
||||
b. Move each subtree of distribution-1.0.data/ onto its destination
|
||||
path. Each subdirectory of distribution-1.0.data/ is a key into
|
||||
sysconfig.get\_paths(), such as
|
||||
distribution-1.0.data/(config\|purelib\|platlib\|scripts).
|
||||
See` <http://docs.python.org/dev/packaging/setupcfg.html#resources>`_`http://docs.python.org/dev/packaging/setupcfg.html#resources <http://docs.python.org/dev/packaging/setupcfg.html#resources>`_
|
||||
c. If applicable, update scripts starting with “#!python” to point to
|
||||
the correct interpreter.
|
||||
d. Update distribution-1.0.dist.info/RECORD with the installed paths.
|
||||
e. Remove empty distribution-1.0.data directory.
|
||||
a. Unpacked archive includes ``distribution-1.0.dist-info/`` and (if
|
||||
there is data) ``distribution-1.0.data/``.
|
||||
b. Move each subtree of ``distribution-1.0.data/`` onto its
|
||||
destination path. Each subdirectory of ``distribution-1.0.data/``
|
||||
is a key into ``sysconfig.get_paths()``, such as
|
||||
``distribution-1.0.data/(config|purelib|platlib|scripts)``. See
|
||||
http://docs.python.org/dev/packaging/setupcfg.html#resources.
|
||||
c. If applicable, update scripts starting with ``#!python`` to point
|
||||
to the correct interpreter.
|
||||
d. Update ``distribution-1.0.dist.info/RECORD`` with the installed
|
||||
paths.
|
||||
e. Remove empty ``distribution-1.0.data`` directory.
|
||||
|
||||
File Format
|
||||
-----------
|
||||
|
||||
File name convention
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
''''''''''''''''''''
|
||||
|
||||
The wheel filename is {distribution}-{version}(-{build tag})?-{python
|
||||
tag}-{abi tag}-{platform tag}.whl
|
||||
The wheel filename is ``{distribution}-{version}(-{build
|
||||
tag})?-{python tag}-{abi tag}-{platform tag}.whl``.
|
||||
|
||||
distribution
|
||||
Distribution name, e.g. ‘django’, ‘pyramid’
|
||||
Distribution name, e.g. 'django', 'pyramid'.
|
||||
|
||||
version
|
||||
PEP-386 compliant version, e.g. 1.0
|
||||
PEP-386 compliant version, e.g. 1.0.
|
||||
|
||||
build tag
|
||||
Optional build number. Must start with a digit. A tie breaker if two
|
||||
wheels have the same version. Sort as None if unspecified, else sort
|
||||
the initial digits as a number, and the remainder lexicographically.
|
||||
Optional build number. Must start with a digit. A tie breaker if
|
||||
two wheels have the same version. Sort as None if unspecified,
|
||||
else sort the initial digits as a number, and the remainder
|
||||
lexicographically.
|
||||
|
||||
language implementation and version tag
|
||||
‘py27’ ‘py2’ ‘py3’
|
||||
E.g. 'py27', 'py2', 'py3'.
|
||||
|
||||
abi tag
|
||||
‘cp33m’, ‘abi3’, ‘none’
|
||||
E.g. 'cp33m', 'abi3', 'none'.
|
||||
|
||||
platform tag
|
||||
‘linux\_x86\_64’, ‘any’
|
||||
E.g. 'linux_x86_64', 'any'.
|
||||
|
||||
For example, distribution-1.0-1-py27-none-any.whl is the first build
|
||||
of a package called 'distribution', and is compatible with Python 2.7
|
||||
(any Python 2.7 implementation), with no abi (pure Python), on any CPU
|
||||
architecture.
|
||||
For example, ``distribution-1.0-1-py27-none-any.whl`` is the first
|
||||
build of a package called 'distribution', and is compatible with
|
||||
Python 2.7 (any Python 2.7 implementation), with no ABI (pure Python),
|
||||
on any CPU architecture.
|
||||
|
||||
The last three components of the filename before the extension are
|
||||
called “compatibility tags.” The compatibility tags express
|
||||
the package’s basic interpreter requirements and are detailed
|
||||
in `PEP 425 <http://hg.python.org/peps/file/tip/pep-0425.txt>`_.
|
||||
called "compatibility tags." The compatibility tags express the
|
||||
package's basic interpreter requirements and are detailed in PEP 425.
|
||||
|
||||
|
||||
File contents
|
||||
~~~~~~~~~~~~~
|
||||
'''''''''''''
|
||||
|
||||
#. Wheel files contain a folder {distribution}-{version}.dist-info/ with
|
||||
the PEP 426 metadata (Metadata version 1.3 or greater) and an
|
||||
#. Wheel files contain a folder {distribution}-{version}.dist-info/
|
||||
with the PEP 426 metadata (Metadata version 1.3 or greater) and an
|
||||
additional file WHEEL with metadata about the archive itself.
|
||||
#. The root of a .whl is installed into one of purelib or platlib.
|
||||
#. Wheel files contain metadata about the wheel format itself in
|
||||
{distribution}-{version}.dist-info/WHEEL::
|
||||
``{distribution}-{version}.dist-info/WHEEL``::
|
||||
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel 0.7
|
||||
Root-Is-Purelib: true
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel 0.7
|
||||
Root-Is-Purelib: true
|
||||
|
||||
#. Wheel-Version is the version number of the Wheel specification.
|
||||
Generator is the name and optionally the version of the software that
|
||||
produced the archive. Root-Is-Purelib is true if the top level
|
||||
directory of the archive should be installed into purelib; otherwise
|
||||
the root should be installed into platlib.
|
||||
Generator is the name and optionally the version of the software
|
||||
that produced the archive. Root-Is-Purelib is true if the top level
|
||||
directory of the archive should be installed into purelib;
|
||||
otherwise the root should be installed into platlib.
|
||||
#. A wheel installer should warn if Wheel-Version is greater than the
|
||||
version it supports, and fail if Wheel-Version has a greater major
|
||||
version than the version it supports.
|
||||
#. If a .whl contains scripts, both purelib and platlib, or any other
|
||||
files that are not installed on sys.path, they are found in
|
||||
{distribution}-{version}.data/{key}, where {key} is an index into
|
||||
sysconfig.get\_paths().
|
||||
files that are not installed on ``sys.path``, they are found in
|
||||
``{distribution}-{version}.data/{key}``, where ``{key}`` is an
|
||||
index into ``sysconfig.get_paths()``.
|
||||
#. Wheel, being an installation format that is intended to work across
|
||||
multiple versions of Python, does not generally include .pyc files.
|
||||
#. Wheel does not contain setup.py or setup.cfg.
|
||||
|
@ -146,19 +152,19 @@ The .dist-info directory
|
|||
#. METADATA is the PEP 426 metadata (Metadata version 1.3 or greater)
|
||||
#. WHEEL is the wheel metadata, specific to a build of the package.
|
||||
#. RECORD is a list of (almost) all the files in the wheel and their
|
||||
secure hashes. Unlike PEP 376, every file except RECORD, which cannot
|
||||
contain a hash of itself, must include its hash. The hash algorithm
|
||||
must be sha256 or better; specifically, md5 and sha1 are not
|
||||
permitted, as signed wheel files rely on the strong hashes in RECORD to
|
||||
validate the integrity of the archive.
|
||||
secure hashes. Unlike PEP 376, every file except RECORD, which
|
||||
cannot contain a hash of itself, must include its hash. The hash
|
||||
algorithm must be sha256 or better; specifically, md5 and sha1 are
|
||||
not permitted, as signed wheel files rely on the strong hashes in
|
||||
RECORD to validate the integrity of the archive.
|
||||
#. INSTALLER and REQUESTED are not included in the archive.
|
||||
#. RECORD.jws is used for digital signatures. It is not mentioned in
|
||||
#. RECORD.jws is used for digital signatures. It is not mentioned in
|
||||
RECORD.
|
||||
#. RECORD.p7s is reserved as a courtesy to anyone who would prefer to
|
||||
use s/mime signatures to secure their wheel files. It is not
|
||||
use s/mime signatures to secure their wheel files. It is not
|
||||
mentioned in RECORD.
|
||||
#. During extraction, wheel installers verify all the hashes in RECORD
|
||||
against the file contents. Apart from RECORD and its signatures,
|
||||
against the file contents. Apart from RECORD and its signatures,
|
||||
installation will fail if any file in the archive is not both
|
||||
mentioned and correctly hashed in RECORD.
|
||||
|
||||
|
@ -175,62 +181,62 @@ the .data directory, named as the .dist-info directory but with the
|
|||
distribution-1.0.data/
|
||||
|
||||
The .data directory contains subdirectories named after the keys of
|
||||
sysconfig.get\_paths(), and those subdirectories contain the scripts,
|
||||
headers, documentation and so forth from the distribution. During
|
||||
installation the contents of these subdirectories are moved onto their
|
||||
destination paths.
|
||||
``sysconfig.get_paths()``, and those subdirectories contain the
|
||||
scripts, headers, documentation and so forth from the distribution.
|
||||
During installation the contents of these subdirectories are moved
|
||||
onto their destination paths.
|
||||
|
||||
|
||||
Signed wheel files
|
||||
------------------
|
||||
|
||||
Wheel files include an extended RECORD that enables digital signatures.
|
||||
PEP 376’s RECORD is altered to include
|
||||
digestname=urlsafe\_b64encode\_nopad(digest) (urlsafe base64 encoding
|
||||
with no trailing = characters) as the second column instead of an
|
||||
md5sum. All possible entries are hashed, including any generated files
|
||||
such as .pyc files, but not RECORD. For example::
|
||||
Wheel files include an extended RECORD that enables digital
|
||||
signatures. PEP 376's RECORD is altered to include
|
||||
``digestname=urlsafe_b64encode_nopad(digest)`` (urlsafe base64
|
||||
encoding with no trailing = characters) as the second column instead
|
||||
of an md5sum. All possible entries are hashed, including any
|
||||
generated files such as .pyc files, but not RECORD. For example::
|
||||
|
||||
file.py,sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\_pNh2yI,3144
|
||||
distribution-1.0.dist-info/RECORD,,
|
||||
|
||||
RECORD.jws is not mentioned in RECORD at all. Every other file in the
|
||||
RECORD.jws is not mentioned in RECORD at all. Every other file in the
|
||||
archive must have a correct hash in RECORD, or the installation will
|
||||
fail.
|
||||
|
||||
The signature is one or more JSON Web Signature JSON Serialization
|
||||
(JWS-JS) signatures stored in a file RECORD.jws adjacent to RECORD.
|
||||
|
||||
A signature-aware installer can be instructed to check for a particular
|
||||
Ed25519 public key by using an extended “extras” syntax.::
|
||||
A signature-aware installer can be instructed to check for a
|
||||
particular Ed25519 public key by using an extended "extras" syntax.::
|
||||
|
||||
# request a normal optional feature "extra", and indicate
|
||||
# the package should be signed by a particular
|
||||
# urlsafe-b64encode-nopad encoded ed25519 public key:
|
||||
package[extra, ed25519=ouBJlTJJ4SJXoy8Bi1KRlewWLU6JW7HUXTgvU1YRuiA]
|
||||
|
||||
An application could distribute a requires.txt file with many such lines
|
||||
for all its dependencies and their public keys. By installing from this
|
||||
file an application’s users would know whether the applicaton’s
|
||||
dependencies came from the correct publishers.
|
||||
An application could distribute a requires.txt file with many such
|
||||
lines for all its dependencies and their public keys. By installing
|
||||
from this file an application's users would know whether the
|
||||
application's dependencies came from the correct publishers.
|
||||
|
||||
Applications that wish to “fail open” for backwards compatibility with
|
||||
Applications that wish to "fail open" for backwards compatibility with
|
||||
non-signature-aware installers should specify that their package
|
||||
provides the extra ed25519=(key) with no associated dependencies.
|
||||
provides the extra ``ed25519=(key)`` with no associated dependencies.
|
||||
|
||||
Key distribution is outside the scope of this spec. Public wheel signing
|
||||
keys could be signed with the packager’s GPG key or stored at
|
||||
an https://-protected URL.
|
||||
Key distribution is outside the scope of this spec. Public wheel
|
||||
signing keys could be signed with the packager's GPG key or stored at
|
||||
an ``https://`` protected URL.
|
||||
|
||||
|
||||
JSON Web Signatures Extensions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
''''''''''''''''''''''''''''''
|
||||
|
||||
The Ed25519 algorithm is used as an extension to the JSON Web Signatures
|
||||
specification. Wheel uses alg="Ed25519" in the header. The key attribute
|
||||
holds the signature’s public JSON Web Key. For JSON Web Key / JSON
|
||||
Private Key the verifying (public) key is called vk and the signing
|
||||
(private) key is called sk.
|
||||
The Ed25519 algorithm is used as an extension to the JSON Web
|
||||
Signatures specification. Wheel uses ``alg="Ed25519"`` in the header.
|
||||
The key attribute holds the signature's public JSON Web Key. For JSON
|
||||
Web Key / JSON Private Key the verifying (public) key is called vk and
|
||||
the signing (private) key is called sk.
|
||||
|
||||
Example header::
|
||||
|
||||
|
@ -243,7 +249,7 @@ Example header::
|
|||
}
|
||||
}
|
||||
|
||||
A future version of wheel may omit typ.
|
||||
A future version of wheel may omit ``typ``.
|
||||
|
||||
Example payload::
|
||||
|
||||
|
@ -263,24 +269,25 @@ See
|
|||
Comparison to .egg
|
||||
------------------
|
||||
|
||||
#. Wheel is an installation format; egg is importable. Wheel archives do
|
||||
not need to include .pyc and are less tied to a specific Python
|
||||
#. Wheel is an installation format; egg is importable. Wheel archives
|
||||
do not need to include .pyc and are less tied to a specific Python
|
||||
version or implementation. Wheel can install (pure Python) packages
|
||||
built with previous versions of Python so you don’t always have to
|
||||
built with previous versions of Python so you don't always have to
|
||||
wait for the packager to catch up.
|
||||
#. Wheel uses .dist-info directories; egg uses .egg-info. Wheel is
|
||||
#. Wheel uses .dist-info directories; egg uses .egg-info. Wheel is
|
||||
compatible with the new world of Python packaging and the new
|
||||
concepts it brings.
|
||||
#. Wheel has a richer file naming convention for today’s
|
||||
multi-implementation world. A single wheel archive can indicate its
|
||||
compatibility with a number of Python language versions and
|
||||
implementations, ABIs, and system architectures. Historically the ABI
|
||||
has been specific to a CPython release, wheel is ready for the stable
|
||||
ABI.
|
||||
#. Wheel is lossless. The first wheel implementation bdist\_wheel always
|
||||
generates egg-info, and then converts it to a .whl. It is also
|
||||
possible to convert existing eggs and bdist\_wininst distributions.
|
||||
#. Wheel is versioned. Every wheel file contains the version of the
|
||||
#. Wheel has a richer file naming convention for today's
|
||||
multi-implementation world. A single wheel archive can indicate
|
||||
its compatibility with a number of Python language versions and
|
||||
implementations, ABIs, and system architectures. Historically the
|
||||
ABI has been specific to a CPython release, wheel is ready for the
|
||||
stable ABI.
|
||||
#. Wheel is lossless. The first wheel implementation bdist_wheel
|
||||
always generates egg-info, and then converts it to a .whl. It is
|
||||
also possible to convert existing eggs and bdist_wininst
|
||||
distributions.
|
||||
#. Wheel is versioned. Every wheel file contains the version of the
|
||||
wheel specification and the implementation that packaged it.
|
||||
Hopefully the next migration can simply be to Wheel 2.0.
|
||||
#. Wheel is a reference to the other Python.
|
||||
|
@ -290,10 +297,10 @@ FAQ
|
|||
===
|
||||
|
||||
Wheel defines a .data directory. Should I put all my data there?
|
||||
No. The word 'data' is used only because it is short, and is only
|
||||
No. The word 'data' is used only because it is short, and is only
|
||||
meant to indicate files that are not installed into site-packages.
|
||||
This specification does not have an opinion on how you should organize
|
||||
your code.
|
||||
This specification does not have an opinion on how you should
|
||||
organize your code.
|
||||
|
||||
|
||||
Copyright
|
||||
|
@ -301,3 +308,13 @@ Copyright
|
|||
|
||||
This document has been placed into the public domain.
|
||||
|
||||
|
||||
|
||||
..
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
indent-tabs-mode: nil
|
||||
sentence-end-double-space: t
|
||||
fill-column: 70
|
||||
coding: utf-8
|
||||
End:
|
||||
|
|
Loading…
Reference in New Issue