Что такое wheel в python
Перейти к содержимому

Что такое wheel в python

  • автор:

pip wheel#

Build Wheel archives for your requirements and dependencies.

Wheel is a built-package format, and offers the advantage of not recompiling your software during every install. For more details, see the wheel docs: https://wheel.readthedocs.io/en/latest/

’pip wheel’ uses the build system interface as described here: https://pip.pypa.io/en/stable/reference/build-system/

Build System Interface

Differences to build #

build is a simple tool which can among other things build wheels for projects using PEP 517. It is comparable to the execution of pip wheel —no-deps . . It can also build source distributions which is not possible with pip . pip wheel covers the wheel scope of build but offers many additional features.

Options#

Build wheels into <dir>, where the default is the current working directory.

Do not use binary packages. Can be supplied multiple times, and each time adds to the existing value. Accepts either “:all:” to disable all binary packages, “:none:” to empty the set (notice the colons), or one or more package names with commas between them (no colons). Note that some packages are tricky to compile and may fail to install when this option is used on them.

Do not use source packages. Can be supplied multiple times, and each time adds to the existing value. Accepts either “:all:” to disable all source packages, “:none:” to empty the set, or one or more package names with commas between them. Packages without binary distributions will fail to install when this option is used on them.

Prefer older binary packages over newer source packages.

Disable isolation when building a modern source distribution. Build dependencies specified by PEP 518 must be already installed if this option is used.

Use PEP 517 for building source distributions (use —no-use-pep517 to force legacy behaviour).

Check the build dependencies when PEP517 is used.

-c , —constraint <file> #

Constrain versions using the given constraints file. This option can be used multiple times.

-e , —editable <path/url> #

Install a project in editable mode (i.e. setuptools “develop mode”) from a local project path or a VCS url.

-r , —requirement <file> #

Install from the given requirements file. This option can be used multiple times.

Directory to check out editable projects into. The default in a virtualenv is “<venv path>/src”. The default for global installs is “<current dir>/src”.

Ignore the Requires-Python information.

Don’t install package dependencies.

Specify whether the progress bar should be used [on, off] (default: on)

Don’t verify if built wheel is valid.

-C , —config-settings <settings> #

Configuration settings to be passed to the PEP 517 build backend. Settings take the form KEY=VALUE. Use multiple —config-settings options to pass multiple keys to the backend.

Extra arguments to be supplied to ‘setup.py bdist_wheel’.

Extra global options to be supplied to the setup.py call before the install or bdist_wheel command.

Include pre-release and development versions. By default, pip only finds stable versions.

Require a hash to check each requirement against, for repeatable installs. This option is implied when any package in a requirements file has a —hash option.

Don’t clean up build directories.

