Como modernizar um projeto baseado em setup.py?#

pyproject.toml deve ser adicionado?#

Um arquivo pyproject.toml é fortemente recomendado. A presença de um arquivo pyproject.toml em si não traz muita coisa. [1] O que é realmente recomendado é a tabela [build-system] no pyproject.toml.

Deve o setup.py ser excluído?#

Não, setup.py pode existir em um projeto moderno baseado em Setuptools. O arquivo setup.py é um arquivo de configuração válido para setuptools que foi escrito em Python. No entanto, os seguintes comandos for descontinuados e NÃO DEVEM ser mais executados, e seus comandos de substituição recomendados devem ser usados:

Descontinuado

Recomendação

python setup.py install

python -m pip install .

python setup.py develop

python -m pip install --editable .

python setup.py sdist

python -m build

python setup.py bdist_wheel

Para mais detalhes:

Onde começar?#

O projeto deve conter um arquivo pyproject.toml na raiz de sua árvore de fontes que contém uma tabela [build-system] como esta:

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

Este é o método padronizado para permitir que frontends de construção saibam que Setuptools é o backend de construção para este projeto.

Observe que a presença de um arquivo pyproject.toml (mesmo que vazio) aciona pip para alterar seu comportamento padrão para usar isolamento de construção.

Para mais detalhes:

Como lidar com dependências de tempo de construção adicionais?#

Além do próprio setuptools, se setup.py depende de outras bibliotecas de terceiros (fora da biblioteca padrão do Python), elas devem ser listadas na lista requires do [build-system ] tabela, para que o frontend de construção saiba instalá-los ao construir as distribuições.

Por exemplo, um arquivo setup.py como este:

import setuptools
import some_build_toolkit  # comes from the `some-build-toolkit` library

def get_version():
    version = some_build_toolkit.compute_version()
    return version

setuptools.setup(
    name="my-project",
    version=get_version(),
)

requer um arquivo pyproject.toml como este (setup.py permanece inalterado):

[build-system]
requires = [
    "setuptools",
    "some-build-toolkit",
]
build-backend = "setuptools.build_meta"

Para mais detalhes:

Qual é o recurso de isolamento de compilação?#

Frontends de construção normalmente criam um ambiente virtual efêmero onde instalam apenas as dependências de construção (e suas dependências) listadas em build-system.requires e acionam a construção nesse ambiente.

Para alguns projetos este isolamento é indesejado e pode ser desativado da seguinte forma:

  • python -m build --no-isolation

  • python -m pip install --no-build-isolation

Para mais detalhes:

Como lidar com metadados de empacotamento?#

Todos os metadados estáticos podem opcionalmente ser movidos para uma tabela [project] em pyproject.toml.

Por exemplo, um arquivo setup.py como este:

import setuptools

setuptools.setup(
    name="my-project",
    version="1.2.3",
)

pode ser totalmente substituído por um arquivo pyproject.toml como este:

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "my-project"
version = "1.2.3"

Leia Declaring project metadata: the [project] table para a especificação completa do conteúdo permitido na tabela [project].

Como lidar com metadados dinâmicos?#

Se alguns campos de metadados de empacotamento não forem estáticos, eles precisam ser listados como dynamic nesta tabela [project].

Por exemplo, um arquivo setup.py como este:

import setuptools
import some_build_toolkit

def get_version():
    version = some_build_toolkit.compute_version()
    return version

setuptools.setup(
    name="my-project",
    version=get_version(),
)

pode ser modernizado desta forma:

[build-system]
requires = [
    "setuptools",
    "some-build-toolkit",
]
build-backend = "setuptools.build_meta"

[project]
name = "my-project"
dynamic = ["version"]
import setuptools
import some_build_toolkit

def get_version():
    version = some_build_toolkit.compute_version()
    return version

setuptools.setup(
    version=get_version(),
)

Para mais detalhes:

E se alguma coisa que não possa ser alterar esperar um arquivo setup.py?#

Por exemplo, existe um processo que não pode ser alterado facilmente e precisa executar um comando como python setup.py --name.

É perfeitamente normal deixar um arquivo setup.py na árvore de fontes do projeto mesmo depois de todo o seu conteúdo ter sido movido para pyproject.toml. Este arquivo pode ser tão minimalista quanto este:

import setuptools

setuptools.setup()

Onde posso ler mais sobre isso?#