Comecei a trabalhar com Python. Eu adicionei requirements.txt
e setup.py
ao meu projeto. Mas, ainda estou confuso sobre o propósito de ambos os arquivos. Eu li que setup.py
foi projetado para coisas redistribuíveis e que requirements.txt
é projetado para coisas não redistribuíveis. Mas não estou certo de que isso seja correto.
Como esses dois arquivos realmente devem ser usados?
Respostas:
requisitos.txt
Isso ajuda você a configurar seu ambiente de desenvolvimento. Programas como
pip
podem ser usados para instalar todos os pacotes listados no arquivo de uma só vez. Depois disso, você pode começar a desenvolver seu script Python. Especialmente útil se você planeja ter outras pessoas contribuindo para o desenvolvimento ou usando ambientes virtuais. É assim que você o usa:setup.py
Isso permite que você crie pacotes que você pode redistribuir. Este script destina-se a instalar seu pacote no sistema do usuário final, não a preparar o ambiente de desenvolvimento como o
pip install -r requirements.txt
faz. Veja esta resposta para mais detalhes em setup.py.As dependências do seu projeto são listadas em ambos os arquivos.
fonte
A resposta curta
requirements.txt
é para listar apenas os requisitos do pacote.setup.py
por outro lado, é mais como um script de instalação. Se você não planeja instalar o código python, normalmente você só precisarequirements.txt
.O arquivo
setup.py
descreve, além das dependências do pacote, o conjunto de arquivos e módulos que devem ser empacotados (ou compilados, no caso de módulos nativos (ou seja, escritos em C)) e metadados para adicionar às listagens de pacotes python ( por exemplo, nome do pacote, versão do pacote, descrição do pacote, autor, ...).Como os dois arquivos listam dependências, isso pode causar um pouco de duplicação. Leia abaixo para obter detalhes.
requisitos.txt
Este arquivo lista os requisitos do pacote Python. É um arquivo de texto simples (opcionalmente com comentários) que lista as dependências do pacote do seu projeto Python (uma por linha). Ele não descrever a maneira em que seu pacote python está instalado. Você geralmente consumiria o arquivo de requisitos com
pip install -r requirements.txt
.O nome do arquivo de texto é arbitrário, mas geralmente é
requirements.txt
por convenção. Ao explorar repositórios de código-fonte de outros pacotes Python, você pode topar com outros nomes, comodev-dependencies.txt
oudependencies-dev.txt
. Eles têm a mesma finalidade,dependencies.txt
mas geralmente listam dependências adicionais de interesse para os desenvolvedores do pacote específico, a saber, para testar o código-fonte (por exemplo, pytest, pylint, etc.) antes do lançamento. Os usuários do pacote geralmente não precisam de todo o conjunto de dependências do desenvolvedor para executar o pacote.Se várias
requirements-X.txt
variantes estiverem presentes, geralmente uma listará as dependências de tempo de execução e a outra de tempo de construção ou dependências de teste. Alguns projetos também distribuem seus arquivos de requisitos em cascata, ou seja, quando um arquivo de requisitos inclui outro arquivo ( exemplo ). Isso pode reduzir a repetição.setup.py
Este é um script Python que usa o
setuptools
módulo para definir um pacote Python (nome, arquivos incluídos, metadados do pacote e instalação). Irá, comorequirements.txt
, também listar dependências de tempo de execução do pacote. Setuptools é a maneira de fato de construir e instalar pacotes Python, mas tem suas deficiências, que com o tempo geraram o desenvolvimento de novos "gerenciadores de meta-pacotes", como o pip. As deficiências de exemplo das ferramentas de instalação são a incapacidade de instalar várias versões do mesmo pacote e a falta de um comando de desinstalação.Quando um usuário Python faz
pip install ./pkgdir_my_module
(oupip install my-module
), o pip será executadosetup.py
no diretório (ou módulo) fornecido. Da mesma forma, qualquer módulo que tenha umsetup.py
pode serpip
instalado, por exemplo, executando apip install .
partir da mesma pasta.Eu realmente preciso de ambos?
A resposta curta é não, mas é bom ter os dois. Eles alcançam finalidades diferentes, mas podem ser usados para listar suas dependências.
Há um truque que você pode considerar para evitar a duplicação de sua lista de dependências entre
requirements.txt
esetup.py
. Se você já escreveu um totalmente funcionalsetup.py
para o seu pacote e suas dependências são principalmente externas, você pode considerar ter um simplesrequirements.txt
com apenas o seguinte:O
-e
é umapip install
opção especial que instala o pacote fornecido em modo editável . Quandopip -r requirements.txt
for executado neste arquivo, o pip instalará suas dependências por meio da lista em./setup.py
. A opção editável colocará um link simbólico em seu diretório de instalação (em vez de um ovo ou cópia arquivada). Ele permite que os desenvolvedores editem o código no local do repositório sem reinstalar.Você também pode tirar proveito do que é chamado de "extras de ferramentas de instalação" quando você tem ambos os arquivos em seu repositório de pacotes. Você pode definir pacotes opcionais em setup.py em uma categoria personalizada e instalar esses pacotes apenas dessa categoria com pip:
e então, no arquivo de requisitos:
Isso manteria todas as suas listas de dependências dentro de setup.py.
Observação : você normalmente executaria pip e setup.py a partir de uma sandbox, como as criadas com o programa
virtualenv
. Isso evitará a instalação de pacotes Python fora do contexto do ambiente de desenvolvimento do seu projeto.fonte
.
w / o-e
dentrorequirements.txt
. Este método apenas delega todos os requisitossetup.py
e você não precisa forçar ninguém a entrar no modo editável. Os usuários ainda podem fazer,pip install -e .
se quiserem.-e .
também usa setup.py para encontrar dependências, mas vincula a pasta atual (no local, com um link simbólico) na pasta de instalação do pip, em vez de fazer uma cópia --e
geralmente você usaria apenas se estiver desenvolvendo o pacote. Com-e
, as alterações nos arquivos do pacote Python (* .py) entrariam em vigor imediatamente no ambiente pip, em vez de forçar a reinstalação do pacote após cada alteração.cd foo && pip install -r ./bar/requirements.txt
isso, ele pesquisará setup.py emfoo/bar
oufoo
? Nesse último caso, há uma maneira de alcançar o primeiro?pip -r REQ
não se preocupa com o diretório em que REQ está. Você pode alimentá-lo a partir de um fifo mesmo se você quiser:pip install -r <(echo "mylib1"; echo "mylib2";)
. Onde<(CMD)
está a substituição do comando bash, não o redirecionamento stdin.Para fins de integridade, aqui está como eu vejo isso em
34 ângulos diferentes.Esta é a descrição precisa citada da documentação oficial (grifo meu):
Mas ainda pode não ser fácil de ser entendido, então, na próxima seção, virão 2 exemplos factuais para demonstrar como as 2 abordagens devem ser usadas de forma diferente.
Seus usos reais são, portanto (supostamente) diferentes
Se o seu projeto
foo
vai ser lançado como uma biblioteca autônoma (ou seja, outras provavelmente o fariamimport foo
), então você (e seus usuários posteriores) gostariam de ter uma declaração flexível de dependência, para que sua biblioteca não fosse (e não deve ) ser "exigente" sobre qual versão exata de SUAS dependências deve ser. Portanto, normalmente, seu setup.py contém linhas como esta:Se você deseja apenas "documentar" ou "fixar" seu ambiente atual EXATO para seu aplicativo
bar
, ou seja, você ou seus usuários gostariam de usar seu aplicativobar
como está, ou sejapython bar.py
, em execução , você pode querer congelar seu ambiente para que ele sempre se comportaria da mesma forma. Nesse caso, seu arquivo de requisitos ficaria assim:Na verdade, qual devo usar?
Se você estiver desenvolvendo um aplicativo
bar
que será usado porpython bar.py
, mesmo que seja "apenas um script por diversão", ainda é recomendado usar o arquivo requirements.txt porque, quem sabe, na próxima semana (que por acaso é o Natal) você receberá um novo computador como um presente, então você precisaria configurar seu ambiente exato lá novamente.Se você estiver desenvolvendo uma biblioteca
foo
que será usada porimport foo
, deverá preparar um setup.py. Período. Mas você ainda pode optar por fornecer também um requirements.txt ao mesmo tempo, que pode:(a) seja no
A==1.2.3
estilo (conforme explicado no item 2 acima);(b) ou apenas conter um único mágico
.
que seria aproximadamente igual a "instalar os requisitos com base em setup.py", mas sem duplicação. Pessoalmente, considero que essa última abordagem confunde os limites, aumenta a confusão e NÃO realmente agrega valor, mas, mesmo assim, é um truque derivado de uma abordagem mencionada pelo mantenedor do pacote Python, Donald, em seu blog .
Limites inferiores diferentes.
Mesmo depois de ter seguido os 3 critérios acima e decidido corretamente que sua biblioteca
hybrid-engine
usaria umsetup.py
para declarar sua dependênciaengine>=1.2.0
, e seu aplicativo de amostrareliable-car
usariarequirements.txt
para declarar sua dependênciaengine>=1.2.3
, embora a versão mais recente doengine
já esteja em 1.4.0. Como você pode ver, sua escolha para o número do limite inferior ainda é sutilmente diferente. E aqui está o porquê.hybrid-engine
depende deengine>=1.2.0
porque, hipoteticamente falando, a capacidade de "combustão interna" necessária foi introduzida pela primeira vez emengine 1.2.0
, e essa capacidade é a necessidade dehybrid-engine
, independentemente de haver alguns (menores) bugs dentro de tal versão e foram corrigidos nas versões subsequentes 1.2.1 , 1.2.2 e 1.2.3.reliable-car
depende deengine>=1.2.3
porque essa é a versão mais antiga SEM problemas conhecidos, até agora. Claro, há novos recursos em versões posteriores, digamos, "motor elétrico" introduzidoengine 1.3.0
e "reator nuclear" introduzidoengine 1.4.0
, mas eles não são necessários para o projetoreliable-car
.fonte
A==1.2.3
e, em seguida, se o pacote downstream de sua biblioteca dependerA==1.2.4
, agora não haverá uma maneira de satisfazer ambos. A solução para minimizar esse conflito é sua biblioteca definir um intervalo que você sabe que funcionaria. Supondo que muitas bibliotecas upstream já sigam semver.org ,A>=1,<2
funcionaria.foo
queimport foo
dar-lhe? Aquela resposta hacky aceita naquele link que você forneceu serve como um exemplo perfeito de porque o mantenedor do pacote "não deve e não deve ser exigente". :-) Agora posso ter seu voto positivo?