Base URL of the Python Package Index (default https://pypi.org/simple). This should point to a repository compliant with PEP 503 (the simple repository API) or a local directory laid out in the same format.

Extra URLs of package indexes to use in addition to —index-url. Should follow the same rules as —index-url.

Ignore package index (only looking at —find-links URLs instead).

If a URL or path to an html file, then parse for links to archives such as sdist (.tar.gz) or wheel (.whl) files. If a local path or file:// URL that’s a directory, then look for archives in the directory listing. Links to VCS project URLs are not supported.

Examples#

Build wheels for a requirement (and all its dependencies), and then install

Python на колёсах

Инфраструктура системы пакетов для Python долго подвергалась критике как от разработчиков, так и от системных администраторов. Долгое время даже само комьюнити не могло прийти к соглашению, какие именно инструменты использовать в каждом конкретном случае. Уже существуют distutils, setuptools, distribute, distutils2 в качестве базовых механизмов распространения и virtualenv, buildout, easy_install и pip в качестве высокоуровневых инструментов управления всем этим беспорядком.

До setuptools основным форматом распространения были исходные файлы или некоторые бинарные MSI-дистрибутивы для Windows. Под Linux были изначально сломанный bdist_dumb и bdist_rpm , который работал только на системах, основанных на Red Hat. Но даже bdist_rpm работал недостаточно хорошо для того, чтобы люди начали его использовать.

Несколько лет назад PJE попытался исправить эту проблему, предоставив смесь из setuptools и pkg_resources для улучшения distutils и добавления метаданных в Python-пакеты. В дополнение к этому он написал утилиту easy_install для их установки. По причине отсутствия формата распространения, поддерживающего метаданные, был предоставлен формат ‘яиц’ [egg].

Python eggs – обычные zip-архивы, содержащие python-пакет и необходимые метаданные. Хотя многие люди, вероятно, никогда намеренно не собирали egg’и, их формат метаданных до сих пор жив-здоров. И все разворачивают свои проекты с использованием setuptools.

К сожалению, некоторое время спустя сообщество разделилось, и часть его провозгласила смерть бинарных форматов и ‘яиц’ в частности. После этого pip, замена easy_install, перестал принимать egg-формат.

Потом прошло еще немного времени, и отказ от бинарных пакетов стал доставлять неудобства. Люди всё больше и больше стали деплоить на облачные сервера, а необходимость перекомпиляции C-шных библиотек на каждой машине не слишком радует. Так как ‘яйца’ на тот момент были малопонятны (я так полагаю), их переделали в новых PEP-ах, и назвали ‘колёсами’ [wheels].

В дальнейшем предполагается, что все действия происходят в virtualenv-окружении.

Что за колесо?

Начнём с простого. Что представляют собой ‘колёса’ и чем они отличаются от ‘яиц’? Оба формата являются zip-файлами. Главная разница в том, что egg можно импортировать без распаковки, wheel же придётся распаковать. Хотя нет никаких технических причин, делающих ‘колёса’ неимпортируемыми, поддержка их прямого импорта никогда даже не планировалась.

Другое различие в том, что ‘яйца’ содержат скомпилированные байткод, а ‘колёса’ – нет. Главное преимущество этого в том, что нет необходимости создавать отдельные wheel’ы для каждой версии Python до тех пор, пока не придётся распространять слинкованные через libpython модули. Хотя в новых версиях Python 3 при использовании стабильного ABI даже это уже можно провернуть.

Однако wheel-формат тоже не лишен проблем, некоторые из которых он наследует от ‘яиц’. Например, бинарные дистрибутивы под Linux до сих пор неприемлемы для большинства из-за двух недостатков: Python сам по себе компилируется под Linux в разных формах, и модули линкуются с разными системными библиотеками. Первая проблема вызвана сосуществованием несовместимых версий Python 2: USC2 и USC4. В зависимости от режима компиляции меняется ABI. В настоящее время wheel (насколько я могу судить) не содержит информации о том, с каким режимом Unicode связана библиотека. Отдельная проблема в том, что дистрибутивы Linux меньше совместимы между собой, чем хотелось бы, и обстоятельства могут сложиться так, что сборка, скомпилированная под один дистрибутив, не будет работать на остальных.

Всё это выливается в то, что, вообще говоря, на данный момент бинарные ‘колёса’ нельзя загружать на PyPI как несовместимые с различными системами.

В дополнение ко всему этому wheel сейчас знает только две крайности: бинарные пакеты и пакеты, содержащие чистый python-код. Бинарные пакеты специфичны для Python ветки 2.x. Сейчас это не кажется большой проблемой, потому что цикл 2.x подходит к концу, и пакетов, собранных только для 2.7, хватит надолго. Но если бы вдруг речь пошла про Python 2.8, была бы интересна возможность заявить, что этот пакет не зависит от версии Python, но он содержит бинарники, поэтому он не может не зависеть от архитектуры.

Единственный случай, оправдывающий существование такого пакета – это когда он содержит распределенные библиотеки, загружаемые с ctypes из CFFI. Такие библиотеки не связаны через libpython и не зависимы от реализации языка (их можно использовать даже с pypy).

Но есть и светлая сторона: ничто не запрещает использовать бинарные wheel’ы в своих собственных однородных инфраструктурах.

Сборка колеса

Итак, теперь мы знаем, что такое wheel. Как сделать своё собственное ‘колесо’? Сборка из собственных библиотек – простейший процесс. Всё, что нужно – свежая версия setuptools и библиотека wheel . Как только они оба установлены, ‘колесо’ собирается следующей командой:

Wheel будет создан в директории пакета. Однако есть одна вещь, которой следует опасаться: распространение бинарников. По умолчанию собираемое ‘колесо’ (при условии, что в setup.py не используется никаких бинарных шагов) состоит из pure-python кода. Это значит, что даже если распространять .so , .dylib или .dll как часть своего пакета, полученное ‘колесо’ будет выглядеть платформо-независимым.

Решение этой проблемы – вручную реализовать Distribution из setuptools, скинув флаг чистоты в false :

Установка колеса

С использованием свежей версии pip ‘колесо’ ставится следующим образом:

Но что с зависимостями? Тут появляются некоторые сложности. Обычно одним из требований к пакету является возможность его установки даже без подключения к интернету. К счастью, pip позволяет отключать загрузку из индекса и устанавливать директорию, содержащую всё необходимое для установки. Если у нас есть wheel’ы для всех зависимостей необходимых версий, можно сделать следующее:

Таким образом будет установлена версия 1.0 пакета package в наше виртуальное окружение.

Колёса для зависимостей

Окей, но что, если у нас нет .whl для всех наших зависимостей? Pip в теории позволяет решить эту проблему использованием команды wheel . Это должно работать как-то так:

Эта команда выгрузит все пакеты, от которых зависит наш пакет, в указанную папку. Но есть пара проблем.
Первая состоит в том, что в команде в настоящий момент есть баг, который не выгружает зависимости, которые уже являются ‘колёсами’. Так что если зависимость уже доступна на PyPI в wheel-формате, она не будет загружена.

Это временно решается shell-скриптом, который вручную перемещает из кэша скачанные wheel’ы.

Вторая проблема чуть серьёзней: как pip найдет наш собственный пакет, если его нет на PyPI? Правильно, никак. Документация в таком случае рекомендует использовать не pip wheel package , а pip wheel -r requirements.txt , где requirements.txt содержит все необходимые зависимости.

Сборка пакетов c использованием DevPI

Такое временное решение проблемы зависимостей вполне применимо в простых ситуациях, но что делать, если есть множество внутренних python-пакетов, зависящих друг от друга? Такая конструкция быстро разваливается.

К счастью, в прошлом году Holker Krekel создал решение этой беды под названием DevPI, который по существу является хаком, эмулирующим работу pip с PyPI. После установки на компьютер DevPI работает как прозрачный прокси перед PyPI и позволяет pip-у устанавливать пакеты из локального репозитория. К тому же все пакеты, скачанные с PyPI, автоматически кэшируются, так что даже если отключить сеть, эти пакеты будут доступны для установки. И, в конце концов, появляется возможность загрузки своих собственных пакетов на локальный сервер, чтобы ссылаться на них так же, как и на хранящиеся в публичном индексе.

Я рекомендую установить DevPI в локальный virtualenv, после чего добавить ссылки на devpi-server и devpi в PATH .

После этого остаётся просто запустить devpi-server , и он будет работать до ручной остановки.

После запуска его необходимо единожды проинициализировать:

Так как я использую DevPI ‘для себя’, имена пользователя DevPI и системного пользователя совпадают. На последнем шаге создаётся индекс по имени проекта (при необходимости можно создать несколько).

Для перенаправления pip на локальный репозиторий можно сделать экспорт переменной окружения:

Я размешаю эту команду в скрипт postactivate моего virtualenv для предотвращения случайной загрузки из неверного индекса.

Для размещения собственных wheel’ов в локальном DevPI используется утилита devpi :

Флаг —no-vcs отключает магию, которая пытается определить систему контроля версий и перемещает некоторые файлы в первую очередь. Мне это не нужно, так как в моих проектах распространяются файлы, которые я не включаю в VCS (бинарники, например).

Напоследок я настоятельно рекомендую разбить файлы setup.py таким образом, что PyPI их отвергнет, а DevPI примет, чтобы случайно не зарелизить свой код с помощью setup.py resease . Самый простой способ это сделать – добавить неверный классификатор PyPI:

Заворачиваем

Теперь всё готово для начала использования внутренних зависимостей и сборки собственных ‘колёс’. Как только они появятся, их можно заархивировать, загрузить на другой сервер и установить в отдельный virtualenv.
Весь процесс станет чуть проще, когда pip wheel перестанет игнорировать существующие wheel-пакеты. А пока приведенный выше shell-скрипт – не худшее решение.

В сравнении с ‘яйцами’

Сейчас wheel-формат более притягателен, чем egg. Его разработка активнее, PyPI начал добавлять его поддержку и, так как с ним начинают работать утилиты, он похож на лучшее решение. ‘Яйца’ пока что поддерживаются только easy_install, хотя большинство давно перешло на pip.

Я считаю, что сообщество Zope до сих пор крупнейшее из базирующихся на egg-формате и buildout. И я считаю, что если решение на основе ‘яиц’ в вашем случае применимо, его и стоит применять. Я знаю, что многие не используют eggs вовсе, предпочитая создавать virtualenv-ы, архивировать их и рассылать по разным серверам. Как раз для такого развёртывания wheels – лучшее решение, так как у разных серверов могут быть разные пути к библиотекам. Встречалась проблема, связанная с тем, что .pyc -файлы создавались на билд-сервере для virtualenv, а эти файлы содержат конкретные пути к файлам. С использованием wheel .pyc создаются после установки в виртуальное окружение и автоматически будут иметь корректные пути.

Итак, теперь он у вас есть. Python на колёсах. И это вроде даже работает, и, возможно, стоит потраченного времени.

Binary distribution format¶

The binary distribution format ( wheel ) was originally defined in PEP 427. The current version of the specification is here.

Abstract¶

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. Although a specialized installer is recommended, 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.

PEP Acceptance¶

This PEP was accepted, and the defined wheel version updated to 1.0, by Nick Coghlan on 16th February, 2013 1

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 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.

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’¶

Wheel installation notionally consists of two phases:

Check that installer is compatible with Wheel-Version. Warn if minor version is greater, abort if major version is greater.

If Root-Is-Purelib == ‘true’, unpack archive into purelib (site-packages).

Else unpack archive into platlib (site-packages).

Unpacked archive includes distribution-1.0.dist-info/ and (if there is data) distribution-1.0.data/ .

Move each subtree of distribution-1.0.data/ onto its destination path. Each subdirectory of distribution-1.0.data/ is a key into a dict of destination directories, such as distribution-1.0.data/(purelib|platlib|headers|scripts|data) . The initially supported paths are taken from distutils.command.install .

If applicable, update scripts starting with #!python to point to the correct interpreter.

Update distribution-1.0.dist-info/RECORD with the installed paths.

Remove empty distribution-1.0.data directory.

Compile any installed .py to .pyc. (Uninstallers should be smart enough to remove .pyc even if it is not mentioned in RECORD.)

Recommended installer features¶

In wheel, scripts are packaged in .data/scripts/ . If the first line of a file in scripts/ starts with exactly b’#!python’ , 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.

The b’#!pythonw’ convention is allowed. b’#!pythonw’ indicates a GUI script instead of a console script.

Generate script wrappers.

In wheel, scripts packaged on Unix systems will certainly not have accompanying .exe wrappers. Windows installers may want to add them during install.

Recommended archiver features¶

Archivers are encouraged to place the .dist-info 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.

File Format¶

File name convention¶

Distribution name, e.g. ‘django’, ‘pyramid’.

Distribution version, e.g. 1.0.

Optional build number. Must start with a digit. Acts as a tie-breaker if two wheel file names are the same in all other respects (i.e. name, version, and other tags). Sort as an empty tuple if unspecified, else sort as a two-item tuple with the first item being the initial digits as an int , and the second item being the remainder of the tag as a str .

language implementation and version tag

E.g. ‘py27’, ‘py2’, ‘py3’.

E.g. ‘cp33m’, ‘abi3’, ‘none’.

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.

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.

Escaping and Unicode¶

As the components of the filename are separated by a dash ( — , HYPHEN-MINUS), this character cannot appear within any component. This is handled as follows:

In distribution names, any run of -_. characters (HYPHEN-MINUS, LOW LINE and FULL STOP) should be replaced with _ (LOW LINE), and uppercase characters should be replaced with corresponding lowercase ones. This is equivalent to regular name normalization followed by replacing — with _ . Tools consuming wheels must be prepared to accept . (FULL STOP) and uppercase letters, however, as these were allowed by an earlier version of this specification.

Version numbers should be normalised according to PEP 440. Normalised version numbers cannot contain — .

The remaining components may not contain — characters, so no escaping is necessary.

Tools producing wheels should verify that the filename components do not contain — , as the resulting file may not be processed correctly if they do.

The archive filename is Unicode. It will be some time before the tools are updated to support non-ASCII filenames, but they are supported in this specification.

The filenames inside 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 zipfile .

File contents¶

The contents of a wheel file, where is replaced with the name of the package, e.g. beaglevote and is replaced with its version, e.g. 1.0.0 , consist of:

/ , the root of the archive, contains all files to be installed in purelib or platlib as specified in WHEEL . purelib and platlib are usually both site-packages .

.data/ 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. data , scripts , headers , purelib , platlib ).

