Empacotando e distribuindo projetos#

Status da página:

Desatualizada

Última revisão:

2023-12-14

Esta seção cobre alguns detalhes adicionais sobre configuração, empacotamento e distribuição de projetos Python com setuptools que não são cobertos pelo tutorial introdutório em Empacotando projetos Python. Ele ainda assume que você já está familiarizado com o conteúdo da página Instalando pacotes.

A seção não visa cobrir as melhores práticas para o desenvolvimento de projetos Python como um todo. Por exemplo, ele não fornece orientação ou recomendações de ferramentas para controle de versão, documentação ou teste.

Para mais material de referência, veja Construindo e Distribuindo Pacotes na documentação Setuptools, mas note que alguns conteúdos de aviso podem estar desatualizados. No caso de conflitos, dê preferência ao conselho do Guia de Usuário para Empacotamento de Python.

Requisitos para empacotamento e distribuição#

  1. Primeiro, certifique-se de que você já cumpriu os requisitos para instalação de pacotes.

  2. Instale “twine” [1]:

    python3 -m pip install twine
    
    py -m pip install twine
    

Você precisará disso para enviar as distribuições do seu projeto para o PyPI (veja abaixo).

Configurando seu projeto#

Arquivos iniciais#

setup.py#

O arquivo mais importante é setup.py que existe na raiz do diretório do seu projeto. Para obter um exemplo, consulte o setup.py no projeto de exemplo PyPA.

setup.py tem duas funções principais:

  1. É o arquivo onde vários aspectos do seu projeto são configurados. A principal característica do setup.py é que ele contém uma função global setup(). Os argumentos nomeados para esta função são como os detalhes específicos do seu projeto são definidos. Os argumentos mais relevantes são explicados em a seção abaixo de.

  2. É a interface de linha de comando para executar vários comandos relacionados a tarefas de empacotamento. Para obter uma lista dos comandos disponíveis, execute python3 setup.py --help-commands.

setup.cfg#

setup.cfg é um arquivo ini que contém opções padrão para os comandos setup.py. Para obter um exemplo, consulte o setup.cfg no projeto de exemplo PyPA.

README.rst / README.md#

Todos os projetos devem conter um arquivo leia-me que cubra o objetivo do projeto. O formato mais comum é reStructuredText com uma extensão “rst”, embora isso não seja um requisito; múltiplas variantes do Markdown também são suportadas (veja o argumento long_description_content_type do setup()).

Para obter um exemplo, consulte o README.md do projeto de exemplo PyPA.

Nota

Projetos usando Setuptools 0.6.27+ têm arquivos leia-me padrão (README.rst, README.txt ou README) incluídos nas distribuições de código-fonte por padrão. A biblioteca interna distutils adota este comportamento a partir do Python 3.7. Adicionalmente, Setuptools 36.4.0+ incluirá um README.md se encontrado. Se você estiver usando setuptools, você não precisa listar seu arquivo leia-me em MANIFEST.in. Caso contrário, inclua para ser explícito.

MANIFEST.in#

Um MANIFEST.in é necessário quando você precisa empacotar arquivos adicionais que não são incluídos automaticamente em uma distribuição de código-fonte. Para obter detalhes sobre como escrever um arquivo MANIFEST.in, incluindo uma lista do que é incluído por padrão, consulte “Using MANIFEST.in”.

No entanto, você pode não ter que usar um MANIFEST.in. Por exemplo, o projeto de amostra PyPA removeu seu arquivo de manifesto, uma vez que todos os arquivos necessários foram incluídos pelo Setuptools 43.0.0 e mais recentes.

Nota

MANIFEST.in não afeta distribuições binárias como wheels.

LICENSE.txt#

Cada pacote deve incluir um arquivo de licença detalhando os termos de distribuição. Em muitas jurisdições, os pacotes sem uma licença explícita não podem ser legalmente usados ou distribuídos por ninguém que não seja o detentor dos direitos autorais. Se não tiver certeza de qual licença escolher, você pode usar recursos como Escolha uma licença do GitHub ou consultar um advogado.

