682 lines
52 KiB
HTML
682 lines
52 KiB
HTML
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="color-scheme" content="light dark">
|
||
<title>PEP 491 – The Wheel Binary Package Format 1.9 | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0491/">
|
||
<link rel="stylesheet" href="../_static/style.css" type="text/css">
|
||
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
|
||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
|
||
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
|
||
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
|
||
<meta property="og:title" content='PEP 491 – The Wheel Binary Package Format 1.9 | peps.python.org'>
|
||
<meta property="og:description" content="This PEP describes the second version of a built-package format for Python called “wheel”. Wheel provides a Python-specific, relocatable package format that allows people to install software more quickly and predictably than re-building from source eac...">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0491/">
|
||
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
|
||
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
|
||
<meta property="og:image:alt" content="Python PEPs">
|
||
<meta property="og:image:width" content="200">
|
||
<meta property="og:image:height" content="200">
|
||
<meta name="description" content="This PEP describes the second version of a built-package format for Python called “wheel”. Wheel provides a Python-specific, relocatable package format that allows people to install software more quickly and predictably than re-building from source eac...">
|
||
<meta name="theme-color" content="#3776ab">
|
||
</head>
|
||
<body>
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Following system colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="9"></circle>
|
||
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Selected dark colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Selected light colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="5"></circle>
|
||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||
</svg>
|
||
</symbol>
|
||
</svg>
|
||
<script>
|
||
|
||
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
|
||
</script>
|
||
<section id="pep-page-section">
|
||
<header>
|
||
<h1>Python Enhancement Proposals</h1>
|
||
<ul class="breadcrumbs">
|
||
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </li>
|
||
<li>PEP 491</li>
|
||
</ul>
|
||
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
|
||
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
|
||
</button>
|
||
</header>
|
||
<article>
|
||
<section id="pep-content">
|
||
<h1 class="page-title">PEP 491 – The Wheel Binary Package Format 1.9</h1>
|
||
<dl class="rfc2822 field-list simple">
|
||
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
||
<dd class="field-odd">Daniel Holth <dholth at gmail.com></dd>
|
||
<dt class="field-even">Discussions-To<span class="colon">:</span></dt>
|
||
<dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/distutils-sig@python.org/">Distutils-SIG list</a></dd>
|
||
<dt class="field-odd">Status<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><abbr title="Inactive draft that may be taken up again at a later time">Deferred</abbr></dd>
|
||
<dt class="field-even">Type<span class="colon">:</span></dt>
|
||
<dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
|
||
<dt class="field-odd">Topic<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><a class="reference external" href="../topic/packaging/">Packaging</a></dd>
|
||
<dt class="field-even">Created<span class="colon">:</span></dt>
|
||
<dd class="field-even">16-Apr-2015</dd>
|
||
</dl>
|
||
<hr class="docutils" />
|
||
<section id="contents">
|
||
<details><summary>Table of Contents</summary><ul class="simple">
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#pep-deferral">PEP Deferral</a></li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a></li>
|
||
<li><a class="reference internal" href="#details">Details</a><ul>
|
||
<li><a class="reference internal" href="#installing-a-wheel-distribution-1-0-py32-none-any-whl">Installing a wheel ‘distribution-1.0-py32-none-any.whl’</a><ul>
|
||
<li><a class="reference internal" href="#recommended-installer-features">Recommended installer features</a></li>
|
||
<li><a class="reference internal" href="#recommended-archiver-features">Recommended archiver features</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#file-format">File Format</a><ul>
|
||
<li><a class="reference internal" href="#file-name-convention">File name convention</a></li>
|
||
<li><a class="reference internal" href="#escaping-and-unicode">Escaping and Unicode</a></li>
|
||
<li><a class="reference internal" href="#file-contents">File contents</a><ul>
|
||
<li><a class="reference internal" href="#the-dist-info-directory">The .dist-info directory</a></li>
|
||
<li><a class="reference internal" href="#the-data-directory">The .data directory</a></li>
|
||
<li><a class="reference internal" href="#install-paths">Install paths</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#signed-wheel-files">Signed wheel files</a></li>
|
||
<li><a class="reference internal" href="#comparison-to-egg">Comparison to .egg</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#faq">FAQ</a><ul>
|
||
<li><a class="reference internal" href="#wheel-defines-a-data-directory-should-i-put-all-my-data-there">Wheel defines a .data directory. Should I put all my data there?</a></li>
|
||
<li><a class="reference internal" href="#why-does-wheel-include-attached-signatures">Why does wheel include attached signatures?</a></li>
|
||
<li><a class="reference internal" href="#why-does-wheel-allow-jws-signatures">Why does wheel allow JWS signatures?</a></li>
|
||
<li><a class="reference internal" href="#why-does-wheel-also-allow-s-mime-signatures">Why does wheel also allow S/MIME signatures?</a></li>
|
||
<li><a class="reference internal" href="#what-s-the-deal-with-purelib-vs-platlib">What’s the deal with “purelib” vs. “platlib”?</a></li>
|
||
<li><a class="reference internal" href="#is-it-possible-to-import-python-code-directly-from-a-wheel-file">Is it possible to import Python code directly from a wheel file?</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#appendix">Appendix</a></li>
|
||
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
||
</ul>
|
||
</details></section>
|
||
<section id="abstract">
|
||
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
|
||
<p>This PEP describes the second version of a built-package format for Python
|
||
called “wheel”. Wheel provides a Python-specific, relocatable package format
|
||
that allows people to install software more quickly and predictably than
|
||
re-building from source each time.</p>
|
||
<p>A wheel is a ZIP-format archive with a specially formatted file name and
|
||
the <code class="docutils literal notranslate"><span class="pre">.whl</span></code> extension. It contains a single distribution nearly as it
|
||
would be installed according to <a class="pep reference internal" href="../pep-0376/" title="PEP 376 – Database of Installed Python Distributions">PEP 376</a> with a particular installation
|
||
scheme. Simple wheels can be unpacked onto <code class="docutils literal notranslate"><span class="pre">sys.path</span></code> and used directly
|
||
but wheels are usually installed with a specialized installer.</p>
|
||
<p>This version of the wheel specification adds support for installing
|
||
distributions into many different directories, and adds a way to find
|
||
those files after they have been installed.</p>
|
||
</section>
|
||
<section id="pep-deferral">
|
||
<h2><a class="toc-backref" href="#pep-deferral" role="doc-backlink">PEP Deferral</a></h2>
|
||
<p>This PEP is not currently being actively pursued, with Python packaging
|
||
improvements currently focusing on the package build process rather than
|
||
expanding the binary archive format to cover additional use cases.</p>
|
||
<p>Some specific elements to be addressed when work on this PEP is resumed in the
|
||
future:</p>
|
||
<ul class="simple">
|
||
<li>migrating the official wheel format definition to
|
||
<a class="reference external" href="https://packaging.python.org/specifications/">https://packaging.python.org/specifications/</a> (similar to what <a class="pep reference internal" href="../pep-0566/" title="PEP 566 – Metadata for Python Software Packages 2.1">PEP 566</a> did for
|
||
<a class="reference external" href="https://packaging.python.org/specifications/core-metadata/">https://packaging.python.org/specifications/core-metadata/</a>)</li>
|
||
<li>updating the PEP itself to focus on the <em>changes</em> being made between the
|
||
two versions of the format and the rationale for those changes, rather than
|
||
having to repeat all the information that is unchanged from <a class="pep reference internal" href="../pep-0427/" title="PEP 427 – The Wheel Binary Package Format 1.0">PEP 427</a></li>
|
||
<li>clarifying that the PEP is deliberately written to allow existing installers
|
||
to be compliant with the specification when using existing install scheme
|
||
definitions, while also allowing the creation of new install scheme
|
||
definitions that take advantage of the richer categorisation scheme for
|
||
the contents of the binary archive</li>
|
||
</ul>
|
||
</section>
|
||
<section id="rationale">
|
||
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
|
||
<p>Wheel 1.0 is best at installing files into <code class="docutils literal notranslate"><span class="pre">site-packages</span></code> and a few
|
||
other locations specified by distutils, but users would like to install
|
||
files from single distribution into many directories – perhaps separate
|
||
locations for docs, data, and code. Unfortunately not everyone agrees
|
||
on where these install locations should be relative to the root directory.
|
||
This version of the format adds many more categories, each of which can be
|
||
installed to a different destination based on policy. Since it might
|
||
also be important to locate the installed files at runtime, this version
|
||
of the format also adds a way to record the installed paths in a way that
|
||
can be read by the installed software.</p>
|
||
</section>
|
||
<section id="details">
|
||
<h2><a class="toc-backref" href="#details" role="doc-backlink">Details</a></h2>
|
||
<section id="installing-a-wheel-distribution-1-0-py32-none-any-whl">
|
||
<h3><a class="toc-backref" href="#installing-a-wheel-distribution-1-0-py32-none-any-whl" role="doc-backlink">Installing a wheel ‘distribution-1.0-py32-none-any.whl’</a></h3>
|
||
<p>Wheel installation notionally consists of two phases:</p>
|
||
<ul class="simple">
|
||
<li>Unpack.<ol class="loweralpha simple">
|
||
<li>Parse <code class="docutils literal notranslate"><span class="pre">distribution-1.0.dist-info/WHEEL</span></code>.</li>
|
||
<li>Check that installer is compatible with Wheel-Version. Warn if
|
||
minor version is greater, abort if major version is greater.</li>
|
||
<li>If Root-Is-Purelib == ‘true’, unpack archive into purelib
|
||
(site-packages).</li>
|
||
<li>Else unpack archive into platlib (site-packages).</li>
|
||
</ol>
|
||
</li>
|
||
<li>Spread.<ol class="loweralpha simple">
|
||
<li>Unpacked archive includes <code class="docutils literal notranslate"><span class="pre">distribution-1.0.dist-info/</span></code> and (if
|
||
there is data) <code class="docutils literal notranslate"><span class="pre">distribution-1.0.data/</span></code>.</li>
|
||
<li>Move each subtree of <code class="docutils literal notranslate"><span class="pre">distribution-1.0.data/</span></code> onto its
|
||
destination path. Each subdirectory of <code class="docutils literal notranslate"><span class="pre">distribution-1.0.data/</span></code>
|
||
is a key into a dict of destination directories, such as
|
||
<code class="docutils literal notranslate"><span class="pre">distribution-1.0.data/(purelib|platlib|headers|scripts|data)</span></code>.</li>
|
||
<li>Update scripts starting with <code class="docutils literal notranslate"><span class="pre">#!python</span></code> to point to the correct
|
||
interpreter. (Note: Python scripts are usually handled by package
|
||
metadata, and not included verbatim in wheel.)</li>
|
||
<li>Update <code class="docutils literal notranslate"><span class="pre">distribution-1.0.dist.info/RECORD</span></code> with the installed
|
||
paths.</li>
|
||
<li>If empty, remove the <code class="docutils literal notranslate"><span class="pre">distribution-1.0.data</span></code> directory.</li>
|
||
<li>Compile any installed .py to .pyc. (Uninstallers should be smart
|
||
enough to remove .pyc even if it is not mentioned in RECORD.)</li>
|
||
</ol>
|
||
</li>
|
||
</ul>
|
||
<p>In practice, installers will usually extract files directly from the archive
|
||
to their destinations without writing a temporary <code class="docutils literal notranslate"><span class="pre">distribution-1.0.data/</span></code>
|
||
directory.</p>
|
||
<section id="recommended-installer-features">
|
||
<h4><a class="toc-backref" href="#recommended-installer-features" role="doc-backlink">Recommended installer features</a></h4>
|
||
<dl>
|
||
<dt>Rewrite <code class="docutils literal notranslate"><span class="pre">#!python</span></code>.</dt><dd>In wheel, verbatim scripts are packaged in
|
||
<code class="docutils literal notranslate"><span class="pre">{distribution}-{version}.data/scripts/</span></code>. If the first line of
|
||
a file in <code class="docutils literal notranslate"><span class="pre">scripts/</span></code> starts with exactly <code class="docutils literal notranslate"><span class="pre">b'#!python'</span></code>, rewrite to
|
||
point to the correct interpreter. Unix installers may need to add
|
||
the +x bit to these files if the archive was created on Windows.<p>The <code class="docutils literal notranslate"><span class="pre">b'#!pythonw'</span></code> convention is allowed. <code class="docutils literal notranslate"><span class="pre">b'#!pythonw'</span></code> indicates
|
||
a GUI script instead of a console script.</p>
|
||
</dd>
|
||
<dt>Generate script wrappers.</dt><dd>Python scripts are more commonly represented as a <code class="docutils literal notranslate"><span class="pre">module:callable</span></code>
|
||
string in package metadata, and are not included verbatim in the wheel
|
||
archive’s <code class="docutils literal notranslate"><span class="pre">scripts</span></code> directory. This kind of script gives the installer
|
||
an opportunity to generate platform specific wrappers.</dd>
|
||
</dl>
|
||
</section>
|
||
<section id="recommended-archiver-features">
|
||
<h4><a class="toc-backref" href="#recommended-archiver-features" role="doc-backlink">Recommended archiver features</a></h4>
|
||
<dl class="simple">
|
||
<dt>Place <code class="docutils literal notranslate"><span class="pre">.dist-info</span></code> at the end of the archive.</dt><dd>Archivers are encouraged to place the <code class="docutils literal notranslate"><span class="pre">.dist-info</span></code> files physically
|
||
at the end of the archive. This enables some potentially interesting
|
||
ZIP tricks including the ability to amend the metadata without
|
||
rewriting the entire archive.</dd>
|
||
</dl>
|
||
</section>
|
||
</section>
|
||
<section id="file-format">
|
||
<h3><a class="toc-backref" href="#file-format" role="doc-backlink">File Format</a></h3>
|
||
<section id="file-name-convention">
|
||
<h4><a class="toc-backref" href="#file-name-convention" role="doc-backlink">File name convention</a></h4>
|
||
<p>The wheel filename is <code class="docutils literal notranslate"><span class="pre">{distribution}-{version}(-{build</span>
|
||
<span class="pre">tag})?-{python</span> <span class="pre">tag}-{abi</span> <span class="pre">tag}-{platform</span> <span class="pre">tag}.whl</span></code>.</p>
|
||
<dl class="simple">
|
||
<dt>distribution</dt><dd>Distribution name, e.g. ‘django’, ‘pyramid’.</dd>
|
||
<dt>version</dt><dd>Distribution version, e.g. 1.0.</dd>
|
||
<dt>build tag</dt><dd>Optional build number. Must start with a digit. A tie breaker
|
||
if two wheels have the same version. Sort as the empty string
|
||
if unspecified, else sort the initial digits as a number, and the
|
||
remainder lexicographically.</dd>
|
||
<dt>language implementation and version tag</dt><dd>E.g. ‘py27’, ‘py2’, ‘py3’.</dd>
|
||
<dt>abi tag</dt><dd>E.g. ‘cp33m’, ‘abi3’, ‘none’.</dd>
|
||
<dt>platform tag</dt><dd>E.g. ‘linux_x86_64’, ‘any’.</dd>
|
||
</dl>
|
||
<p>For example, <code class="docutils literal notranslate"><span class="pre">distribution-1.0-1-py27-none-any.whl</span></code> 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.</p>
|
||
<p>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 <a class="pep reference internal" href="../pep-0425/" title="PEP 425 – Compatibility Tags for Built Distributions">PEP 425</a>.</p>
|
||
</section>
|
||
<section id="escaping-and-unicode">
|
||
<h4><a class="toc-backref" href="#escaping-and-unicode" role="doc-backlink">Escaping and Unicode</a></h4>
|
||
<p>Each component of the filename is escaped by replacing runs of
|
||
non-alphanumeric characters with an underscore <code class="docutils literal notranslate"><span class="pre">_</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="s2">"[^\w\d.]+"</span><span class="p">,</span> <span class="s2">"_"</span><span class="p">,</span> <span class="n">distribution</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">UNICODE</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The archive filename is Unicode. The packaging tools may only support
|
||
ASCII package names, but Unicode filenames are supported in this
|
||
specification.</p>
|
||
<p>The filenames <em>inside</em> the archive are encoded as UTF-8. Although some
|
||
ZIP clients in common use do not properly display UTF-8 filenames,
|
||
the encoding is supported by both the ZIP specification and Python’s
|
||
<code class="docutils literal notranslate"><span class="pre">zipfile</span></code>.</p>
|
||
</section>
|
||
<section id="file-contents">
|
||
<h4><a class="toc-backref" href="#file-contents" role="doc-backlink">File contents</a></h4>
|
||
<p>The contents of a wheel file, where {distribution} is replaced with the
|
||
name of the package, e.g. <code class="docutils literal notranslate"><span class="pre">beaglevote</span></code> and {version} is replaced with
|
||
its version, e.g. <code class="docutils literal notranslate"><span class="pre">1.0.0</span></code>, consist of:</p>
|
||
<ol class="arabic">
|
||
<li><code class="docutils literal notranslate"><span class="pre">/</span></code>, the root of the archive, contains all files to be installed in
|
||
<code class="docutils literal notranslate"><span class="pre">purelib</span></code> or <code class="docutils literal notranslate"><span class="pre">platlib</span></code> as specified in <code class="docutils literal notranslate"><span class="pre">WHEEL</span></code>. <code class="docutils literal notranslate"><span class="pre">purelib</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">platlib</span></code> are usually both <code class="docutils literal notranslate"><span class="pre">site-packages</span></code>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">{distribution}-{version}.dist-info/</span></code> contains metadata.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">{distribution}-{version}.data/</span></code> contains one subdirectory
|
||
for each non-empty install scheme key not already covered, where
|
||
the subdirectory name is an index into a dictionary of install paths
|
||
(e.g. <code class="docutils literal notranslate"><span class="pre">data</span></code>, <code class="docutils literal notranslate"><span class="pre">scripts</span></code>, <code class="docutils literal notranslate"><span class="pre">include</span></code>, <code class="docutils literal notranslate"><span class="pre">purelib</span></code>, <code class="docutils literal notranslate"><span class="pre">platlib</span></code>).</li>
|
||
<li>Python scripts must appear in <code class="docutils literal notranslate"><span class="pre">scripts</span></code> and begin with exactly
|
||
<code class="docutils literal notranslate"><span class="pre">b'#!python'</span></code> in order to enjoy script wrapper generation and
|
||
<code class="docutils literal notranslate"><span class="pre">#!python</span></code> rewriting at install time. They may have any or no
|
||
extension.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">{distribution}-{version}.dist-info/METADATA</span></code> is Metadata version 1.1
|
||
or greater format metadata.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">{distribution}-{version}.dist-info/WHEEL</span></code> is metadata about the archive
|
||
itself in the same basic key: value format:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Wheel</span><span class="o">-</span><span class="n">Version</span><span class="p">:</span> <span class="mf">1.9</span>
|
||
<span class="n">Generator</span><span class="p">:</span> <span class="n">bdist_wheel</span> <span class="mf">1.9</span>
|
||
<span class="n">Root</span><span class="o">-</span><span class="n">Is</span><span class="o">-</span><span class="n">Purelib</span><span class="p">:</span> <span class="n">true</span>
|
||
<span class="n">Tag</span><span class="p">:</span> <span class="n">py2</span><span class="o">-</span><span class="n">none</span><span class="o">-</span><span class="nb">any</span>
|
||
<span class="n">Tag</span><span class="p">:</span> <span class="n">py3</span><span class="o">-</span><span class="n">none</span><span class="o">-</span><span class="nb">any</span>
|
||
<span class="n">Build</span><span class="p">:</span> <span class="mi">1</span>
|
||
<span class="n">Install</span><span class="o">-</span><span class="n">Paths</span><span class="o">-</span><span class="n">To</span><span class="p">:</span> <span class="n">wheel</span><span class="o">/</span><span class="n">_paths</span><span class="o">.</span><span class="n">py</span>
|
||
<span class="n">Install</span><span class="o">-</span><span class="n">Paths</span><span class="o">-</span><span class="n">To</span><span class="p">:</span> <span class="n">wheel</span><span class="o">/</span><span class="n">_paths</span><span class="o">.</span><span class="n">json</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">Wheel-Version</span></code> is the version number of the Wheel specification.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">Generator</span></code> is the name and optionally the version of the software
|
||
that produced the archive.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">Root-Is-Purelib</span></code> is true if the top level directory of the archive
|
||
should be installed into purelib; otherwise the root should be installed
|
||
into platlib.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">Tag</span></code> is the wheel’s expanded compatibility tags; in the example the
|
||
filename would contain <code class="docutils literal notranslate"><span class="pre">py2.py3-none-any</span></code>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">Build</span></code> is the build number and is omitted if there is no build number.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">Install-Paths-To</span></code> is a location <em>relative to the archive</em> that will be
|
||
overwritten with the install-time paths of each category in the install
|
||
scheme. See the install paths section. May appear 0 or more times.</li>
|
||
<li>A wheel installer should warn if Wheel-Version is greater than the
|
||
version it supports, and must fail if Wheel-Version has a greater
|
||
major version than the version it supports.</li>
|
||
<li>Wheel, being an installation format that is intended to work across
|
||
multiple versions of Python, does not generally include .pyc files.</li>
|
||
<li>Wheel does not contain setup.py or setup.cfg.</li>
|
||
</ol>
|
||
<section id="the-dist-info-directory">
|
||
<h5><a class="toc-backref" href="#the-dist-info-directory" role="doc-backlink">The .dist-info directory</a></h5>
|
||
<ol class="arabic simple">
|
||
<li>Wheel .dist-info directories include at a minimum METADATA, WHEEL,
|
||
and RECORD.</li>
|
||
<li>METADATA is the package metadata, the same format as PKG-INFO as
|
||
found at the root of sdists.</li>
|
||
<li>WHEEL is the wheel metadata specific to a build of the package.</li>
|
||
<li>RECORD is a list of (almost) all the files in the wheel and their
|
||
secure hashes. Unlike <a class="pep reference internal" href="../pep-0376/" title="PEP 376 – Database of Installed Python Distributions">PEP 376</a>, 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.</li>
|
||
<li><a class="pep reference internal" href="../pep-0376/" title="PEP 376 – Database of Installed Python Distributions">PEP 376</a>’s INSTALLER and REQUESTED are not included in the archive.</li>
|
||
<li>RECORD.jws is used for digital signatures. It is not mentioned in
|
||
RECORD.</li>
|
||
<li>RECORD.p7s is allowed as a courtesy to anyone who would prefer to
|
||
use S/MIME signatures to secure their wheel files. It is not
|
||
mentioned in RECORD.</li>
|
||
<li>During extraction, wheel installers verify all the hashes in RECORD
|
||
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.</li>
|
||
</ol>
|
||
</section>
|
||
<section id="the-data-directory">
|
||
<h5><a class="toc-backref" href="#the-data-directory" role="doc-backlink">The .data directory</a></h5>
|
||
<p>Any file that is not normally installed inside site-packages goes into
|
||
the .data directory, named as the .dist-info directory but with the
|
||
.data/ extension:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">distribution</span><span class="o">-</span><span class="mf">1.0</span><span class="o">.</span><span class="n">dist</span><span class="o">-</span><span class="n">info</span><span class="o">/</span>
|
||
|
||
<span class="n">distribution</span><span class="o">-</span><span class="mf">1.0</span><span class="o">.</span><span class="n">data</span><span class="o">/</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The .data directory contains subdirectories with the scripts, headers,
|
||
documentation and so forth from the distribution. During installation the
|
||
contents of these subdirectories are moved onto their destination paths.</p>
|
||
<p>If a subdirectory is not found in the install scheme, the installer should
|
||
emit a warning, and it should be installed at <code class="docutils literal notranslate"><span class="pre">distribution-1.0.data/...</span></code>
|
||
as if the package was unpacked by a standard unzip tool.</p>
|
||
</section>
|
||
<section id="install-paths">
|
||
<h5><a class="toc-backref" href="#install-paths" role="doc-backlink">Install paths</a></h5>
|
||
<p>In addition to the distutils install paths, wheel now includes the listed
|
||
categories based on GNU autotools. This expanded scheme should help installers
|
||
to implement system policy, but installers may root each category at any
|
||
location.</p>
|
||
<p>A UNIX install scheme might map the categories to their installation paths
|
||
like this:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
|
||
<span class="s1">'bindir'</span><span class="p">:</span> <span class="s1">'$eprefix/bin'</span><span class="p">,</span>
|
||
<span class="s1">'sbindir'</span><span class="p">:</span> <span class="s1">'$eprefix/sbin'</span><span class="p">,</span>
|
||
<span class="s1">'libexecdir'</span><span class="p">:</span> <span class="s1">'$eprefix/libexec'</span><span class="p">,</span>
|
||
<span class="s1">'sysconfdir'</span><span class="p">:</span> <span class="s1">'$prefix/etc'</span><span class="p">,</span>
|
||
<span class="s1">'sharedstatedir'</span><span class="p">:</span> <span class="s1">'$prefix/com'</span><span class="p">,</span>
|
||
<span class="s1">'localstatedir'</span><span class="p">:</span> <span class="s1">'$prefix/var'</span><span class="p">,</span>
|
||
<span class="s1">'libdir'</span><span class="p">:</span> <span class="s1">'$eprefix/lib'</span><span class="p">,</span>
|
||
<span class="s1">'static_libdir'</span><span class="p">:</span> <span class="sa">r</span><span class="s1">'$prefix/lib'</span><span class="p">,</span>
|
||
<span class="s1">'includedir'</span><span class="p">:</span> <span class="s1">'$prefix/include'</span><span class="p">,</span>
|
||
<span class="s1">'datarootdir'</span><span class="p">:</span> <span class="s1">'$prefix/share'</span><span class="p">,</span>
|
||
<span class="s1">'datadir'</span><span class="p">:</span> <span class="s1">'$datarootdir'</span><span class="p">,</span>
|
||
<span class="s1">'mandir'</span><span class="p">:</span> <span class="s1">'$datarootdir/man'</span><span class="p">,</span>
|
||
<span class="s1">'infodir'</span><span class="p">:</span> <span class="s1">'$datarootdir/info'</span><span class="p">,</span>
|
||
<span class="s1">'localedir'</span><span class="p">:</span> <span class="s1">'$datarootdir/locale'</span><span class="p">,</span>
|
||
<span class="s1">'docdir'</span><span class="p">:</span> <span class="s1">'$datarootdir/doc/$dist_name'</span><span class="p">,</span>
|
||
<span class="s1">'htmldir'</span><span class="p">:</span> <span class="s1">'$docdir'</span><span class="p">,</span>
|
||
<span class="s1">'dvidir'</span><span class="p">:</span> <span class="s1">'$docdir'</span><span class="p">,</span>
|
||
<span class="s1">'psdir'</span><span class="p">:</span> <span class="s1">'$docdir'</span><span class="p">,</span>
|
||
<span class="s1">'pdfdir'</span><span class="p">:</span> <span class="s1">'$docdir'</span><span class="p">,</span>
|
||
<span class="s1">'pkgdatadir'</span><span class="p">:</span> <span class="s1">'$datadir/$dist_name'</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If a package needs to find its files at runtime, it can request
|
||
they be written to a specified file or files by the installer <em>and</em>
|
||
included in those same files inside the archive itself, relative
|
||
to their location within the archive (so a wheel is still installed
|
||
correctly if unpacked with a standard unzip tool, or perhaps not
|
||
unpacked at all).</p>
|
||
<p>If the <code class="docutils literal notranslate"><span class="pre">WHEEL</span></code> metadata contains these fields:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Install</span><span class="o">-</span><span class="n">Paths</span><span class="o">-</span><span class="n">To</span><span class="p">:</span> <span class="n">wheel</span><span class="o">/</span><span class="n">_paths</span><span class="o">.</span><span class="n">py</span>
|
||
<span class="n">Install</span><span class="o">-</span><span class="n">Paths</span><span class="o">-</span><span class="n">To</span><span class="p">:</span> <span class="n">wheel</span><span class="o">/</span><span class="n">_paths</span><span class="o">.</span><span class="n">json</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Then the wheel installer, when it is about to unpack <code class="docutils literal notranslate"><span class="pre">wheel/_paths.py</span></code> from
|
||
the archive, replaces it with the actual paths used at install time. The
|
||
paths may be absolute or relative to the generated file.</p>
|
||
<p>If the filename ends with <code class="docutils literal notranslate"><span class="pre">.py</span></code> then a Python script is written. The
|
||
script MUST be executed to get the paths, but it will probably look like
|
||
this:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">data</span><span class="o">=</span><span class="s1">'../wheel-0.26.0.dev1.data/data'</span>
|
||
<span class="n">headers</span><span class="o">=</span><span class="s1">'../wheel-0.26.0.dev1.data/headers'</span>
|
||
<span class="n">platlib</span><span class="o">=</span><span class="s1">'../wheel-0.26.0.dev1.data/platlib'</span>
|
||
<span class="n">purelib</span><span class="o">=</span><span class="s1">'../wheel-0.26.0.dev1.data/purelib'</span>
|
||
<span class="n">scripts</span><span class="o">=</span><span class="s1">'../wheel-0.26.0.dev1.data/scripts'</span>
|
||
<span class="c1"># ...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If the filename ends with <code class="docutils literal notranslate"><span class="pre">.json</span></code> then a JSON document is written:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span> <span class="s2">"data"</span><span class="p">:</span> <span class="s2">"../wheel-0.26.0.dev1.data/data"</span><span class="p">,</span> <span class="o">...</span> <span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Only the categories actually used by a particular wheel must be written to
|
||
this file.</p>
|
||
<p>These files are designed to be written to a location that can be found by the
|
||
installed package without introducing any dependency on a packaging library.</p>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
<section id="signed-wheel-files">
|
||
<h3><a class="toc-backref" href="#signed-wheel-files" role="doc-backlink">Signed wheel files</a></h3>
|
||
<p>Wheel files include an extended RECORD that enables digital
|
||
signatures. <a class="pep reference internal" href="../pep-0376/" title="PEP 376 – Database of Installed Python Distributions">PEP 376</a>’s RECORD is altered to include a secure hash
|
||
<code class="docutils literal notranslate"><span class="pre">digestname=urlsafe_b64encode_nopad(digest)</span></code> (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 which cannot contain its
|
||
own hash. For example:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">file</span><span class="o">.</span><span class="n">py</span><span class="p">,</span><span class="n">sha256</span><span class="o">=</span><span class="n">AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT</span>\<span class="n">_pNh2yI</span><span class="p">,</span><span class="mi">3144</span>
|
||
<span class="n">distribution</span><span class="o">-</span><span class="mf">1.0</span><span class="o">.</span><span class="n">dist</span><span class="o">-</span><span class="n">info</span><span class="o">/</span><span class="n">RECORD</span><span class="p">,,</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The signature file(s) RECORD.jws and RECORD.p7s are not mentioned in
|
||
RECORD at all since they can only be added after RECORD is generated.
|
||
Every other file in the archive must have a correct hash in RECORD
|
||
or the installation will fail.</p>
|
||
<p>If JSON web signatures are used, one or more JSON Web Signature JSON
|
||
Serialization (JWS-JS) signatures is stored in a file RECORD.jws adjacent
|
||
to RECORD. JWS is used to sign RECORD by including the SHA-256 hash of
|
||
RECORD as the signature’s JSON payload:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span> <span class="s2">"hash"</span><span class="p">:</span> <span class="s2">"sha256=ADD-r2urObZHcxBW3Cr-vDCu5RJwT4CaRTHiFmbcIYY"</span> <span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>(The hash value is the same format used in RECORD.)</p>
|
||
<p>If RECORD.p7s is used, it must contain a detached S/MIME format signature
|
||
of RECORD.</p>
|
||
<p>A wheel installer is not required to understand digital signatures but
|
||
MUST verify the hashes in RECORD against the extracted file contents.
|
||
When the installer checks file hashes against RECORD, a separate signature
|
||
checker only needs to establish that RECORD matches the signature.</p>
|
||
<p>See</p>
|
||
<ul class="simple">
|
||
<li><span class="target" id="index-0"></span><a class="rfc reference external" href="https://datatracker.ietf.org/doc/html/rfc7515.html"><strong>RFC 7515</strong></a></li>
|
||
<li><a class="reference external" href="https://datatracker.ietf.org/doc/html/draft-jones-jose-jws-json-serialization.html">https://datatracker.ietf.org/doc/html/draft-jones-jose-jws-json-serialization.html</a></li>
|
||
<li><span class="target" id="index-1"></span><a class="rfc reference external" href="https://datatracker.ietf.org/doc/html/rfc7517.html"><strong>RFC 7517</strong></a></li>
|
||
<li><a class="reference external" href="https://datatracker.ietf.org/doc/html/draft-jones-jose-json-private-key.html">https://datatracker.ietf.org/doc/html/draft-jones-jose-json-private-key.html</a></li>
|
||
</ul>
|
||
</section>
|
||
<section id="comparison-to-egg">
|
||
<h3><a class="toc-backref" href="#comparison-to-egg" role="doc-backlink">Comparison to .egg</a></h3>
|
||
<ol class="arabic simple">
|
||
<li>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
|
||
wait for the packager to catch up.</li>
|
||
<li>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.</li>
|
||
<li>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.</li>
|
||
<li>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.</li>
|
||
<li>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.</li>
|
||
<li>Wheel is a reference to the other Python.</li>
|
||
</ol>
|
||
</section>
|
||
</section>
|
||
<section id="faq">
|
||
<h2><a class="toc-backref" href="#faq" role="doc-backlink">FAQ</a></h2>
|
||
<section id="wheel-defines-a-data-directory-should-i-put-all-my-data-there">
|
||
<h3><a class="toc-backref" href="#wheel-defines-a-data-directory-should-i-put-all-my-data-there" role="doc-backlink">Wheel defines a .data directory. Should I put all my data there?</a></h3>
|
||
<blockquote>
|
||
<div>This specification does not have an opinion on how you should organize
|
||
your code. The .data directory is just a place for any files that are
|
||
not normally installed inside <code class="docutils literal notranslate"><span class="pre">site-packages</span></code> or on the PYTHONPATH.
|
||
In other words, you may continue to use <code class="docutils literal notranslate"><span class="pre">pkgutil.get_data(package,</span>
|
||
<span class="pre">resource)</span></code> even though <em>those</em> files will usually not be distributed
|
||
in <em>wheel’s</em> <code class="docutils literal notranslate"><span class="pre">.data</span></code> directory.</div></blockquote>
|
||
</section>
|
||
<section id="why-does-wheel-include-attached-signatures">
|
||
<h3><a class="toc-backref" href="#why-does-wheel-include-attached-signatures" role="doc-backlink">Why does wheel include attached signatures?</a></h3>
|
||
<blockquote>
|
||
<div>Attached signatures are more convenient than detached signatures
|
||
because they travel with the archive. Since only the individual files
|
||
are signed, the archive can be recompressed without invalidating
|
||
the signature or individual files can be verified without having
|
||
to download the whole archive.</div></blockquote>
|
||
</section>
|
||
<section id="why-does-wheel-allow-jws-signatures">
|
||
<h3><a class="toc-backref" href="#why-does-wheel-allow-jws-signatures" role="doc-backlink">Why does wheel allow JWS signatures?</a></h3>
|
||
<blockquote>
|
||
<div>The JOSE specifications of which JWS is a part are designed to be easy
|
||
to implement, a feature that is also one of wheel’s primary design
|
||
goals. JWS yields a useful, concise pure-Python implementation.</div></blockquote>
|
||
</section>
|
||
<section id="why-does-wheel-also-allow-s-mime-signatures">
|
||
<h3><a class="toc-backref" href="#why-does-wheel-also-allow-s-mime-signatures" role="doc-backlink">Why does wheel also allow S/MIME signatures?</a></h3>
|
||
<blockquote>
|
||
<div>S/MIME signatures are allowed for users who need or want to use
|
||
existing public key infrastructure with wheel.<p>Signed packages are only a basic building block in a secure package
|
||
update system. Wheel only provides the building block.</p>
|
||
</div></blockquote>
|
||
</section>
|
||
<section id="what-s-the-deal-with-purelib-vs-platlib">
|
||
<h3><a class="toc-backref" href="#what-s-the-deal-with-purelib-vs-platlib" role="doc-backlink">What’s the deal with “purelib” vs. “platlib”?</a></h3>
|
||
<blockquote>
|
||
<div>Wheel preserves the “purelib” vs. “platlib” distinction, which is
|
||
significant on some platforms. For example, Fedora installs pure
|
||
Python packages to ‘/usr/lib/pythonX.Y/site-packages’ and platform
|
||
dependent packages to ‘/usr/lib64/pythonX.Y/site-packages’.<p>A wheel with “Root-Is-Purelib: false” with all its files
|
||
in <code class="docutils literal notranslate"><span class="pre">{name}-{version}.data/purelib</span></code> is equivalent to a wheel with
|
||
“Root-Is-Purelib: true” with those same files in the root, and it
|
||
is legal to have files in both the “purelib” and “platlib” categories.</p>
|
||
<p>In practice a wheel should have only one of “purelib” or “platlib”
|
||
depending on whether it is pure Python or not and those files should
|
||
be at the root with the appropriate setting given for “Root-is-purelib”.</p>
|
||
</div></blockquote>
|
||
</section>
|
||
<section id="is-it-possible-to-import-python-code-directly-from-a-wheel-file">
|
||
<h3><a class="toc-backref" href="#is-it-possible-to-import-python-code-directly-from-a-wheel-file" role="doc-backlink">Is it possible to import Python code directly from a wheel file?</a></h3>
|
||
<blockquote>
|
||
<div>Technically, due to the combination of supporting installation via
|
||
simple extraction and using an archive format that is compatible with
|
||
<code class="docutils literal notranslate"><span class="pre">zipimport</span></code>, a subset of wheel files <em>do</em> support being placed directly
|
||
on <code class="docutils literal notranslate"><span class="pre">sys.path</span></code>. However, while this behaviour is a natural consequence
|
||
of the format design, actually relying on it is generally discouraged.<p>Firstly, wheel <em>is</em> designed primarily as a distribution format, so
|
||
skipping the installation step also means deliberately avoiding any
|
||
reliance on features that assume full installation (such as being able
|
||
to use standard tools like <code class="docutils literal notranslate"><span class="pre">pip</span></code> and <code class="docutils literal notranslate"><span class="pre">virtualenv</span></code> to capture and
|
||
manage dependencies in a way that can be properly tracked for auditing
|
||
and security update purposes, or integrating fully with the standard
|
||
build machinery for C extensions by publishing header files in the
|
||
appropriate place).</p>
|
||
<p>Secondly, while some Python software is written to support running
|
||
directly from a zip archive, it is still common for code to be written
|
||
assuming it has been fully installed. When that assumption is broken
|
||
by trying to run the software from a zip archive, the failures can often
|
||
be obscure and hard to diagnose (especially when they occur in third
|
||
party libraries). The two most common sources of problems with this
|
||
are the fact that importing C extensions from a zip archive is <em>not</em>
|
||
supported by CPython (since doing so is not supported directly by the
|
||
dynamic loading machinery on any platform) and that when running from
|
||
a zip archive the <code class="docutils literal notranslate"><span class="pre">__file__</span></code> attribute no longer refers to an
|
||
ordinary filesystem path, but to a combination path that includes
|
||
both the location of the zip archive on the filesystem and the
|
||
relative path to the module inside the archive. Even when software
|
||
correctly uses the abstract resource APIs internally, interfacing with
|
||
external components may still require the availability of an actual
|
||
on-disk file.</p>
|
||
<p>Like metaclasses, monkeypatching and metapath importers, if you’re not
|
||
already sure you need to take advantage of this feature, you almost
|
||
certainly don’t need it. If you <em>do</em> decide to use it anyway, be
|
||
aware that many projects will require a failure to be reproduced with
|
||
a fully installed package before accepting it as a genuine bug.</p>
|
||
</div></blockquote>
|
||
</section>
|
||
</section>
|
||
<section id="appendix">
|
||
<h2><a class="toc-backref" href="#appendix" role="doc-backlink">Appendix</a></h2>
|
||
<p>Example urlsafe-base64-nopad implementation:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># urlsafe-base64-nopad for Python 3</span>
|
||
<span class="kn">import</span> <span class="nn">base64</span>
|
||
|
||
<span class="k">def</span> <span class="nf">urlsafe_b64encode_nopad</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="n">base64</span><span class="o">.</span><span class="n">urlsafe_b64encode</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="sa">b</span><span class="s1">'='</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">urlsafe_b64decode_nopad</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
|
||
<span class="n">pad</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">'='</span> <span class="o">*</span> <span class="p">(</span><span class="mi">4</span> <span class="o">-</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o">&</span> <span class="mi">3</span><span class="p">))</span>
|
||
<span class="k">return</span> <span class="n">base64</span><span class="o">.</span><span class="n">urlsafe_b64decode</span><span class="p">(</span><span class="n">data</span> <span class="o">+</span> <span class="n">pad</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="copyright">
|
||
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
|
||
<p>This document has been placed into the public domain.</p>
|
||
</section>
|
||
</section>
|
||
<hr class="docutils" />
|
||
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0491.rst">https://github.com/python/peps/blob/main/peps/pep-0491.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0491.rst">2023-09-09 17:39:29 GMT</a></p>
|
||
|
||
</article>
|
||
<nav id="pep-sidebar">
|
||
<h2>Contents</h2>
|
||
<ul>
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#pep-deferral">PEP Deferral</a></li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a></li>
|
||
<li><a class="reference internal" href="#details">Details</a><ul>
|
||
<li><a class="reference internal" href="#installing-a-wheel-distribution-1-0-py32-none-any-whl">Installing a wheel ‘distribution-1.0-py32-none-any.whl’</a><ul>
|
||
<li><a class="reference internal" href="#recommended-installer-features">Recommended installer features</a></li>
|
||
<li><a class="reference internal" href="#recommended-archiver-features">Recommended archiver features</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#file-format">File Format</a><ul>
|
||
<li><a class="reference internal" href="#file-name-convention">File name convention</a></li>
|
||
<li><a class="reference internal" href="#escaping-and-unicode">Escaping and Unicode</a></li>
|
||
<li><a class="reference internal" href="#file-contents">File contents</a><ul>
|
||
<li><a class="reference internal" href="#the-dist-info-directory">The .dist-info directory</a></li>
|
||
<li><a class="reference internal" href="#the-data-directory">The .data directory</a></li>
|
||
<li><a class="reference internal" href="#install-paths">Install paths</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#signed-wheel-files">Signed wheel files</a></li>
|
||
<li><a class="reference internal" href="#comparison-to-egg">Comparison to .egg</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#faq">FAQ</a><ul>
|
||
<li><a class="reference internal" href="#wheel-defines-a-data-directory-should-i-put-all-my-data-there">Wheel defines a .data directory. Should I put all my data there?</a></li>
|
||
<li><a class="reference internal" href="#why-does-wheel-include-attached-signatures">Why does wheel include attached signatures?</a></li>
|
||
<li><a class="reference internal" href="#why-does-wheel-allow-jws-signatures">Why does wheel allow JWS signatures?</a></li>
|
||
<li><a class="reference internal" href="#why-does-wheel-also-allow-s-mime-signatures">Why does wheel also allow S/MIME signatures?</a></li>
|
||
<li><a class="reference internal" href="#what-s-the-deal-with-purelib-vs-platlib">What’s the deal with “purelib” vs. “platlib”?</a></li>
|
||
<li><a class="reference internal" href="#is-it-possible-to-import-python-code-directly-from-a-wheel-file">Is it possible to import Python code directly from a wheel file?</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#appendix">Appendix</a></li>
|
||
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
||
</ul>
|
||
|
||
<br>
|
||
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0491.rst">Page Source (GitHub)</a>
|
||
</nav>
|
||
</section>
|
||
<script src="../_static/colour_scheme.js"></script>
|
||
<script src="../_static/wrap_tables.js"></script>
|
||
<script src="../_static/sticky_banner.js"></script>
|
||
</body>
|
||
</html> |