Python scripts must appear in scripts and begin with exactly b’#!python’ in order to enjoy script wrapper generation and #!python rewriting at install time. They may have any or no extension.

.dist-info/METADATA is Metadata version 1.1 or greater format metadata.

.dist-info/WHEEL is metadata about the archive itself in the same basic key: value format:

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.

Tag is the wheel’s expanded compatibility tags; in the example the filename would contain py2.py3-none-any .

Build is the build number and is omitted if there is no build number.

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.

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.

This version of the wheel specification is based on the distutils install schemes and does not define how to install files to other locations. The layout offers a superset of the functionality provided by the existing wininst and egg binary formats.

The .dist-info directory¶

Wheel .dist-info directories include at a minimum METADATA, WHEEL, and RECORD.

METADATA is the package metadata, the same format as PKG-INFO as found at the root of sdists.

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.

PEP 376’s INSTALLER and REQUESTED are not included in the archive.

RECORD.jws is used for digital signatures. It is not mentioned in RECORD.

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.

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.

The .data directory¶

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:

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.

Signed wheel files¶

Wheel files include an extended RECORD that enables digital signatures. PEP 376’s RECORD is altered to include a secure hash 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 which cannot contain its own hash. For example:

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.

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:

(The hash value is the same format used in RECORD.)

