Formato de distribuição binária¶
This page specifies the binary distribution format for Python packages, also called the wheel format.
Um wheel é um arquivo em formato ZIP com um nome de arquivo formatado de forma especial e a extensão .whl. Ele contém uma única distribuição quase como seria instalado de acordo com a PEP 376 com um esquema de instalação particular. Embora um instalador especializado seja recomendado, um arquivo wheel pode ser instalado simplesmente descompactando em pacotes de sites com a ferramenta padrão de “descompactação” enquanto preserva informações suficientes para espalhar seu conteúdo em seus caminhos finais a qualquer momento.
Detalhes¶
Instalando um wheel ‘distribution-1.0-py32-none-any.whl’¶
A instalação do wheel consiste, em teoria, em duas fases:
Desempacotar.
Analisar
distribution-1.0.dist-info/WHEEL.Verificar se o instalador é compatível com a versão Wheel. Avisa se a versão secundária é maior, cancela se a versão principal é maior.
Se Root-Is-Purelib == ‘true’, descompactar o arquivo em purelib (sites-packages).
Caso contrário, descompactar o arquivo em platlib (site-packages).
Espalhar.
O arquivo descompactado inclui
distribution-1.0.dist-info/e (se houver dados)distribution-1.0.data/.Move each subtree of
distribution-1.0.data/onto its destination path. Each subdirectory ofdistribution-1.0.data/is a key into a dict of destination directories, such asdistribution-1.0.data/(purelib|platlib|headers|scripts|data). These subdirectories are installation paths defined by sysconfig.Se aplicável, atualizar os scripts começando com
#!pythonpara apontar para o interpretador correto.Atualizar
distribution-1.0.dist-info/RECORDcom os caminhos instalados.Remover o diretório vazio
distribution-1.0.data.Compilar qualquer .py instalado em .pyc. (Os desinstaladores devem ser inteligentes o suficiente para remover .pyc, mesmo que não seja mencionado em RECORD.)
Recursos de instalador recomendados¶
- Reescrever
#!python. No wheel, os scripts são empacotados em
{distribution}-{version}.data/scripts/. Se a primeira linha de um arquivo emscripts/começar exatamente comb'#!python', reescreva para apontar para o interpretador correto. Os instaladores do Unix podem precisar adicionar o bit +x a esses arquivos se o arquivo tiver sido criado em Windows.A convenção
b'#!pythonw'é permitida.b'#!pythonw'indica um script GUI ao invés de um script de console.- Gerar script wrappers.
No wheel, scripts empacotados em sistemas Unix certamente não serão acompanhados de wrappers .exe. Os instaladores Windows podem querer adicioná-los durante a instalação.
Recursos de arquivador recomendados¶
- Colocar
.dist-infono final do arquivo. Os arquivadores são encorajados a colocar os arquivos
.dist-infofisicamente no final do repositório. Isso permite alguns truques de ZIP potencialmente interessantes, incluindo a capacidade de corrigir os metadados sem reescrever todo o arquivo.
Formato de arquivos¶
Convenção de nome de arquivos¶
O nome de arquivo do wheel é {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl.
- distribution
Nome da distribuição (p.ex., ‘django’, ‘pyramid’).
- version
Versão da distribuição (p.ex., 1.0).
- build tag
Número de construção opcional. Deve começar com um dígito. Atua como um desempate se os nomes de arquivo de dois wheels forem iguais em todos os outros aspectos (ou seja, nome, versão e outras tags). Classifique como uma tupla vazia se não for especificado, caso contrário, classifique como uma tupla de dois itens com o primeiro item sendo os dígitos iniciais como um
int, e o segundo item sendo o restante da tag como umstr.Um caso de uso comum para números de construção é reconstruir uma distribuição binária devido a uma mudança no ambiente de construção, como ao usar a imagem manylinux para construir distribuições usando versões de pré-lançamento do CPython.
Aviso
Os números de construção não fazem parte da versão de distribuição e, portanto, são difíceis de se referir externamente, especialmente fora do ecossistema do Python de ferramentas e padrões. Um caso comum em que uma distribuição precisa ser referenciada externamente é quando se resolve uma vulnerabilidade de segurança.
Devido a esta limitação, novas distribuições que precisam ser referenciadas externamente não devem usar números de construção ao construir a nova distribuição. Em vez disso, deve ser criada uma nova versão de distribuição para esses casos.
- implementação da linguagem e tag de versão
p.ex., ‘py27’, ‘py2’, ‘py3’.
- abi tag
p.ex., ‘cp33m’, ‘abi3’, ‘none’.
- platform tag
p.ex., ‘linux_x86_64’, ‘any’.
Por exemplo, distribution-1.0-1-py27-none-any.whl é a primeira construção de um pacote chamado ‘distribution’ e é compatível com Python 2.7 (qualquer implementação Python 2.7), com sem ABI (puro Python), em qualquer arquitetura de CPU.
Os últimos três componentes do nome do arquivo antes da extensão são chamados de “tags de compatibilidade”. As tags de compatibilidade expressam os requisitos básicos do interpretador do pacote e são detalhadas na PEP 425.
Escape e Unicode¶
Como os componentes do nome do arquivo são separados por um traço (-, HYPHEN-MINUS), este caractere não pode aparecer em nenhum componente. Isso é tratado da seguinte maneira:
Em nomes de distribuição, qualquer ocorrência de caracteres
-_.(HYPHEN-MINUS, LOW LINE e FULL STOP) deve ser substituída por_(LOW LINE) e caracteres maiúsculos devem ser substituídos pelos minúsculos correspondentes. Isso é equivalente à normalização de nome regular da PEP 503 seguida pela substituição de-por_. Porém, ferramentas que usem wheels devem estar preparadas para aceitar.(FULL STOP) e letras maiúsculas, pois estes eram permitidos por uma versão anterior desta especificação.Os números de versão devem ser normalizados de acordo com a especificação de especificadores de versão. Os números de versão normalizados não podem conter
-.Os componentes restantes não podem conter caracteres
-, portanto, nenhum escape é necessário.
Ferramentas que produzem wheels devem verificar se os componentes do nome de arquivo não contêm -, pois o arquivo resultante pode não ser processado corretamente se contiverem.
O nome do arquivo é Unicode. Levará algum tempo até que as ferramentas sejam atualizadas para oferecer suporte a nomes de arquivos não ASCII, mas eles são suportados nesta especificação.
Os nomes de arquivos dentro do arquivo são codificados como UTF-8. Embora alguns clientes ZIP em uso comum não exibam nomes de arquivo UTF-8 apropriadamente, a codificação é suportada pela especificação ZIP e pelo zipfile do Python.
Conteúdo dos arquivos¶
The contents of a wheel file, where {distribution} is replaced with the
normalized name of the package, e.g.
beaglevote and {version} is replaced
with its normalized version,
e.g. 1.0.0, (with dash/- characters replaced with underscore/_ characters
in both fields) consist of:
/, a raiz do arquivo, contém todos os arquivos a serem instalados empurelibouplatlibconforme especificado emWHEEL.purelibeplatlibsão normalmentesite-packages.{distribution}-{version}.dist-info/contém metadados.distribution-version.dist-info/licenses/contains license files.{distribution}-{version}.data/contém um subdiretório para cada chave de esquema de instalação não vazia ainda não coberta, onde o nome do subdiretório é um índice em um dicionário de caminhos de instalação (p.ex.,data,scripts,headers,purelib,platlib).Python scripts must appear in
scriptsand begin with exactlyb'#!python'in order to enjoy script wrapper generation and#!pythonrewriting at install time. They may have any or no extension. Thescriptsdirectory may only contain regular files.{distribution}-{version}.dist-info/METADATAé Metadata versão 1.1 ou metadados de formato superior.{distribution}-{version}.dist-info/WHEELsão metadados sobre p arquivo em si no mesmo formato “chave: valor”:Wheel-Version: 1.0 Generator: bdist_wheel 1.0 Root-Is-Purelib: true Tag: py2-none-any Tag: py3-none-any Build: 1
Wheel-Versioné o número de versão da especificação Wheel.Generatoré o nome e, opcionalmente, a versão do software que produziu o arquivo.Root-Is-Purelibé verdadeiro se o diretório de nível superior do arquivo deve ser instalado em purelib; caso contrário, a raiz deve ser instalada no platlib.Tagsão as tags de compatibilidade expandida do wheel; no exemplo, o nome do arquivo conteriapy2.py3-none-any.Buildé o número da construção e é omitido se não houver número da construção.Um instalador de wheel deve avisar se Wheel-Version é maior do que a versão que ele suporta, e deve falhar se Wheel-Version tiver uma versão principal maior do que a versão que ele suporta.
O Wheel, sendo um formato de instalação destinado a funcionar em várias versões do Python, geralmente não inclui arquivos .pyc.
Wheel não contém setup.py ou setup.cfg.
Esta versão da especificação do wheel é baseada nos esquemas de instalação do distutils e não define como instalar arquivos em outros locais. O layout oferece um superconjunto da funcionalidade fornecida pelos formatos binários wininst e egg existentes.
O diretório .dist-info¶
Os diretórios .dist-info de wheels incluem no mínimo METADATA, WHEEL e RECORD.
METADATA são os metadados do pacote, o mesmo formato do PKG-INFO encontrado na raiz dos sdists.
WHEEL são os metadados de wheel específicos para uma construção do pacote.
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.
INSTALLER e REQUESTED da PEP 376 não são incluídos no arquivo.
RECORD.jws and RECORD.p7s are deprecated. Where they are still used, neither RECORD.jws nor RECORD.p7s are mentioned in RECORD. Build backends and other tools must not add them to wheels anymore, installers should be aware that these files may still be part of some wheels.
During extraction, wheel installers verify all the hashes in RECORD against the file contents. Apart from RECORD, RECORD.jws and RECORD.p7s, installation will fail if any file in the archive is not both mentioned and correctly hashed in RECORD.
Subdirectories in .dist-info/¶
Subdirectories under .dist-info/ are reserved for future use.
The following subdirectory names under .dist-info/ are reserved for specific usage:
Subdirectory name |
PEP / Standard |
|---|---|
|
|
|
|
|
|
|
The .dist-info/licenses/ directory¶
If the metadata version is 2.4 or greater and one or more License-File
fields is specified, the .dist-info/ directory MUST contain a
licenses/ subdirectory, which MUST contain the files listed in the
License-File fields in the METADATA file at their respective paths
relative to the licenses/ directory.
The .dist-info/sboms/ directory¶
All files contained within the .dist-info/sboms/ directory MUST
be Software Bill-of-Materials (SBOM) files that describe software contained
within the distribution archive.
O diretório .data¶
Qualquer arquivo que não é normalmente instalado dentro de site-packages vai para o diretório .data, nomeado como o diretório .dist-info, mas com a extensão .data/:
distribution-1.0.dist-info/
distribution-1.0.data/
O diretório .data contém subdiretórios com os scripts, cabeçalhos, documentação e assim por diante da distribuição. Durante a instalação, o conteúdo desses subdiretórios é movido para seus caminhos de destino.
FAQ¶
Wheel define um diretório .data. Devo colocar todos os meus dados lá?¶
Esta especificação não tem uma opinião sobre como você deve organizar seu código. O diretório .data é apenas um lugar para quaisquer arquivos que não são normalmente instalados dentro de
site-packagesou no PYTHONPATH. Em outras palavras, você pode continuar a usarpkgutil.get_data(package, resource)ainda que esses arquivos normalmente não sejam distribuídos no diretório.datado wheel.
Qual é a diferença entre “purelib” e “platlib”?¶
O Wheel preserva a distinção “purelib” vs. “platlib”, que é significativa em algumas plataformas. Por exemplo, o Fedora instala pacotes puro Python em ‘/usr/lib/pythonX.Y/site-packages’ e pacotes dependentes de plataforma em ‘/usr/lib64/pythonX.Y/site-packages’.
Um wheel com “Root-Is-Purelib: false” com todos os seus arquivos em
{nome}-{versão}.data/purelibé equivalente a um wheel com “Root-Is-Purelib: true” com os mesmos arquivos na raiz, e é válido ter arquivos nas categorias “purelib” e “platlib”.Na prática, um wheel deve ter apenas um de “purelib” ou “platlib” dependendo se é puro Python ou não e esses arquivos devem estar na raiz com a configuração apropriada fornecida para “Root-is-purelib”.
É possível importar código Python diretamente de um arquivo wheel?¶
Tecnicamente, devido à combinação de suporte de instalação via extração simples e usando um formato de arquivo compatível com
zipimport, um subconjunto de arquivos wheel oferece suporte a ser colocado diretamente nosys.path. No entanto, embora esse comportamento seja uma consequência natural do design do formato, não é recomendável confiar nele.Em primeiro lugar, o wheel é projetado principalmente como um formato de distribuição, então pular a etapa de instalação também significa evitar deliberadamente qualquer dependência de recursos que pressupõem a instalação completa (como ser capaz de usar ferramentas padrão como
pipevirtualenvpara capturar e gerenciar dependências de uma forma que possam ser devidamente rastreadas para fins de auditoria e atualização de segurança, ou integração completa com o maquinário de construção padrão para extensões C, publicando arquivos de cabeçalho no local apropriado).Em segundo lugar, embora alguns softwares Python sejam escritos para suportar a execução direta de um arquivo zip, ainda é comum que o código seja escrito assumindo que foi totalmente instalado. Quando essa suposição é quebrada ao tentar executar o software a partir de um arquivo zip, as falhas podem frequentemente ser obscuras e difíceis de diagnosticar (especialmente quando ocorrem em bibliotecas de terceiros). As duas fontes mais comuns de problemas com isso são o fato de que a importação de extensões C de um arquivo zip não ser suportada pelo CPython (uma vez que fazer isso não é suportado diretamente pela máquina de carregamento dinâmico em qualquer plataforma) e que quando executando a partir de um arquivo zip, o atributo
__file__não se refere mais a um caminho de sistema de arquivos comum, mas a um caminho de combinação que inclui tanto a localização do arquivo zip no sistema de arquivos quanto o caminho relativo para o módulo dentro do arquivo. Mesmo quando o software usa corretamente as APIs de recursos abstratos internamente, a interface com componentes externos ainda pode exigir a disponibilidade de um arquivo real no disco.Como metaclasses, monkeypatching e importadores de metacaminho, se você ainda não tem certeza de que precisa tirar proveito desse recurso, é quase certo que não precisa dele. Se você decidir usá-lo de qualquer maneira, esteja ciente de que muitos projetos exigirão que uma falha seja reproduzida com um pacote totalmente instalado antes de aceitá-lo como um bug genuíno.
Histórico¶
February 2013: This specification was approved through PEP 427.
February 2021: The rules on escaping in wheel filenames were revised, to bring them into line with what popular tools actually do.
December 2024: Clarified that the
scriptsfolder should only contain regular files (the expected behaviour of consuming tools when encountering symlinks or subdirectories in this folder is not formally defined, and hence may vary between tools).December 2024: The
.dist-info/licenses/directory was specified through PEP 639.January 2025: Clarified that name and version needs to be normalized for
.dist-infoand.datadirectories.January 2026: Deprecate RECORD.jws and RECORD.p7s PEP 815.
Apêndice¶
Exemplo de implementação de urlsafe-base64-nopad:
# urlsafe-base64-nopad for Python 3
import base64
def urlsafe_b64encode_nopad(data):
return base64.urlsafe_b64encode(data).rstrip(b'=')
def urlsafe_b64decode_nopad(data):
pad = b'=' * (4 - (len(data) & 3))
return base64.urlsafe_b64decode(data + pad)