Para obter um exemplo, consulte o LICENSE.txt do projeto de exemplo PyPA.

<seu pacote>#

Embora não seja obrigatório, a prática mais comum é incluir seus módulos e pacotes Python em um único pacote de nível superior que tem o mesmo name do seu projeto, ou algo muito próximo.

Para obter um exemplo, consulte o pacote de exemplo que está incluído no projeto de exemplo PyPA.

Argumentos de setup()#

Como mencionado acima, o principal recurso do setup.py é que ele contém uma função global setup(). Os argumentos nomeados para esta função são como os detalhes específicos do seu projeto são definidos.

Alguns são temporariamente explicados abaixo até que suas informações sejam movidas em outros lugares. A lista completa pode ser encontrada na documentação setuptools.

A maioria dos fragmentos fornecidos são retirados do setup.py contido no projeto de exemplo do PyPA.

Veja Escolhendo um esquema de versionamento para mais informações sobre maneiras de usar versões para transmitir informações de compatibilidade para seus usuários.

packages#

packages=find_packages(include=['sample', 'sample.*']),

Defina packages para uma lista de todos pacotes em seu projeto, incluindo seus subpacotes, sub-subpacotes, etc. Embora os pacotes possam ser listados manualmente, setuptools.find_packages() encontra-os automaticamente. Use o argumento nomeado include para encontrar apenas os pacotes fornecidos. Use o argumento nomeado exclude para omitir pacotes que não devem ser lançados e instalados.

py_modules#

py_modules=["six"],

Se o seu projeto contém qualquer módulo Python de arquivo único que não faz parte de um pacote, defina py_modules para uma lista dos nomes dos módulos (menos a extensão .py) para fazer o Setuptools ficar ciente deles.

install_requires#

install_requires=['peppercorn'],

“install_requires” deve ser usado para especificar quais dependências um projeto precisa minimamente para ser executado. Quando o projeto é instalado pelo pip, esta é a especificação que é usada para instalar suas dependências.

Para mais informações sobre como usar “install_requires”, veja install_requires vs Arquivos de requisitos.

package_data#

package_data={
    'sample': ['package_data.dat'],
},

Frequentemente, arquivos adicionais precisam ser instalados em um pacote. Esses arquivos geralmente são dados intimamente relacionados à implementação do pacote ou arquivos de texto contendo documentação que pode ser do interesse dos programadores que usam o pacote. Esses arquivos são chamados de “dados do pacote”.

O valor deve ser um mapeamento do nome do pacote para uma lista de nomes de caminhos relativos que devem ser copiados para o pacote. Os caminhos são interpretados como relativos ao diretório que contém o pacote.

Para mais informações, veja Incluindo arquivos de dados da documentação do setuptools.

data_files#

data_files=[('my_data', ['data/data_file'])],

Embora configurar Dados de pacote seja suficiente para a maioria das necessidades, em alguns casos você pode precisar colocar arquivos de dados fora de seus pacotes. A diretiva data_files permite que você faça isso. É mais útil se você precisar instalar arquivos que são usados por outros programas, que podem não ter conhecimento dos pacotes Python.