If RECORD.p7s is used, it must contain a detached S/MIME format signature of RECORD.

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.

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 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.

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 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.

Wheel defines a .data directory. Should I put all my data there?¶

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 site-packages or on the PYTHONPATH. In other words, you may continue to use pkgutil.get_data(package, resource) even though those files will usually not be distributed in wheel’s .data directory.

Why does wheel include attached signatures?¶

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.

Why does wheel allow JWS signatures?¶

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.

Why does wheel also allow S/MIME signatures?¶

S/MIME signatures are allowed for users who need or want to use existing public key infrastructure with wheel.

Signed packages are only a basic building block in a secure package update system. Wheel only provides the building block.

What’s the deal with “purelib” vs. “platlib”?¶

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’.

A wheel with “Root-Is-Purelib: false” with all its files in .data/purelib 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.

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”.

Is it possible to import Python code directly from a wheel file?¶

Technically, due to the combination of supporting installation via simple extraction and using an archive format that is compatible with zipimport , a subset of wheel files do support being placed directly on sys.path . However, while this behaviour is a natural consequence of the format design, actually relying on it is generally discouraged.

Firstly, wheel is 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 pip and virtualenv 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).

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 not 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 __file__ 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.

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 do 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.

Changes¶

Since PEP 427, this specification has changed as follows:

