Quando usar o arquivo de requisitos do pip versus install_requires em setup.py?

94

Estou usando pip com virtualenv para empacotar e instalar algumas bibliotecas Python.

Eu imagino que o que estou fazendo é um cenário bastante comum. Sou o mantenedor de várias bibliotecas para as quais posso especificar as dependências explicitamente. Algumas de minhas bibliotecas dependem de bibliotecas de terceiros que possuem dependências transitivas sobre as quais não tenho controle.

O que estou tentando fazer é que uma pip installde minhas bibliotecas baixe / instale todas as suas dependências upstream. O que estou lutando com a documentação do pip é se / como os arquivos de requisitos podem fazer isso por conta própria ou se eles são realmente apenas um suplemento para usar install_requires.

Eu usaria install_requiresem todas as minhas bibliotecas para especificar dependências e intervalos de versão e, em seguida, usaria apenas um arquivo de requisitos para resolver um conflito e / ou congelá-los para uma compilação de produção?

Vamos fingir que vivo em um mundo imaginário (eu sei, eu sei) e minhas dependências upstream são diretas e garantidas para nunca entrar em conflito ou quebrar a compatibilidade com versões anteriores. Eu seria compelido a usar um arquivo de requisitos do pip ou apenas deixar que o pip / setuptools / distribua instale tudo com base nele install_requires?

Há muitas perguntas semelhantes aqui, mas não consegui encontrar nenhuma que fosse tão básica quanto quando usar um ou outro ou usar os dois juntos harmoniosamente.

Joe Holloway
fonte
3
Este é um artigo muito bom que explica a relação entre os dois e também como eles se integram.
Björn Pollex

Respostas:

68

Minha filosofia é que install_requiresdeve indicar no mínimo o que você precisa. Pode incluir requisitos de versão se você souber que algumas versões não funcionarão; mas não deve haver requisitos de versão onde você não tem certeza (por exemplo, você não tem certeza se uma versão futura de uma dependência quebrará sua biblioteca ou não).

Os arquivos de requisitos, por outro lado, devem indicar o que você sabe que funciona e podem incluir dependências opcionais recomendadas. Por exemplo, você pode usar SQLAlchemy, mas sugerir MySQL e, portanto, colocar MySQLdb no arquivo de requisitos).

Então, em resumo: install_requiresé manter as pessoas longe de coisas que você sabe que não funcionam, enquanto os arquivos de requisitos levam as pessoas a coisas que você sabe que funcionam. Uma razão para isso é que os install_requiresrequisitos são sempre verificados e não podem ser desabilitados sem realmente alterar os metadados do pacote. Portanto, você não pode tentar uma nova combinação facilmente. Os arquivos de requisitos são verificados apenas no momento da instalação.

Ian Bicking
fonte
5
isso significa que você deve espelhar as setup.py install_requires=dependências requirements.txt?
proppy
9
Ter ambos os requisitos em setup.py e um arquivo de requisitos é perigoso, pois a duplicação apenas pede para ficar fora de sincronia.
Sebastian Blask
1
Além disso, como você realmente trabalha com isso? Eu presumo que você use o arquivo de requisitos uma vez para chegar a um estado que está definitivamente funcionando. Em seguida, instale com o pacote real com pip. Você nunca será capaz de usar -Uporque isso pode substituir as dependências do arquivo de requisitos? Como você atualiza?
Sebastian Blask
1
Essa resposta se aplica igualmente a aplicativos e pacotes? Imagine my-web-app (um aplicativo) dependendo de alguma ferramenta (um pacote), ambos os quais dependem do pacote de solicitações. Se alguma ferramenta tiver um arquivo requirements.txt que fixa uma determinada versão ou intervalo de versões de solicitações, isso parece criar um problema potencial para my-web-app, que pode ter especificado um intervalo de versão / versão conflitante.
Reece
2
Deve haver apenas uma maneira de instalar um pacote. Portanto, não é recomendável ter os dois, a menos que você queira confundir outros colaboradores.
Gewthen
17

aqui está o que coloquei em meu setup.py:

# this grabs the requirements from requirements.txt
REQUIREMENTS = [i.strip() for i in open("requirements.txt").readlines()]

setup(
    .....
    install_requires=REQUIREMENTS
)
rbp
fonte
20
Cuidado, os arquivos de requisitos podem conter comentários e inclusões. Você deve usar o analisador de pip
Romain Hardouin
1
sim, acabei mudando isso para eliminar os comentários. O analisador pip parece melhor do que a minha resposta.
rbp de
7
Por que usar um arquivo de requisitos se tudo o que ele contém já está em setup.py?
Sebastian Blask
2
@RomainHardouin, conforme mencionado nos comentários à sua resposta vinculada, pip não deve ser usado dessa forma.
akaihola
1
sim, isso funcionou para mim até que uma crítica --extra-index-urlnos requisitos foi exigida e isso explodiu na minha cara. Obrigado @RomainHardouin
Tommy
11

O Python Packaging User Guide tem uma página sobre este tópico, eu recomendo fortemente que você leia:

Resumo:

install_requiresexiste para listar as dependências do pacote que absolutamente devem ser instaladas para que o pacote funcione. Não se destina a fixar as dependências a versões específicas, mas os intervalos são aceitos, por exemplo install_requires=['django>=1.8']. install_requiresé observado por pip install name-on-pypie outras ferramentas.

requirements.txté apenas um arquivo de texto, no qual você pode escolher executar pip install -r requirements.txt. Era para ter versões de todas as dependências e subdependencies fixados, como este: django==1.8.1. Você pode criar um usando pip freeze > requirements.txt. (Alguns serviços, como o Heroku, são executados automaticamente pip install -r requirements.txtpara você.) pip install name-on-pypiNão olha requirements.txt, apenas install_requires.

Flimm
fonte
5

Eu só uso um setup.pye install_requiresporque só há um lugar para olhar. É tão poderoso quanto ter um arquivo de requisitos e não há duplicação para manter.

Sebastian Blask
fonte
A questão é quando usar um ou outro, não expliquei, mas minha resposta é que sempre uso um e nunca o outro. Como isso não está respondendo à pergunta?
Sebastian Blask