Cada par (directory, files) na sequência especifica o diretório de instalação e os arquivos a serem instalados nele. O directory deve ser um caminho relativo (embora isso possa mudar no futuro, consulte relatório de problema #92 do wheel) e é interpretado em relação ao prefixo de instalação (sys.prefix do Python para uma instalação padrão; site.USER_BASE para uma instalação do usuário). Cada nome de arquivo em files é interpretado em relação ao script setup.py no topo da distribuição do código-fonte do projeto.

Para obter mais informações, consulte a seção distutils em Instalando arquivos adicionais.

Nota

Ao instalar pacotes como ovo, data_files não é suportado. Então, se seu projeto usa Setuptools, você deve usar pip para instalá-lo. Alternativamente, se você deve usar python setup.py, então você precisa passar a opção --old-and-unmanageable.

scripts#

Embora setup() tenha suporte a uma palavra-chave scripts para apontar para scripts pré-fabricados para instalar, o recomendado A abordagem para obter compatibilidade entre plataformas é usar pontos de entrada Criando scripts executáveis (veja abaixo).

Escolhendo um esquema de versionamento#

See Versioning for information on common version schemes and how to choose between them.

Trabalhando em “modo de desenvolvimento”#

Você pode instalar um projeto em modo “editável” ou “desenvolvedor” enquanto trabalha nele. Quando instalado como editável, um projeto pode ser editado no local sem reinstalação: alterações nos arquivos fonte Python em projetos instalados como editáveis serão refletidas na próxima vez que um processo de interpretador for iniciado.

Para instalar um pacote Python no modo “editável”/”desenvolvedor” mude o diretório para a raiz do diretório do projeto e execute:

python3 -m pip install -e .

O sinalizador de linha de comando do pip -e é abreviação de --editable, e . refere-se ao diretório de trabalho atual, então juntos, isso significa instalar o diretório atual (ou seja, seu projeto) em modo editável. Isso também instalará quaisquer dependências declaradas com install_requires e quaisquer scripts declarados com console_scripts. As dependências serão instaladas no modo usual e não editável.

Você também pode querer instalar algumas de suas dependências no modo editável. Por exemplo, supondo que seu projeto requer “foo” e “bar”, mas você deseja “bar” instalado do VCS no modo editável, então você poderia construir um arquivo de requisitos como:

-e .
-e bar @ git+https://somerepo/bar.git

A primeira linha diz para instalar seu projeto e todas as dependências. A segunda linha substitui a dependência “bar”, de modo que seja preenchida a partir do VCS, não PyPI.

Se, no entanto, você quiser “bar” instalado de um diretório local em modo editável, o arquivo de requisitos deve ser semelhante a este, com os caminhos locais no topo do arquivo:

-e /path/to/project/bar
-e .

Caso contrário, a dependência será resolvida pelo PyPI, devido à ordem de instalação do arquivo de requisitos. Para mais informações sobre os arquivos de requisitos, consulte a seção Requirements File na documentação do pip. Para obter mais informações sobre as instalações de VCS, consulte a seção VCS Support da documentação do pip.

Por último, se você não deseja instalar nenhuma dependência, pode executar:

python3 -m pip install -e . --no-deps

Para mais informações, veja a seção Development Mode na documentação do Setuptools.

Empacotando seu projeto#

Para ter seu projeto instalável de um Índice de Pacotes como o PyPI, você precisará criar uma Distribuição (também conhecida como “Pacote”) para seu projeto.

Antes de compilar wheels e sdists para seu projeto, você precisará instalar o pacote build:

python3 -m pip install build
py -m pip install build

Distribuições fontes#

Minimamente, você deve criar uma Distribuição Fonte:

python3 -m build --sdist
py -m build --sdist

Uma “distribuição fonte” é não construída (ou seja, não é uma Distribuição Construída) e requer uma etapa de construção quando instalada pelo pip. Mesmo se a distribuição for puro Python (ou seja, não contém extensões), ainda envolve uma etapa de construção para construir os metadados de instalação de setup.py e/ou setup.cfg.

Wheels#

Você também deve criar uma wheel para o seu projeto. Uma wheel é um pacote construído que pode ser instalado sem a necessidade de passar pelo processo de “construção”. Instalar wheel é substancialmente mais rápido para o usuário final do que instalar a partir de uma distribuição original.

Se o seu projeto for puro Python, você criará uma “Wheel de Python Puro” (consulte a seção abaixo).

Se o seu projeto contém extensões compiladas, então você criará o que é chamado de *Wheel de Plataforma* (veja a seção abaixo).

Nota

Se o seu projeto também tiver suporte a Python 2 e não contiver extensões C, você deve criar o que é chamado de Wheel Universal adicionando o seguinte ao seu arquivo setup.cfg:

[bdist_wheel]
universal=1

Use esta configuração apenas se o seu projeto não tiver extensões C e tiver suporte ao Python 2 e 3.

Wheels de Puro Python#

Wheels de Python Puro contêm nenhuma extensão compilada e, portanto, só exigem um único wheel Python.

Para construir o wheel:

python3 -m build --wheel
py -m build --wheel

O pacote wheel detectará que o código é puro Python, e construirá um wheel cujo nome pode ser usado em qualquer instalação do Python 3. Para obter detalhes sobre a nomenclatura de arquivos wheel, consulte PEP 425.

Se você executar build sem --wheel ou --sdist, ele irá construir os dois arquivos para você; isso é útil quando você não precisa de vários wheels.

Wheels de Plataforma#

Wheels de Plataforma são wheels que são específicos para uma certa plataforma, como Linux, macOS ou Windows, geralmente em razão de conter extensões compiladas.

Para construir o wheel:

python3 -m build --wheel
py -m build --wheel

O pacote wheel detectará que o código não é puro Python e construirá um wheel cujo nome só pode ser usado na plataforma em que foi construído. Para obter detalhes sobre a nomenclatura de arquivos wheel, consulte PEP 425.

Nota

PyPI oferece suporte atualmente a envios de wheels de plataforma do Windows, macOS e da ABI multidistro manylinux*. Detalhes sobre o último estão definidos em PEP 513.

Enviando seu Projeto para PyPI#

Quando você executou o comando para criar sua distribuição, um novo diretório dist/ foi criado no diretório raiz do seu projeto. É onde você encontrará seus arquivos de distribuição para enviar.

Nota

Esses arquivos são criados apenas quando você executa o comando para criar sua distribuição. Isso significa que a qualquer momento que você alterar a fonte do seu projeto ou a configuração no arquivo setup.py, você precisará reconstruir esses arquivos novamente antes de distribuir as alterações para PyPI.

Nota

Antes de lançar no repositório principal do PyPI, você pode preferir treinar com o site de teste do PyPI que é redefinido em uma base semirregular. Veja Usando TestPyPI sobre como definir sua configuração para usá-lo.

Aviso

Em outros recursos, você pode encontrar referências ao uso de python setup.py register e python setup.py upload. Esses métodos de registro e envio de um pacote são fortemente desencorajados, pois podem usar uma conexão HTTP de texto simples ou HTTPS não verificada em algumas versões Python, permitindo que seu nome de usuário e senha sejam interceptados durante a transmissão.

Dica

O analisador de reStructuredText usado no PyPI não é Sphinx! Além disso, para garantir a segurança de todos os usuários, certos tipos de URLs e diretivas são proibidos ou removidos (por exemplo, a diretiva .. raw::). Antes de tentar enviar sua distribuição, você deve verificar se suas descrições breves/longas fornecidas no setup.py são válidas. Você pode fazer isso executando twine check em todos arquivos do seu pacote:

twine check dist/*

Criar uma conta#

Primeiro, você precisa de uma conta de usuário do PyPI. Você pode criar uma conta usando o formulário no site do PyPI.

Agora você criará um token de API do PyPI para que possa enviar o seu projeto com segurança.

Acesse https://pypi.org/manage/account/#api-tokens e crie um novo token de API; não limite seu escopo a um projeto específico, já que você está criando um novo projeto.

Não feche a página antes de copiar e salvar o token – você não verá o token novamente.

Nota

Para evitar ter que copiar e colar o token toda vez que você enviar, você pode criar um arquivo $HOME/.pypirc:

[pypi]
username = __token__
password = <the token value, including the `pypi-` prefix>

Esteja ciente de que isso armazena seu token em texto simples.

Para mais detalhes, veja a especificação do .pypirc.

Enviar suas distribuições#

Assim que tiver uma conta, você pode enviar suas distribuições para o PyPI usando twine.

O processo de envio de uma versão é o mesmo, independentemente de o projeto já existir ou não no PyPI – se ainda não existir, será criado automaticamente quando a primeira versão for carregada.

Para a segunda versão e as subsequentes, PyPI requer apenas que o número da versão da nova versão seja diferente de todas as versões anteriores.

twine upload dist/*

Você pode ver se o seu pacote foi enviado com sucesso navegando para a URL https://pypi.org/project/<projetoexemplo> onde projetoexemplo é o nome do seu projeto que você enviou. O seu projeto pode demorar um ou dois minutos para aparecer no site.