The rules on escaping in wheel filenames were revised, to bring them into line with what popular tools actually do (February 2021).

Что такое wheel в python

Python wheels are a pre-built binary package format for Python modules and libraries. They are designed to make it easier to install and manage Python packages, by providing a convenient, single-file format that can be downloaded and installed without the need to compile the package from source code. They are designed to replace the older egg format and provide a number of benefits over eggs and other package formats, such as easier installation and better support for versioning and dependencies.

When you install a package provided in traditional .egg format the following steps are performed by the system.

  1. The system downloads a TAR file (tarball).
  2. The system builds a .whl file by calling setup.py
  3. The system installs the actual package after having built the wheel.

This process of downloading and compiling the tar file makes the whole process cumbersome and time-consuming.

What are the advantages of using Python Wheels?

One of the key advantages of using wheels is that they allow Python modules to be installed and used without requiring a build process. This means that users can simply download a wheel package and install it using the pip command, without needing to compile the package from the source code or install any additional dependencies. This can significantly speed up the installation process for large or complex Python packages.

Different types of Python Wheels

In the Python ecosystem, there are three main types of wheels:

Pure-python Wheels

These are built from source code that only depends on the Python Standard Library. They are platform-independent, meaning they can be installed on any system that has a compatible version of Python installed.

The following command is used for building a pure-python wheel from the setup.py of a package:

This will create a .whl file in the dist directory that can be installed on any platform with a compatible version of Python.

Universal Wheels

These are built from source code that depends on the Python Standard Library and additional, non-platform-specific dependencies. They are also platform-independent but may have additional dependencies that need to be installed alongside the wheel.

The following command is used for building a pure-python wheel from the setup.py of a package:

This will create a .whl file in the dist directory that can be installed on any platform with a compatible version of Python and the required dependencies.

Platform Wheels

These are built from source code that depends on the Python Standard Library and additional, platform-specific dependencies. They are not platform-independent, and can only be installed on systems that have the same platform as the one used to build the wheel.

The following command is used for building a pure-python wheel from the setup.py of a package:

This will create a .whl file in the dist directory that can only be installed on macOS systems with an Intel processor running version 10.6 or later.

Filename structure of Wheel

A sample structure of a wheel filename can be seen below:

In this format, the field specifies the name of the Python package, the field specifies the version of the package, the field specifies the build number of the package, the field specifies the version and implementation of Python used to build the package, the field specifies the Python ABI (Application Binary Interface) used, and the field specifies the platform-specific details of the package.

By using this universal naming scheme, wheels ensure that users can easily identify and install compatible packages on any version of Python that supports the wheel format. This makes it easier for developers to distribute their packages and for users to install them, without needing to worry about compatibility issues. Below is a list of some wheel filenames for the MySQL client.

  • mysqlclient-1.3.13-cp36-cp36m-win_amd64.whl
  • mysqlclient‑1.3.13‑cp36‑cp36m‑win32.whl

These two are the wheel files of the MySQL client of version 1.3.13 for different systems like `amd64`, and `win32` with a mere look at these filenames most technical users can easily understand which is the supported version for their system. To install a wheel package using pip, you can use the pip install command followed by the path to the wheel file.

Build a Wheel from Source Code

Suppose you want to create a wheel file from your source code. You can easily do the same by following the below procedure.

The contents of the source directory for a Python package will vary depending on the specifics of the package, but generally, it should include the following:

  • A setup.py file: This file is used to configure the package and its dependencies for installation.
  • The package source code: This will typically be organized into subdirectories based on the package’s modules and submodules.
  • Any necessary data files: If the package needs any data files (e.g. configuration files, sample data) for its operations, they should be included in the source directory.
  • A LICENSE file: This file should contain the license under which the package is distributed.
  • A README file: This file should provide an overview of the package, including its features and usage instructions.

Here is an example of the structure of a Python package source directory:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *