Hackeando maya
Eu aprendi algumas lições que resultaram na minha seguinte proposta de uso recomendado de pipenv
em bibliotecas python. Espero que outras pessoas analisem a proposta e, se chegarmos a um acordo, o texto (atualizado) pode acabar em pipenv
docs.
pipenv
padrões e antipadrões para projeto de biblioteca pythonEDITAR
A seguir, é mais aplicável para bibliotecas python gerais (principalmente de código aberto), que devem ser executadas em diferentes versões e sistemas operacionais de python. Bibliotecas desenvolvidas em ambiente corporativo estrito podem ser casos diferentes (certifique-se de revisar todas as seções de Problemas de qualquer maneira).
FIM DA EDIÇÃO
TL; DR : Adicionar pipenv
arquivos ao projeto de biblioteca Python provavelmente introduzirá complexidade extra e pode ocultar alguns erros sem adicionar nada à segurança da biblioteca. Por esta razão, mantenha Pipfile
, Pipfile.lock
e .env
fora do controle de origem da biblioteca.
Você poderá usar a potência total de pipenv
independentemente de seus arquivos residirem em .gitignore
.
Por biblioteca python setup.py
, sendo direcionado para distribuição e uso em várias plataformas que diferem na versão python e / ou sistema operacional.
Os exemplos são maya
, requests
, flask
etc.
Por outro lado (não a biblioteca python), existem aplicativos direcionados para um interpretador python específico, sistema operacional e muitas vezes sendo implantados em um ambiente estritamente consistente.
pipfile
descreve essas diferenças muito bem em seu Pipfile vs setup.py .
pipenv
(ferramenta de implantação)Eu concordo totalmente com a declaração de que pipenv
é uma ferramenta de implantação , pois permite:
Pipfile.lock
) para implantação de ambiente virtualAjuda quando é necessário implantar um aplicativo ou desenvolver em um ambiente python muito consistente entre vários desenvolvedores.
Chamar pipenv
ferramenta de empacotamento é enganoso se alguém espera que ela crie bibliotecas python ou esteja profundamente envolvido na criação delas. Sim, pipenv
pode ajudar muito (no desenvolvimento local de bibliotecas), mas pode possivelmente prejudicar (geralmente em testes de CI quando usado sem reflexão mais profunda).
TL; DR : pipenv
fornece ambiente seguro por meio da aplicação de dependências concretas aprovadas descritas em Pipfile.lock
file e a biblioteca python só tem permissão para definir dependências abstratas (portanto, não pode fornecer Pipfile.lock
).
pipenv
brilha em cenários de implantação seguindo estas etapas:
Pipfile
)Pipfile.lock
Pipfile.lock
como definição de ambiente Python aprovadopipenv sync
para aplicar "o ouro" Pipfile.lock
outro lugar, obtendo um ambiente python idêntico.Com o desenvolvimento da biblioteca python, não se pode alcançar tal segurança, porque as bibliotecas não devem definir dependências concretas . Quebrar essa regra (portanto, tentar declarar dependências concretas pela biblioteca Python) resulta em problemas como:
setup.py
quebradassetup.py
deve definir todas as dependências abstratas via install_requires
.
Se Pipfile
definir essas dependências também, pode facilmente ocultar problemas como:
install_requires
Pipfile
define regras específicas (faixas de versão, etc.) para uma dependência e install_requires
não.Para evitar isso, siga estas regras:
Pipfile
[packages]
em Pipfile
deve estar vazia ou definir apenas uma única dependência da própria biblioteca.Pipfile.lock
no repositórioManter Pipfile.lock
(normalmente por "razões de segurança") no repositório da biblioteca é errado, porque:
Para evitá-lo, deve-se:
Pipfile.lock
do repositório e adicione-o em .gitignore
tox
(escondendo usedevelop
)Se tox.ini
contiver em sua commands
section entradas como:
pipenv install
pipenv install --dev
pipenv lock
muitas vezes é um problema, porque:
pipenv install
deve instalar apenas a própria biblioteca, e tox
está (por padrão) fazendo isso também. Além da duplicidade, também evita usedevelop=True
e usedevelop=False
em tox.ini
porque Pipenv
é capaz de expressá-lo apenas em uma variante (e tox.ini
permite diferenças em ambientes diferentes).Para evitá-lo, deve-se:
pipenv
em tox.ini
. Veja os pedidos tox.inipipenv
falharpipenv
está sob forte desenvolvimento e alguma coisa quebrará algum dia. Se tal problema interromper sua construção de CI, há uma falha que poderia ser evitada não usando pipenv
e usando ferramentas tradicionais (que geralmente são um pouco mais maduras).
Para evitá-lo, deve-se:
pipenv
em um script de construção de CI, tox.ini
ou lugar semelhante. Você sabe o valor que obtém ao adicioná-lo? O trabalho poderia ser feito com o ferramental existente?As principais questões relacionadas ao papel de pipenv
no desenvolvimento da biblioteca Python são:
pipenv
realmente traz? R: Ferramenta de gerenciamento Virtualenv.pipenv
? R: Gerenciar virtualenv.Seguem-se mais alguns detalhes e truques.
pipenv
não adicionará nenhuma segurança ao seu pacoteNão empurre para o projeto apenas porque todo mundo faz isso ou porque você espera segurança extra. Isso vai te decepcionar.
A proteção usando dependências concretas (e aprovadas) deve ocorrer em uma fase posterior no aplicativo que vai usar sua biblioteca.
Pipfile
, Pipfile.lock
e .env
arquivos fora do repositórioColoque os arquivos em .gitignore
.
Pipfile
é fácil de recriar conforme demonstrado abaixo, pois a maioria ou todos os requisitos já estão definidos em seu setup.py
. E o arquivo .env
provavelmente contém informações privadas, que não devem ser compartilhadas.
Manter esses arquivos fora do repositório evitará todos os problemas, que podem acontecer com compilações de CI ao usar pipenv
em situações que não são apropriadas.
pipenv
como caixa de ferramentas privada do desenvolvedorpipenv
pode simplificar o trabalho do desenvolvedor como ferramenta de gerenciamento virtualenv.
O truque é aprender a recriar rapidamente seus arquivos (privados) pipenv
relacionados, por exemplo:
$ cd <project_repository>
$ # your library will bring the dependencies (via install_requires in setup.py)
$ pipenv install -e .
$ # add more dev tools you preffer
$ pipenv install --dev ipython pdbpp
$ # start hacking
$ pipenv shell
...
Use .env
file se precisar de um método conveniente para configurar variáveis de ambiente.
Lembre-se: mantenha o uso de pipenv
fora de seus builds de CI e sua vida ficará mais simples.
setup.py
para declarar dependências extrasEm sua setup.py
use a seção extras_requires
:
from setuptools import setup
setup(
name='mypackage',
....,
install_requires=["jinja2", "simplejson"],
extras_require={
'tests': ['pytest', 'pyyaml'],
'pg': ['psycopg2'],
},
....
)
Para instalar todas as dependências declaradas para tests
extra:
$ pipenv install -e .[tests]
Observe que ele sempre incluirá as dependências install_requires
.
Este método não permite dividir dependências em seções padrão e dev, mas isso não deve ser um problema real nos cenários esperados.
Isso é muito impressionante, muito obrigado por compilar. Com certeza revisarei com mais detalhes daqui a pouco
/ cc @uranusjr @jtratner @ncoghlan
Algumas referências a maya
questões:
pendulum>=1.0
em setup.py: a versão estava no Pipfile, mas faltava em setup.py)pipenv
interrompeu toda a execução do Travis)Eu amo isso também Talvez devêssemos adicionar isso à documentação do Pipenv, ou mesmo ao Guia do Usuário de Empacotamento do
O corolário do conselho acima parece ser "renunciar a construções de CI determinísticas / reproduzíveis", o que me parece um antipadrão muito amplo.
O que você está propondo como alternativa que ainda permitiria o determinismo?
@ tsiq-oliverc Construções determinísticas têm seu lugar no momento, um aplicativo está para ser construído.
Imagine a seguinte tentativa de realizar compilações realmente determinísticas da biblioteca Python:
Pipfile.lock
Pipfile.lock
resultante das dependências abstratas da biblioteca definidas em Pipfile
Pipfile.lock
separadas definidas no repositório. Observe que construir Pipfile.lock
automaticamente durante a construção de CI não adiciona nenhum determinismoÉ um grande esforço extra. E o que você obtém é uma biblioteca, que será instalada em um contexto diferente (por exemplo, uma semana depois a instalação padrão irá pegar uma ou duas dependências atualizadas) e que não terá nada com o fato de que você usou Pipfile.lock
, que está obsoleto no momento.
O conflito está no fato de que a biblioteca nunca deve definir dependências estritas internamente.
Se você pensa, existe outra alternativa para obter compilações determinísticas para a biblioteca python - descreva-a.
@vlcinsky - Se um consumidor de sua biblioteca usa diferentes versões de dependências, etc., então isso está fora de seu controle. Portanto, concordo que não há maneira viável de um mantenedor de biblioteca gerenciar isso.
Mas o objetivo aqui é presumivelmente um escopo muito menor. Em particular, eu veria os objetivos de um mantenedor de biblioteca como os seguintes (que são aproximadamente equivalências):
Se alguma dessas três coisas não funcionar, parece-me a antítese do controle de qualidade.
Então, sim, eu diria que se você garante suporte às variantes Python A, B e C para o seu consumidor, e elas se comportam de maneira diferente o suficiente para que um arquivo de bloqueio (etc.) não resolva, então você deve ter três arquivos de bloqueio (ou qualquer que seja).
Eu não usei o Pipenv o suficiente para saber como isso seria fácil na prática, no entanto.
No momento, estou pensando em adicionar Pipfile
s também a alguns projetos de biblioteca para o sistema de CI.
Eu absolutamente preciso do bloqueio de dependência (+ hashing) para cumprir as diretrizes de segurança de toda a empresa e atualmente não preciso testar com diferentes versões do Python, já que há apenas uma que é oficialmente suportada. E o fato de que o pipenv simplifica a configuração de um ambiente de desenvolvimento local, incluindo o virtualenv, é um bom efeito colateral.
E o que você obtém é uma biblioteca, que será instalada em um contexto diferente (por exemplo, uma semana depois a instalação padrão pegará uma ou duas dependências atualizadas) e que não obterá nada com o fato de que você usou
Pipfile.lock
, que está obsoleto no momento.
Isso não é universalmente verdadeiro. No mundo do software corporativo, você ainda tem ambientes muito específicos que são oficialmente suportados e um problema de segurança em uma dependência resulta na atualização do seu produto, em vez de o cliente atualizar a dependência por conta própria.
(Sim, estou falando de uma biblioteca, não de um aplicativo aqui ...)
@ Moritz90 seu cenário é para a biblioteca python em ambiente corporativo e pipenv
pode ajudar porque é um ambiente muito mais determinístico.
Minha descrição visa bibliotecas python gerais, como flask
, request
, maya
etc. onde o contexto é muito mais variável. Tentando consertar algumas coisas em maya
, fiquei frustrado ao aprender que, em muitos casos, o uso de pipenv
introduzia problemas reais (normalmente ocultando problemas que seriam normalmente detectados), embora não fornecesse muito ou nenhum acréscimo valor.
Obter compilações determinísticas é bom, mas incorre em custos. E se feito errado, você pode pagar a mais por um resultado de qualidade inferior - e isso é o que eu queria evitar.
Eu diria que esta é uma das instâncias em que não queremos que as compilações sejam absolutamente determinísticas. Se você não fixar suas dependências com ==
, você está se comprometendo a manter o suporte para várias versões por padrão e deve projetar a biblioteca dessa forma. Uma atualização de dependência interrompendo o build no CI é na verdade uma coisa boa porque expõe um bug na biblioteca. Dependências completamente determinísticas (como gerenciadas pelo Pipenv) mascarariam isso. Ainda assim, seria benéfico ser capaz de ser determinítico quando você quiser, isso geralmente não é o melhor.
@uranusjr - Claro. Concordo que, se o desejo for "construções não determinísticas", o conselho acima pode muito bem fazer sentido. Na verdade, é quase uma equivalência lógica e poderia ser declarada de forma muito mais sucinta: "Se você não quer compilações determinísticas, não use uma ferramenta ( pipenv
) cujo objetivo é garantir compilações determinísticas" 😄.
Mas essa certamente não é uma meta desejável em geral.
@ tsiq-oliverc boa definição de escopo - suporta discussão focada. Eu acrescentaria mais um requisito: O determinismo CI não deve ocultar possíveis problemas na biblioteca testada.
Se usarmos Pipenv.lock
, criar virtualenv com base nisso e executar o teste de CI da biblioteca, fizemos parte da funcionalidade que a biblioteca deveria fazer - instalando dependências adequadas. Se a biblioteca estiver de alguma forma danificada a este respeito - o ambiente pré-instalado esconderia este problema.
Para mim, parece mais importante detectar problemas em uma biblioteca do que executar CI de maneira determinística. Se houver uma maneira de fazer as duas coisas (por exemplo, executando o teste por trás do índice pypi privado, que também pode oferecer suporte ao determinismo), não tenho nenhum problema, mas se houver um conflito, eu tenho minhas prioridades.
Não me leve a mal: não há desejo de executar compilações não determinísticas, meu desejo é executar compilações de CI, que detectarão o máximo de problemas possível.
@vlcinsky Claro, eu só queria compartilhar minha experiência para ter certeza de que a documentação atualizada reflete isso também. A documentação atual faz um ótimo trabalho ao explicar as vantagens e desvantagens:
Para bibliotecas, defina dependências abstratas por meio de install_requires em setup.py. [...]
Para aplicativos, defina as dependências e onde obtê-las no Pipfile e use esse arquivo para atualizar o conjunto de dependências concretas em Pipfile.lock. [...]
Obviamente, Pipfile e pipenv ainda são úteis para desenvolvedores de bibliotecas, pois podem ser usados para definir um ambiente de desenvolvimento ou teste.
E, é claro, existem projetos para os quais a distinção entre biblioteca e aplicativo não é tão clara.
(Destacou a parte que se aplica ao meu caso.)
Só quero ter certeza de que continuará assim. Acho que sua postagem original contém muitas declarações gerais sem uma isenção de responsabilidade de que você está falando sobre um projeto de código aberto que será publicado no PyPI.
@ Moritz90 Concordo totalmente. Eu estava tentando destacar esse foco, mas posso torná-lo ainda mais visível.
@ Moritz90 Eu adicionei uma nota introdutória refletindo seu comentário.
@vlcinsky - Isso faz sentido. Eu entendo que você não fizer isso explicitamente quer não determinística constrói, mas eu acho que é inevitavelmente equivalente ao que você quer (ou seja, para questões de captura quando as suas dependências a montante atualização).
Pensando em voz alta, qual é a melhor maneira de resolver esses dois objetivos conflitantes? Uma possibilidade é ter um processo de CI de duas fases:
Pipfile.lock
em seu repo, então é totalmente reproduzível.pipenv update
e, em seguida, executa os testes, para que obtenha a última de todas as suas dependências (que é basicamente o mesmo que o comportamento sem lockfile, eu acho?).@ tsiq-oliverc Para obter compilações determinísticas, eu pensaria na seguinte configuração:
pipenv
Usar pipenv
para fazer a instalação é semelhante ao que a própria biblioteca deve fazer, mas é definitivamente diferente porque é um código diferente que faz o trabalho.
$ git clone <repo_url> <project_dir>
$ cd <project_dir>
$ pip install pipenv
$ $ # clean pypi cache and make it ready to cache somehow - not described here
$ pipenv install -e .[test]
$ # if we need extra testing packages in pipenv
$ pipenv install <extra_test_packages>
$ # record current requirements expressed in `Pipfile.lock`
$ pipenv lock
$ # if needed, record the `Pipfile.lock` somewhere
Os resultados desse trabalho são:
Pipfile.lock
como dependências registradas (pode ajudar os desenvolvedores a reproduzir o ambiente facilmente)existem fases:
tox
, pip
etc. usando apenas nosso cache local pypipipenv
)Pipfile.lock
registra pacotes pypi que foram usados para instalar a biblioteca. Ele pode ser usado para reproduzir o ambiente no site do desenvolvedor.Outra vantagem é que esta configuração não requer que os desenvolvedores mantenham Pipfile
ou Pipfile.lock
. Também executar os testes em contextos diferentes é sempre igual ( Pipfile.lock
é sempre reconstruído em determinado contexto).
O cache pypi é a parte que precisa de alguma pesquisa. Eu acho que um diretório simples seria suficiente e talvez pipenv
já esteja pronto para ajudar com isso. Talvez a edição nº 1731 seja a parte que falta.
Como um pacote que faz a resolução de dependências, muitos de nossos próprios testes dependem de compilações determinísticas - isto é, pegando coisas conhecidas e esperando um gráfico resolvido. Usamos pytest-pypi
para isso.
Adoro a discussão animada sobre este tópico. Acho que a nuance é importante e você deve sempre testar as dependências conhecidas e também as não fixadas
você deve sempre testar as dependências conhecidas, bem como as não fixadas
Eu apoio esta sugestão. É uma boa ideia sempre ter um "estado bom conhecido" explícito para compilações reproduzíveis e simplificar a depuração no caso de uma atualização quebrar algo, além de garantir que as versões menores / de correção de bug também funcionem.
(Na minha opinião pessoal, a situação ideal seria que o gerenciador de pacotes instale as versões secundárias mais recentes por padrão para que as bibliotecas possam sempre especificar as versões de dependência concretas com as quais foram testadas, mas eu percebo que é uma opinião altamente controversa e requer todos para seguir sempre.)
@ Moritz90 @techalchemy @uranusjr @ tsiq-oliverc
Aqui está meu resumo da discussão anterior.
Pipfile.lock
arquivo (s)?Cada sistema operacional e interpretador python com suporte contribuem para a matriz de contextos de execução possíveis.
Por exemplo, suporte para Flask (pelo menos material CI visível no repositório):
Faz 9 contextos de execução diferentes que podem ser diferentes.
Cada contexto de execução pode ter Pipfile.lock
.
Quem deve mantê-los?
As opções são:
Pipfile.lock
para a plataforma de desenvolvimento principal (qual plataforma gosta de ser ignorada?)Proposta: Deixe o CI gerar o arquivo por pipenv install -e .
. Não o inclua no repo, ajude os desenvolvedores a escolher Pipfile.lock
adequados como resultado de compilações automatizadas.
Ao corrigir um problema, que pode ser causado por alterações de dependências no pypi, o desenvolvedor pode precisar de meios simples para reproduzir o ambiente do teste com falha.
Proposta:
Pipfile.lock
por pipenv install -e .
seguido por pipenv lock
.Pipfile.lock
do teste com falha.Pipfile.lock
em tox.ini
.setup.py
quebradoA biblioteca setup.py
pode estar quebrada (falta de dependência em install_requires
, falta de especificador de versão, etc.) e o teste de CI não deve ocultar tal problema (pré-instalando dependências omitidas por conta própria).
Proposta:
pipenv install -e .
para fornecer o mesmo resultado da instalação simples (atualmente existem alguns problemas com isso).pipenv
) e possivelmente compare que a saída pip freeze
resultante é um subconjunto do que é instalado por pipenv
.Alguma atualização de dependência pode quebrar a biblioteca usando-a. O CI deve detectar a falha em tal problema.
Proposta:
Pipfile.lock
, isso não é problema (já que executamos no modo não fixado de qualquer maneira)Em todos os modos propostos, tentei evitar manter pipenv
arquivos no repositório, evitando que os desenvolvedores mantenham essas coisas realmente complexas (automação !!!).
Em contraste com meu texto original, o segundo e terceiro modos usam pipenv
em scripts de CI.
Pacote simples com menor número de dependências que não mudam com frequência.
Simplesmente execute como antes da era pipenv
e mantenha as coisas simples para nós.
Casos raros em que dependências farão problemas são fáceis de corrigir e não justificam tornar a CI mais complexa.
Cada vez que o teste de CI é executado, gere um novo Pipfile.lock
que descreve completamente o ambiente usado no momento.
O Pipfile.lock
se tornará um artefato de CI.
Se as coisas derem errado, o desenvolvedor pode escolher Pipfile.lock
da compilação quebrada, aplicá-la localmente e fazer o teste e a correção.
Se alguém quiser implantar, Pipfile.lock
da última compilação bem-sucedida pode ser usado.
Quando a mudança de dependências for um problema real, o CI deve criar Pipfile.lock
uma vez e mantê-lo usando por determinado período (um mês?).
Isso torna a configuração do CI mais difícil, pois deve haver pelo menos dois jobs diferentes (um gerando Pipfile.lock
, o outro aplicando e usando em testes).
Aviso: Pipfile.lock
deve ser atualizado também no momento, setup.py
muda dependências.
Observe que a Idade do Gelo requer Scrat, o tipo de teste do esquilo que ignora o status congelado e verifica as versões não fixadas.
Como visto, o determinismo e a complexidade crescem de modo a modo.
Minha proposta seria:
Todos os ganhos custam alguma coisa.
Se o objetivo aqui é atualizar o conselho nos documentos, então honestamente parece irresponsável dizer algo dramaticamente diferente para "Siga as melhores práticas (compilações reproduzíveis) por padrão, até que você não tenha escolha."
@vlcinsky Sob o título "Modo: Gerar e selar", pode fazer sentido mencionar que o último Pipfile.lock
bem-sucedido deve sempre ser mantido por perto, por exemplo, declarando-o como um artefato Jenkins. Com essa mudança, seria bom recomendar essa configuração para a maioria dos projetos. Como @ tsiq-oliverc, eu não recomendaria o primeiro modo, nunca.
Quanto mais penso nisso, mais sinto que esta documentação se tornará uma seção sobre por que usar pipenv
para compilações de CI é uma ótima ideia, mesmo se você estiver desenvolvendo uma biblioteca.
@ tsiq-oliverc a grande maioria dos pacotes python gerais estão no modo "Executar, Forrest, Executar". Eu ajudei alguns desses pacotes com a introdução de tox
e pytest
, porque senti que isso contribuiria para a qualidade de determinado pacote e porque eu tinha uma ideia bastante clara de como isso poderia ser bem feito.
Agora, há outra grande ferramenta e eu me pergunto como usar pipenv
corretamente em projetos Python gerais para contribuir com sua qualidade. Quero encontrar uma ou duas receitas que funcionem bem, que sejam justificadas e fáceis de seguir.
O que eu diria ao projeto Flask?
Pipfile.lock
arquivos e configurar a política para atualizá-los?Pipfile.lock
artefato para casos em que alguém precisa reproduzir o teste com falha em seu próprio computador?O objetivo é encontrar um estilo de trabalho funcional. Se terminar em doc, bom, se não, não tem problema.
@vlcinsky Eu diria que (1) e (4) devem ser as recomendações para tais projetos. Embora sem um Pipfile.lock
pré-existente, você não saberá as versões usadas na compilação com antecedência (o que é bom fora de ambientes corporativos), você ainda obterá um resultado reproduzível se gerar e arquivar o arquivo de bloqueio durante a construção.
Edit : A versão tl; dr da minha recomendação seria:
pipenv
pode ajudá-lo a atingir esse objetivo.Pipfile.lock
em seu repositório e use-o para implantação. (Isso já está coberto pela documentação existente.)Pipfile.lock
on-the-fly em seu build de CI e arquive-o para mais tarde.(Claro, a documentação real deve ter um pouco mais de detalhes e exemplos.)
@ Moritz90 Modifiquei "Gerar e Selar" conforme você propôs.
Re (1): fácil de dizer, impossível de executar sem ser mais específico.
Re (4): sim, eu também acho que "Gerar e Selar" é o modo mais viável. Mas no caso do Flask não ousarei (pelo menos não no momento).
Pipfile.lock
re preexistente no ambiente empresarial: deve ser criado de alguma forma, (semi) manualmente ou automaticamente. Eu acho que no ambiente corporativo você não instala diretamente do pypi público, mas usa algum privado e que fornece apenas pacotes aprovados ( devpi-server
fornece um ótimo serviço nisso - índices múltiplos, volatilidade controlada de pacotes publicados, aprovações para externos pacotes etc.) Se o processo de construção de Pipfile.lock
rodar em tal ambiente, ele só pode usar o que for aprovado, então se uma nova versão deve aparecer lá, alguém tem que se levantar e torná-la aprovada. Seguir a construção do CI testará se ele não quebra as coisas. E com pipenv check
teste de problemas de segurança também pode ser automatizado.
Acho que esse fluxo de trabalho seria mais seguro em comparação com alguém criando-o (semi) manualmente. Mas meu conhecimento do ambiente corporativo é muito limitado.
Olá equipe pipenv. Eu compartilho muito do que é dito neste texto, ele ajuda muito qualquer desenvolvedor a entender melhor as limitações do Pipfile / pipenv ao desenvolver uma biblioteca. Eu quero ver este texto ou parte dele integrado na documentação oficial do pipenv.
Tenho a seguinte alteração que gostaria de discutir:
Para nosso pacote python interno, totalmente reutilizável, publicado em nosso pypi interno, etc, e até mesmo para meus próprios pacotes python (ex: cfgtree , txrwlock , pipenv-to-requirements ), eu uso um pacote que alguns já podem conhecer ou mesmo usar , que abstrai esses detalhes e torna a vida do desenvolvedor Python mais fácil: PBR.
O PBR basicamente lê requirements.txt
encontrado na pasta raiz de um pacote de distribuição e o injeta em install_requires
de setup.py
. O desenvolvedor simplesmente precisa manter um requirements.txt
com declarações de dependência soltas. Até que o suporte de Pipfile
seja integrado oficialmente dentro do PBR, eu tenho que usar pipenv-to-requirements que gera requirements.txt
automaticamente de Pipfile
para que ambos sejam sincronizados e ambos confirmados no código-fonte, e o PBR faz a injeção corretamente após o pacote de distribuição ter sido construído. Eu acho que alguém poderia usar pipenv
para gerar este requirements.txt
Eu trabalho em um suporte do Pipfile para PBR, de modo que ele possa ler o Pipfile
(e não o arquivo de bloqueio) e injetá-lo em install_requires
como faz com requirements.txt
.
Não sei se existem outros pacotes semelhantes, porque ele também faz outras coisas que as pessoas podem não querer (versão do histórico do git, geração automática de AUTHORS e ChangLog).
Mas no final, eu realmente sinto que é tão mais fácil escrever, manter e lidar com o controle de versão de uma biblioteca Python, eu ficaria triste se não compartilhasse essa experiência. Estou promovendo-o como a maneira "recomendada" de escrever bibliotecas Python modernas em minha empresa.
Eu reconheço que é como "trapacear" em todas as dificuldades sobre biblioteca e pipenv, mas no final o trabalho está feito e os desenvolvedores estão felizes em usá-lo até agora. Parte do treinamento de python, que estou dando para o novo desenvolvedor de python em minha empresa, envolve, primeiro, escrever uma biblioteca python mantendo install_requires
manualmente e, em seguida, mudar para PBR
para ver como fica mais fácil ( e, francamente, eu sou um fã do recurso de
Parte do motivo para declarar as dependências das bibliotecas usando um arquivo dedicado também para bibliotecas é poder usar ferramentas como readthedocs ou pyup (mesmo se o pyup fizer mais sentido quando vinculado a um aplicativo).
Não quero necessariamente promover este método como a maneira "padrão" de fazer o pacote python, na verdade é a maneira "OpenStack", mas gostaria de compartilhar minha experiência, e se outros tiverem experiências semelhantes ou contraditórias, estarei feliz em ouvi-los e atualizar meu ponto de vista.
Equipe, o que você acha de uma espécie de seção de "comunidade" na documentação? Para que usuários como eu possam compartilhar sua experiência sobre como ele usa o pipenv, sem necessariamente o endosso total da equipe do pipenv?
PS: Posso mover isso para um problema dedicado, se você não quiser poluir este tópico
@vlcinsky (1) é muito fácil de executar - coloque seu lockfile em seu repo.
Acho que o que você quer dizer é: é impossível dar conselhos específicos, uma vez que essa estratégia básica não é mais suficiente. Isso certamente é verdade, mas isso ocorre porque o problema específico provavelmente difere caso a caso.
Ou, dito de outra forma, a solução depende de quais garantias adicionais você deseja que seu fluxo de trabalho de CI forneça.
@gsemet você sabe o quê? Todos os meus pacotes python criados nos últimos dois anos são baseados em pbr
- é realmente ótimo. E eu sigo suas tentativas de apoiar Pipfile no pbr sempre que posso (alguns polegares para cima, votos etc).
No caso deste problema (procurando por pipenv
padrões e antipadrões para bibliotecas python gerais), omiti pbr
intencionalmente por dois motivos:
pbr
por outros motivos (você os mencionou) e isso provavelmente desviaria a discussãoPor outro lado, estou ansioso por uma receita sua para os amantes do pbr. Eu lerei isto.
@ tsiq-oliverc, você acertou o prego: coloque seu arquivo de bloqueio em seu repo
Este é exatamente o problema que me motivou a iniciar esta edição. Se você reler o início deste problema, encontrará a descrição de alguns casos, em que adicionar Pipfile.lock
pode interromper seus testes de CI (interrompendo a execução da compilação ou ocultando problemas, que de outra forma seriam detectados, ou instalando dependências erradas para determinado contexto ...).
Se você me mostrar um repositório, onde isso é feito corretamente (biblioteca python geral), eu ficaria feliz. Ou eu demonstraria quais riscos existem ou quais coisas estão inacabadas.
Legal ! Eu também mantenho este cortador de cozinha :)
@vlcinsky Certo, então vamos enumerar os problemas específicos e encontrar soluções para eles 😄 (não conheço nenhuma biblioteca de alta qualidade que use o Pipenv, mas principalmente porque não procurei.)
Tanto quanto posso dizer, estes são os sintomas específicos em sua postagem original:
pipenv install -e .
, certo?@ tsiq-oliverc Devo dizer que seus comentários me inspiraram e sei que eles contribuíram para um maior nível de reprodutibilidade da solução proposta.
A seguir está relacionado à sua proposta de colocar o arquivo de bloqueio ( Pipfile.lock
) no repositório para garantir a repetibilidade:
re Escondendo dependências de setup.py quebradas. . O pipenv install -e .
segue o que proponho, mas note que este não é o uso de Pipfile.lock
, é um método para (re) criá-lo. Se alguém mantiver Pipenv.lock
e usá-lo para criar o virtualenv antes de instalar o pacote, o problema está presente.
É provável que as dependências re doit
instalado para Python 2.7 deve ser uma versão mais antiga, pois a mais recente abandonou o suporte para Python 2.x. watchdog
dependency requer bibliotecas dependentes de plataforma: inotify no Linux, algo mais no Windows, algo mais no OSX. Meu ex-cliente costumava dizer "Isso nunca vai acontecer" e em 50% das situações aconteceu em 2 semanas. Essa não é a prática recomendada para scripts de CI.
Os desenvolvedores são forçados a atualizar .. Imagine biblioteca de código aberto com 15 colaboradores. É tão fácil esquecer a regeneração de Pipfile.lock
por um desenvolvedor de núcleo recém-chegado ou cansado. Por exemplo, no pacote maya
, fui solicitado a regenerar o Pipfile.lock
pois uma nova dependência foi adicionada a setup.py
. Isso foi necessário? Eu atualizei corretamente? Eu atualizei para todos os contextos de execução suportados? As respostas são não, não tenho certeza, não. De qualquer forma, obrigado pela sua proposta (me inspirou para a solução descrita ao lado do seu comentário).
re Competindo com tox : Tox permite a criação de múltiplos virtuaisenvs e automação da execução de testes dentro deles. tox.ini
típico define virtualenvs diferentes para python 2.7, 3.4, 3.5, 3.6 e qualquer outro que você precisa, e permite instalar o pacote lá e executar o conjunto de testes. É uma ferramenta elétrica estabelecida para testadores sérios. pipenv
não é a ferramenta para este propósito, mas pode interferir na instalação das coisas necessárias. De certa forma, segui seu conselho e propus usar uma ferramenta superior (tox) acima de pipenv
onde possível.
re Pipenv falha. Isso é realmente lamentável. Eu tive o teste de CI (baseado em tox) que rodou bem no localhost, mas quando executado via Travis, ele falhou devido ao problema de pipenv
. Se eu quiser usar agora, a fixação não ajudará até que a correção seja lançada. Mas é assim que acontece - vou esperar.
Observe que algumas partes do meu post original terão que ser atualizadas como parece, usando pipenv
em scripts de CI em seu lugar justificado ("selando" a configuração do virtualenv para possível uso posterior).
@ tsiq-oliverc Embora inicialmente tenha gostado da sua sugestão de testar tanto o "bom conhecido" quanto as versões mais recentes, acho cada vez mais difícil justificar o esforço quanto mais penso a respeito. Acho que você deve decidir fazer um ou outro, não ambos.
A única coisa que você ganha é que saberá imediatamente se uma falha foi causada por uma atualização de dependência ou alteração de código. Mas você pode conseguir o mesmo simplesmente fazendo commits separados (ao atualizar manualmente as dependências bloqueadas) ou tentando reproduzir o bug com o arquivo de bloqueio mais recente produzido por uma compilação bem-sucedida (sempre usando as versões mais recentes). E em ambientes restritos, você não pode "apenas atualizar" de qualquer maneira ...
@vlcinsky Embora eu concorde com seu ponto geral sobre as diferenças entre ambientes, o argumento "um arquivo de bloqueio por configuração" soa como um espantalho para mim. Na prática, você poderá compartilhar os arquivos de bloqueio entre pelo menos alguns dos ambientes.
Uma questão em aberto que ainda não foi respondida é como lidar com o caso em que vocês dois precisam testar em ambientes diferentes e bloquear suas dependências. Tenho que admitir que não sei nada sobre tox
além de sua existência, mas parece que há necessidade de algum tipo de cola entre tox
e pipenv
isso resolve esse problema de alguma forma.
@ Moritz90
Em relação a muitas variantes de Pipfile.lock
servindo como espantalho (para manter os outros fora do meu campo):
Peguei o projeto flask
(considerando-o muito maduro) e executei testes toxicológicos:
Aqui você vê a lista de variantes testadas (apenas localmente no Linux, multiplique por 3 como o Windows e o OSX fará o mesmo conjunto de testes, mas pode resultar em ambientes diferentes).
Existem 16 execuções de teste diferentes em um sistema operacional, 5 deles falharam porque eu não os tenho instalados (tudo bem), um está lidando com a construção de documentos (requer biblioteca importante) e outro com cobertura (que também requer biblioteca importável ):
coverage-report: commands succeeded
docs-html: commands succeeded
py27-devel: commands succeeded
py27-lowest: commands succeeded
py27-simplejson: commands succeeded
py27: commands succeeded
py35: commands succeeded
py36-devel: commands succeeded
py36-lowest: commands succeeded
py36-simplejson: commands succeeded
py36: commands succeeded
ERROR: py34: InterpreterNotFound: python3.4
ERROR: pypy-devel: InterpreterNotFound: pypy
ERROR: pypy-lowest: InterpreterNotFound: pypy
ERROR: pypy-simplejson: InterpreterNotFound: pypy
ERROR: pypy: InterpreterNotFound: pypy
Para cada um dos virtuaisenvs criados, criei requirements.txt
arquivo por pip freeze > {venv_name}.txt
Em seguida, hashes calculados para os arquivos, classificados de acordo com os valores de hash, para que todos sejam agrupados. Aí vem o espantalho:
b231a4cc8f30e3fd1ca0bfb0397c4918f5ab5ec3e56575c15920809705eb815e py35.txt
b231a4cc8f30e3fd1ca0bfb0397c4918f5ab5ec3e56575c15920809705eb815e py36.txt
cdf69aa2a87ffd0291ea65265a7714cc8c417805d613701af7b22c8ff2b5c0e4 py27-devel.txt
dfe27df6451f10a825f4a82dfe5bd58bd91c7e515240e1b102ffe46b4c358cdf py36-simplejson.txt
e48cd24ea944fc9d8472d989ef0094bf42eb55cc28d7b59ee00ddcbee66ea69f py36-lowest.txt
f8c745d16a20390873d146ccb50cf5689deb01aad6d157b77be203b407e6195d py36-devel.txt
053e107ac856bc8845a1c8095aff6737dfb5d7718b081432f7a67f2125dc87ef docs-html.txt
45b90aa0885182b883b16cb61091f754b2d889036c94eae0f49953aa6435ece5 py27-simplejson.txt
48bd0f6e66a6374a56b9c306e1c14217d224f9d42490328076993ebf490d61b5 coverage-report.txt
564580dad87c793c207a7cc6692554133e21a65fd4dd6fc964e5f819f9ab249c py27.txt
8b8ff4633af0897652630903ba7155feee543a823e09ced63a14959b653a7340 py27-lowest.txt
Assustador, não é? De todos os testes, apenas dois compartilham as mesmas dependências congeladas.
Esta é a realidade da biblioteca python geral com um bom conjunto de testes. Você provavelmente vai admitir que isso é algo bem diferente da biblioteca python testada em ambiente corporativo.
Verificando jinja2
, que parece ser uma besta muito mais simples:
coverage-report: commands succeeded
py26: commands succeeded
py27: commands succeeded
py33: commands succeeded
py35: commands succeeded
py36: commands succeeded
ERROR: docs-html: commands failed
ERROR: py34: InterpreterNotFound: python3.4
ERROR: pypy: InterpreterNotFound: pypy
Ao ver as somas de verificação, fico surpreso, pois py27.txt e py26.txt são diferentes:
047a880804009107999888a3198f319e5bbba2fa461b74cfdfdc81384499864e py26.txt
047a880804009107999888a3198f319e5bbba2fa461b74cfdfdc81384499864e py33.txt
047a880804009107999888a3198f319e5bbba2fa461b74cfdfdc81384499864e py35.txt
047a880804009107999888a3198f319e5bbba2fa461b74cfdfdc81384499864e py36.txt
48bd0f6e66a6374a56b9c306e1c14217d224f9d42490328076993ebf490d61b5 coverage-report.txt
743ad9e4b59d19e97284e9a5be7839e39e5c46f0b9653c39ef8ca89c7b0bc417 py27.txt
@vlcinsky Isso é realmente assustador. Estou me perguntando se o Flask é um caso especial ou se isso é realmente a norma, mas você definitivamente provou que estou errado.
Agora espero que nossa biblioteca Python não sofra do mesmo problema algum dia e que as diferenças sejam mais administráveis lá.
@ Moritz90 Sua biblioteca interna está servindo a um público completamente diferente, então você pode manter o contexto de execução muito mais restrito.
Bibliotecas python gerais são frequentemente flexíveis e configuráveis, por exemplo, Flask permite que analisadores json alternativos sejam instalados e usados o que é coberto por uma execução de teste separada.
Pode-se aprender muito sobre testes e toxidade com o tox.ini
do Flask
as variantes de teste mais baixas devem ter o cuidado de testar a versão de dependência mais antiga.
devel está testando em relação à versão de desenvolvimento das dependências principais.
Eu diria que o Flask está no nível mais alto de complexidade e exibe um conjunto de testes cuidadoso.
O tox.ini da pirâmide mostra um número semelhante de ambientes (eles também visam a 100% de cobertura de código).
O tox.ini de maya é muito fresco (2 dias) e simples, mesmo aqui existem 4 ambientes diferentes e py27 difere em requisitos de congelados de py35 e py36.
@ Moritz90
Em relação à cola entre pipenv e tox
pipenv --man
mostra algumas instruções, como usar pipenv
dentro de tox.ini
comandostox.ini
file permite a execução de comandos arbitrários, então isso inclui pipenv
.
pipenv
tem um ótimo recurso, que quando executado no virtualenv já ativado (o que é o caso no teste baseado em tox), ele instala em um determinado ambiente virtual. Isso é muito bom.
Como provavelmente precisamos de Pipfile.lock
gerados, algum esforço extra deve ser feito para obtê-lo e mover para o lugar apropriado (ag em .tox/py36/Pipfile.lock
para evitar sobrescrever seguindo o teste. Isso deve ser possível, mas com alguma simplificação seria bem-vindo. Talvez algum truque com a variável ambiental para a localização de Pipfile
tornasse isso ainda mais simples.
@vlcinsky
pipenv install -e .
uma vez para que setup.py agora seja rastreado por meio de seu arquivo de bloqueio. E então execute pipenv install
sempre que adicionar novos pacotes ao setup.py.pipenv --deploy
foi projetado para detectar isso. Execute no seu CI!update-all-lockfiles.sh
localmente e executar pipenv --deploy
em seu CI para detectar erros.@ Moritz90 - Concordo, a abordagem das "duas fases" pode ser exagerada na maioria dos casos. Em particular, se você estiver fazendo atualizações "manuais" deliberadas / intencionais em seu arquivo de bloqueio, isso é completamente desnecessário.
De maneira mais geral, seria bom garantir que essa "proposta" se concentre nas coisas que são realmente problemas difíceis (na minha opinião, isso é (A) servindo vários envs, (B) querendo pegar mudanças nas dependências upstream). Não deve ser baseado em coisas transitórias (bugs no Pipenv) ou potenciais mal-entendidos de como a ferramenta deve ser usada.
Mas mesmo para aqueles problemas "difíceis", o enquadramento deve ser como "em alguns casos extremos complexos, você pode achar que um fluxo de trabalho básico do Pipenv é insuficiente, então aqui estão algumas coisas para se pensar". IMO, não deve ser enquadrado como a abordagem padrão (porque a maioria das pessoas não terá essas preocupações).
O exemplo de documentação fornecido por @vlcinsky ficaria mais simples e menos confuso se o Pipenv / Pipfile permitisse o manuseio de lib-dependencies
, app-dependencies
e dev-dependencies
. Os documentos podem ser parecidos com isto:
Use a opção lib-dependencies
se o pacote for uma biblioteca compartilhada. Exemplo Pipfile
:
[lib-dependencies]
some-lib=="*"
another-lib=="*"
yet-another-one==">=1.0"
[dev-dependencies]
some-dev-tool=="1.1"
Para bibliotecas compartilhadas, é importante manter os intervalos de versão abaixo de [lib-dependencies]
tão amplos quanto possível, para evitar conflitos de versão no sistema do consumidor.
Se o seu pacote for um aplicativo (destinado a ser instalado por pipenv no sistema de destino) que requer versões de dependência exatas, você deve usar a opção [app-dependencies]
. Exemplo Pipfile
:
[app-dependencies]
some-lib=="1.0.12"
another-lib=="1.*"
yet-another-one=="2.0"
[dev-dependencies]
some-dev-tool=="1.1"
/ Exemplo de fim de documento
Outra abordagem poderia ser Pipfile.lib
e Pipfile.app
.
Acho que algo assim omitiria a necessidade de um pedaço de seções antipadrão e ferramentas de terceiros para preencher a lacuna.
Chamar a ferramenta de empacotamento pipenv é enganoso se alguém espera que ela crie bibliotecas Python ou esteja profundamente envolvido na criação delas.
Acho que este é um problema real, o que leva a muita confusão. Especialmente entre pessoas que estão acostumadas com gerenciadores de pacotes em outras linguagens de programação (por exemplo, JS, Rust, Elm). Levei vários meses e leituras ocasionais dos problemas do GIthub, até que percebi que estava usando o Pipenv e o setup.py da maneira errada.
@feluxe
Sua [lib-dependencies]
ou Pipfile.lib
é o que temos hoje em Pipfile
(como dependências abstratas - sendo as mais amplas possíveis).
Seu [app-dependencies]
ou Pipfile.app
é o que temos em Pipfile.lock
(como dependências específicas).
pipenv
e seus arquivos podem ser usados em duas situações diferentes - desenvolver uma biblioteca ou preparar uma implementação de aplicativo, mas provavelmente não para ambos ao mesmo tempo. Por esta razão, não vejo fortes motivos para adicionar seções extras em Pipenv
. É responsabilidade do desenvolvedor saber a que tipo de propósito o Pipfile
vai servir.
Acho que este é um problema real, o que leva a muita confusão. Especialmente entre pessoas que estão acostumadas com gerenciadores de pacotes em outras linguagens de programação (por exemplo, JS, Rust, Elm). Levei vários meses e leituras ocasionais dos problemas do GIthub, até que percebi que estava usando o Pipenv e o setup.py da maneira errada.
Concordou. A solução de três seções também é uma solução muito interessante que nunca considerei, e parece ser correta e (surpreendentemente!) Simples.
Vindo de experiência em Python, sempre achei que o package.json do Node está fazendo isso errado (Rust é melhor porque tem um compilador e um vinculador e pode resolver isso em um estágio posterior). Tratar dependências de aplicativo e lib da mesma maneira simplesmente não funcionará para uma linguagem de script como Python, pelo menos em um sentido abstrato - ou seja, pode funcionar para você, mas uma ferramenta genérica como Pipenv não pode fazer isso porque precisa ser genérico.
Embora eu goste do conceito da solução de três seções, ainda é uma mudança bastante incompatível com o ecossistema existente. Já há setup.py, setup.cfg e (potencialmente) pyproject.toml preenchendo este espaço. Se o Pipenv (Pipfile, para ser exato) quiser se mover para o espaço, ele precisa consolidar com projetos relacionados, como pip (o suporte à biblioteca deve ser idealmente suportado diretamente por ele) e flit .
Como mencionei em outras questões relacionadas ao tratamento de dependência lib / app, esta discussão precisa ser escalada para pypa-dev (a lista de discussão) e / ou o processo PEP, para que possa ser melhor ouvida por outras partes e pessoas relevantes, antes do Pipenv (Pipfile) pode se mover em qualquer direção.
@vlcinsky
Seu [lib-dependencies] ou Pipfile.lib é o que temos hoje no Pipfile (como dependências abstratas - sendo o mais amplo possível).
Desculpe se não ficou claro. Meus lib-dependencies
devem ser o que as pessoas atualmente colocam em setup.py
/ install_requires
. Talvez pypi-dependencies
fosse um nome melhor para o que eu quis dizer.
@uranusjr
Já há setup.py, setup.cfg e (potencialmente) pyproject.toml preenchendo este espaço.
Pipenv (a ferramenta de linha de comando) pode fazer a interface setup.py
. Apenas a seção de dependência de setup.py
teria que ser movida para o Pipfile. Pelo menos na minha imaginação :)
Como mencionei em outras questões relacionadas ao tratamento de dependência lib / app, esta discussão precisa ser escalada para pypa-dev (a lista de discussão) e / ou o processo PEP, para que possa ser melhor ouvida por outras partes e pessoas relevantes, antes do Pipenv (Pipfile) pode se mover em qualquer direção.
Ok, desculpe incomodar;) Se eu encontrar algum tempo, vou escrever algo para a lista de mailling.
No escopo desta proposta, no entanto, eu sugeriria que ela se concentrasse nas melhores práticas atualmente possíveis, em vez de entrar na toca do coelho de elaborar um novo fluxo de trabalho para toda a comunidade de pacotes Python. Seria mais produtivo propor uma prática recomendada dentro das restrições atuais e , em
@uranusjr - Eu venho de um background "compilado", então estou curioso para
Tratar dependências de aplicativo e lib da mesma maneira simplesmente não funcionará para uma linguagem de script como Python
@ tsiq-oliverc Como a melhor prática do aplicativo requer que você fixe suas dependências, as bibliotecas também começariam a fixar as suas, se usassem a mesma fonte de arquivos de requisitos. Isso levaria a problemas na resolução de dependências.
Digamos que meu aplicativo tenha duas dependências A e B, ambas dependem de C, mas A fixa v1, enquanto B fixa v2. As linguagens compiladas permitem que a cadeia de ferramentas detecte isso em tempo de compilação e resolva de várias maneiras. Rust, por exemplo, faz isso durante o tempo de vinculação - O executável final conteria duas cópias de C (v1 e v2), com A e B vinculando cada uma delas. No terreno do C ++, isso seria resolvido com bibliotecas dinâmicas; a pesquisa de símbolo é feita ainda mais tarde (em tempo de execução), mas a ideia é a mesma - o compilador sabe o que você precisa (a partir da interface que você usa) e pode agir de acordo.
As linguagens de script não podem fazer isso porque não sabem o que você realmente deseja fazer até que realmente alcance a chamada. O Node contorna isso sempre assumindo que as dependências são incompatíveis (A e B sempre obtêm seu próprio C, mesmo se as duas cópias forem idênticas), mas isso leva a uma nova classe de problemas e resulta em hacks estranhos, como dependências de pares que todos (Espero?) Concorda são terríveis. O Python provavelmente não quer fazer isso (não pode, de qualquer maneira, já que isso provavelmente interromperia todas as instalações existentes do Python).
Outra maneira de contornar isso é fazer algo inteligente nas ferramentas de empacotamento que “desencadeia” a versão de dependência. Bundler (de Ruby) meio que faz isso, recomendando às pessoas que não incluam o arquivo de bloqueio no gem, para que o Bundler possa usar as versões não fixadas em Gemfile, em vez de versões fixadas em Gemfile.lock. Mas as pessoas tendem a ignorar os conselhos e fazer o que quiserem, então você ainda tem versões fixas em todos os lugares.
Provavelmente fui um pouco forte demais para dizer que simplesmente não funcionaria . Mas pelo menos todas as tentativas anteriores falharam, e muitos dos que tentaram são pessoas muito inteligentes, muito mais inteligentes do que eu. Não acho que isso possa ser feito, pessoalmente, e continuaria pensando dessa forma até ver a proposta muito brilhante que realmente faz isso.
@ tsiq-oliverc Pieter Hintjens escreveu em algum lugar o conceito de "Comentários são bem-vindos na forma de solicitação pull"
Gosto disso porque muda o foco de conselhos filosóficos para coisas realmente tangíveis e práticas. E também limita o número de comentários porque um comentarista frequentemente aprende que a ideia está incompleta ou de alguma forma quebrada no uso real.
Eu pedi a você um exemplo de biblioteca python, onde pipenv
é usado corretamente (ou pelo menos usado) e você não forneceu nenhum.
Você comenta sobre as qualidades de tox
, mas admite que não está familiarizado com elas, ainda repetindo algo sobre as melhores práticas no mundo do desenvolvimento de pacotes python.
Você diz que Flask
é possivelmente um caso especial. Então, pesquisei no Github por projetos python usando a palavra "biblioteca", classificados de acordo com o número de garfos (já que provavelmente reflete quantas pessoas estão fazendo algum desenvolvimento com ele), ignorei todas as "listas atualizadas de algo" e contei o número de ambientes para um SO (normalmente Linux):
O número real de ambientes nos quais os testes serão executados será 2 (+ Windows) ou 3 (+ OSX) vezes maior.
tox
é usado em 2 de 3 projetos (não o comparo ao Travis ou Appveyor, pois eles fazem outro nível de teste ao lado).
O número de ambientes para testar é bastante alto, Flask definitivamente não é o mais selvagem.
O número de ambientes para os quais definir dependências fixas não é gerenciável manualmente.
Simplesmente soltar Pipfile.lock
em um repositório é bastante fácil, mas não faz nenhuma melhora mágica (se sim, mostre-me o cenário real, quando isso vai melhorar a situação).
Talvez você conheça a regra de ouro do mundo "compilado" e sinta que o determinismo (ou repetibilidade) é uma obrigação para o Python também. Como você pode ver, muitos projetos Python vivem muito bem sem ele, então pode ser que a regra de ouro não se aplique tão estritamente aqui.
Ficarei feliz se encontrarmos o uso de pipenv
para bibliotecas python, o que irá melhorar a situação. E quero evitar o uso, o que prejudicaria a qualidade geral.
Para alcançar esse objetivo, minha abordagem é iterar sobre as perguntas:
@feluxe
Desculpe se não ficou claro. Minhas dependências de lib devem ser o que as pessoas atualmente colocam em setup.py / install_requires. Talvez dependências de pypi seja um nome melhor para o que eu quis dizer.
Veja pbr
discussão nesta edição. É o esforço para oferecer suporte às dependências de biblioteca do Pipfile.
Acho que Pipfile
não deve ser usado para dois propósitos (lib e app), essas coisas devem ser feitas separadamente. Se você sentir que é realmente necessário, você poderia descrever o propósito de um projeto usando-o? Normalmente tento manter os projetos de desenvolvimento e implantação de bibliotecas separados, pois eles têm usos bastante diferentes no tempo.
@vlcinsky Não tenho certeza de onde você quer levar isso (não tenho certeza de que tipo de relações públicas você está pedindo!), então vou sair desta conversa por enquanto.
Para reafirmar o TL; DR da minha posição:
@uranusjr Entendi. Embora eu não ache que haja nada específico de linguagem aqui, é simplesmente que diferentes comunidades estabeleceram diferentes heurísticas para lidar com um problema sem solução genérica - se você tiver conflitos de versão, você tem um problema.
Maven / Java (por exemplo) força você a pensar sobre isso no momento da construção. A maneira NPM significa que você terá problemas de tempo de execução se as versões incompatíveis cruzarem uma interface. Resolução de tempo de execução (por exemplo, Python, bibliotecas dinâmicas) significa que um dependente pode travar / etc. se a versão da dependência não for a esperada.
@vlcinsky
Veja a discussão do pbr nesta edição. É o esforço para oferecer suporte às dependências de biblioteca do Pipfile.
pbr parece bom e tudo, mas se enquadra na categoria que eu estava tentando abordar com isto:
Acho que algo assim omitiria a necessidade de um pedaço de seções antipadrão e ferramentas de terceiros para preencher a lacuna.
Acho que essas ferramentas não deveriam ser necessárias em primeiro lugar.
Se você sentir que é realmente necessário, você poderia descrever o propósito de um projeto usando-o? Normalmente tento manter os projetos de desenvolvimento e implantação de bibliotecas separados, pois eles têm usos bastante diferentes no tempo.
Quando se trata de pacotes pypi, acabei usando Pipenv para lidar com dev-dependências, Pipfile
para descrever dev-dependências, setup.py
para descrever dependências lib com install_requires
e setuptools
em setup.py
para publicar meu pacote executando pipenv run python setup.py bdist_wheel upload
. Isso é o que considero complicado.
Em outras linguagens modernas, tenho que aprender uma ferramenta de linha de comando (gerenciador de pacotes) mais um formato de arquivo de dependência. A documentação está em um lugar e é mais fácil de seguir e um recém-chegado resolverá tudo isso em algumas horas. É uma questão de npm init
, npm install foo --dev
, npm publish
. Pipenv / Pipfile já pode fazer a maior parte disso, se pudesse fazer tudo, problemas como este não existiriam.
Reinterrupto minha convocação para uma espécie de seção / wiki de "comunidade" para esta discussão. Existem vários "padrões" que podem ser legítimos e alguns de nós podem querer compartilhá-los "maneira de fazer bibliotecas python", alguns como eu com pbr, e outros podem ter um padrão muito bom. Mas uma página dentro do documento pipenv, não tenho certeza se é uma boa ideia.
PS: para preparar a migração para o novo pypi, você deve usar twine e não python setup.py upload. Usar "upload" deve ser considerado um antipadrão.
Talvez o pipenv possa desenvolver comandos de "publicação"?
@feluxe Você pode querer dar uma olhada na poesia . Eu simplesmente tropecei nele e parece que é o que você está procurando.
Ele faz o que pipenv
faz e muito mais e parece que eles fazem isso melhor, especialmente em relação ao gerenciamento de dependências (pelo menos é o que eles fingem). Ele faz gerenciamento de dependências, empacotando e publicando tudo em uma única ferramenta poetry
.
Eu me pergunto se pipenv
e poetry
poderiam reunir esforços para finalmente dar ao Python um verdadeiro gerenciador de pacotes.
Quero me reiterar antes que essa discussão vá longe demais. O Pipenv não pode simplesmente desenvolver um comando publish
ou fazer qualquer coisa que tente assumir a tarefa de empacotamento. Isso só fragmentaria mais o ecossistema, porque nem todo mundo faz dessa maneira, e com as dependências de app e lib teoricamente diferentes, você não pode dizer a alguém para mesclá-los novamente depois que a distinção for feita em seu fluxo de trabalho.
Pode parecer que quase todos concordam com essa mesclagem, mas a verdade é que há muito mais pessoas que não estão participando dessa discussão porque as coisas funcionam para elas e elas estão fazendo outra coisa. Eu já disse isso várias vezes: a discussão sobre como melhorar o design de conjuntos de ferramentas e formatos de arquivo deve acontecer em algum lugar superior na hierarquia de pacotes do Python, para que receba mais exposição de pessoas que projetam coisas mais fundamentais nas quais o Pipenv depende. Por favor, leve a discussão lá. Não adianta sugerir aqui, porque Pipenv não está em posição de alterá-lo.
Eu já disse várias vezes: A discussão sobre como melhorar o design de conjuntos de ferramentas e formatos de arquivo deve acontecer em algum lugar mais alto na hierarquia de pacotes do Python, para que receba mais exposição às pessoas que projetam coisas mais fundamentais nas quais o Pipenv depende.
Concordo que a discussão sobre esse bug está fora de controle agora que o empacotamento e a publicação surgiram (esse bug é apenas sobre gerenciamento de dependências!), Mas você poderia nos indicar o lugar certo para ter essa discussão? As pessoas estão tendo isso aqui porque o pipenv é visto como um passo muito necessário na direção certa, não porque eles querem impor responsabilidades adicionais aos mantenedores do pipenv.
Edit : Desculpe, devo ter perdido o post em que você fez exatamente isso ao ler os novos comentários pela primeira vez.
No escopo desta proposta, no entanto, eu sugeriria que ela se concentrasse nas melhores práticas atualmente possíveis, em vez de entrar na toca do coelho de elaborar um novo fluxo de trabalho para toda a comunidade de pacotes Python. Seria mais produtivo propor uma prática recomendada dentro das restrições atuais e, em seguida, iniciar a discussão para melhorias.
Eu concordo muito com isso. Devemos primeiro descobrir qual é o melhor fluxo de trabalho possível para os mantenedores de bibliotecas agora, antes de chegarmos a grandes planos. Portanto, vamos nos concentrar nisso novamente, como fizemos no início deste tópico. Acho que ainda não chegamos a uma conclusão.
Voltar ao tópico: Citando a postagem de
Outra maneira de contornar isso é fazer algo inteligente nas ferramentas de empacotamento que “desencadeia” a versão de dependência. Bundler (de Ruby) meio que faz isso, recomendando às pessoas que não incluam o arquivo de bloqueio no gem, para que o Bundler possa usar as versões não fixadas em Gemfile, em vez de versões fixadas em Gemfile.lock. Mas as pessoas tendem a ignorar os conselhos e fazer o que quiserem, então você ainda tem versões fixas em todos os lugares.
Provavelmente fui um pouco forte demais para dizer que simplesmente não funcionaria. Mas pelo menos todas as tentativas anteriores falharam
Ainda não vejo por que a recomendação oficial para bibliotecas por agora não pode ser usar pipenv
para suas compilações de CI, mas manter Pipfile.lock
fora do controle de origem. Visto que, como algumas pessoas apontaram, pipenv
não tem nada a ver com o processo de empacotamento, não devemos nos deparar com o problema que você descreveu acima.
E também não vejo por que isso é um argumento contra a definição de suas dependências abstratas no mesmo arquivo que os aplicativos usam para definir suas dependências abstratas. Tudo bem se pipenv
não quiser implementar uma solução elaborada para integrar Pipfile
com setup.py
, mas não vejo por que isso é uma má ideia em geral.
@vlcinsky
Eu acho que um Pipfile não deve ser usado para duas finalidades (lib e app), essas coisas devem ser feitas separadamente.
Veja meu post acima. Você poderia explicar por que você acha isso? Simplesmente não consigo ver nenhuma desvantagem em princípio. No momento, pode ser uma má ideia incluir Pipfile
, já que você terá que definir as dependências da mesma maneira em dois arquivos diferentes, mas ainda não vi nenhum argumento que explique o porquê seria uma má ideia usar Pipfile
para declarações de dependência em geral.
Observe que já concordei que Pipfile.lock
não deve estar no controle de origem das bibliotecas, a menos que você esteja na mesma situação em que estou.
Editar : Além disso, se descobrir que pipenv
si realmente precisa saber sobre a diferença, você pode apenas introduzir algo como o campo crate-type
da carga antes de começar a introduzir app-dependencies
e lib-dependencies
- isso parece muito complicado.
@ Moritz90 Várias listas de discussão do Python seriam bons locais para manter essa discussão.
pypa-dev é o mais definitivo para discussões centradas no empacotamento do Python e no ecossistema ao seu redor. Eu provavelmente começaria aqui se fosse postar uma discussão semelhante.
python-ideas é um lugar para discutir ideias e tem grande visibilidade para toda a comunidade Python. Também seria um bom ponto de partida se você quiser levar isso para o nível PEP (eventualmente você o faria, eu acho).
@ tsiq-oliverc
Por RP, quero dizer: mostre um exemplo que prova a viabilidade de seu conceito.
Então, pegue alguma biblioteca existente, bifurque-a, aplique seu (1) - você diz que será fácil com pipenv
e mostre-me. Eu tentei muito e tenho dificuldades.
Se seu (2) significar "outra pessoa tem que fazer o trabalho", seu RP não existirá.
Em (3), você fala sobre "pequeno subconjunto de casos" sem fornecer nenhum número real. Todas as principais bibliotecas que descrevi em relação ao número de virtualenvs são consideradas "pequeno subconjunto"?
Para concluir esta discussão, criei um breve resumo do que foi encontrado durante a discussão.
pipenv
(anti) padrões para bibliotecas e aplicativos PythonMudei um pouco o foco: ele fala não apenas sobre bibliotecas Python (gerais), mas também sobre aplicativos, pois foi bastante barato incluí-lo e demonstra bem as diferenças.
Excluí intencionalmente qualquer coisa que propusesse mudanças nas ferramentas existentes, como pipenv
, tox
etc.
pipenv
e o que não éPipfile.lock
.O produto (software python) está pronto para ser usado em outro produto (portanto, biblioteca) ou é o aplicativo final pronto para ser executado.
Pessoalmente, acho que até mesmo "bibliotecas corporativas" se enquadram na categoria de biblioteca (as mesmas regras se aplicam, apenas o número de contextos de execução é menor).
pipenv install <package>
portanto, "coloque o pacote em ação (resolvendo versões para outras bibliotecas)"pipenv sync
portanto, "aplique dependências concretas"dependências concretas: devem fixar versões, de preferência com hashes de bibliotecas usadas
pipenv
artefatos:Pipfile
: dependências abstratas
Pipfile.lock
: dependências concretas (bloqueadas) "tox
ou software de teste semelhantepipenv
e dependências concretas (pode ser adequado para bibliotecas)Pipfile
no repositórioPipfile.lock
criado por pipenv install -e .
Pipfile.lock
documenta (sela) o ambiente e permite a reprodução posterior do virtualenv para análise de problemas.Modo: "Idade do Gelo"
setup.py
install_requires
) mudança ou pacote dependente em pypi é atualizado, regenere Pipfile.lock
por pipenv install -e .
pipenv sync Pipfile.lock
Pipfile.lock
pode ser criadomanualmente pelo desenvolvedor (pode funcionar para aplicativos)
aplicação: determinismo (executado exatamente da mesma maneira dentro do contexto de execução selecionado)
public pypi (baixo determinismo, pacotes são atualizados a qualquer momento)
Pipfile.lock
): determinismo totalPipfile.lock
:implantar aplicativo na produção
pbr
biblioteca requirements.txt
. A atualização de leitura Pipfile
está a caminho.
poetry
pacote pyenv
"solte o arquivo de bloqueio no repo" e você obterá compilações determinísticas:
Pipfile.lock
. Sério: flask
mostra em seus 11 envs virtuais diferentes (em um SO) 10 dependências bloqueadas diferentes. Quem os criará e os comprometerá?Pipfile.lock
(mas gerado pelo script de CI), permitindo regenerar o virtualenv em outro lugar.Pipfile.lock
no repositório da bibliotecasetup.py
.Pipfile
no repositório da bibliotecasetup.py
), ele pode ocultar a declaração de dependência setup.py
quebrada.Pipfile
por pipenv install -e .
ou pipenv install -e .[tests]
se você também precisar testar dependências e elas forem declaradas como extras de "testes" em setup.py
pipenv install <something>
em scripts de CIpipenv
).Bibliotecas Python (especialmente as gerais) exibem um número inesperadamente alto de contextos de execução. A razão é que, com as bibliotecas, o objetivo é a flexibilidade comprovada em diferentes condições. A flexibilidade parece mais importante sobre construções determinísticas. Para as pessoas que vêm do mundo da "compilação", isso pode parecer um antipadrão muito ruim. O fato é que a maioria (possivelmente todas) as bibliotecas Python não fornecem compilações determinísticas (se você estiver ciente de algumas, me avise) e Python ainda está indo muito bem. Os motivos pelos quais os aplicativos Python ainda estão vivos podem ser: o python como linguagem de script difere do mundo compilado. A outra razão poderia ser que o determinismo pode (deve) ser resolvido uma etapa depois, assim que um aplicativo (construir a partir de um conjunto de bibliotecas) deve resolver o requisito (natural e justificado) para o determinismo.
Para aplicações, a situação é exatamente oposta e aqui o determinismo é realmente fácil de alcançar com ferramentas como pipenv
.
o que fazer a seguir?
Obrigado a todos pela discussão tão inspiradora - sinto para mim como uma mensagem "Estou totalmente perdido neste tópico" refatorada três vezes - o que significa que naturalmente melhoramos.
@vlcinsky poetry
não tem nada a ver com pyenv
. É muito parecido com pipenv
(mas com uma implementação muito melhor em relação ao gerenciamento de bibliotecas e aplicativos, IMO), mas com a parte de empacotamento e publicação.
Você tem um arquivo pyproject.toml
que define seu projeto e suas dependências (dependências abstratas) e um pyproject.lock
que descreve as dependências fixadas e são fixados para qualquer versão e plataforma python de pyproject.toml
arquivo foi especificado para ter apenas um arquivo de bloqueio determinístico para evitar os problemas que pipenv
está enfrentando. Apenas durante a instalação, poetry
verificará quais pacotes instalar, comparando-os com o ambiente.
E ao empacotar sua biblioteca, ele usará as dependências abstratas (e não as fixas) para que você mantenha a flexibilidade ao distribuir seu pacote (via PyPI, por exemplo).
A vantagem disso é que ele usará dependências abstratas para bibliotecas e o arquivo de bloqueio para aplicativos. Esse é o melhor de ambos mundos.
A poesia fixas está literalmente
Essencialmente, gastamos muito tempo e esforço na resiliência em que pequenos projetos que fazem promessas grandiosas não precisam despender tanto esforço porque as pessoas não estão atingindo casos extremos. Se você realmente acredita que outra ferramenta oferece o melhor de todos os mundos, encorajo-o a usá-la - o pipenv em si não vai lidar com embalagens para você no curto prazo, ou nunca.
@techalchemy Não estou vendendo nada, na verdade, estou apenas direcionando para ideias que poderiam ser usadas em pipenv
.
E poetry
fixa dependências em pyproject.lock
, assim como pipenv
faz em Pipfile.lock
. Então você tem uma reprodução exatamente como pipenv
oferece. Se você tiver um arquivo de bloqueio, ele será usado e instale a dependência fixada e, se não me engano, é também o que pipenv
faz.
A única vez que ele usa dependências abstratas é quando empacota o projeto para distribuição (basicamente para bibliotecas), pois neste caso você não quer dependências fixas.
@vlcinsky Ainda existem alguns pontos que precisam ser resolvidos, corrigidos ou expandidos, mas ainda estou muito interessado em que isso entre em forma de documentação, Pipenv ou outro. Você estaria interessado em enviar uma solicitação de pull? Eu ficaria mais do que feliz em ajudar a desenvolver o artigo.
Em relação à poesia, pessoalmente não sou um fã como um todo, mas ela faz muitas coisas corretas. Provavelmente, não deve ser mencionado nos documentos do Pipenv porque viola algumas das melhores práticas que os desenvolvedores do Pipenv desejam levar às pessoas, mas deve ser mencionado se a discussão for realizada em pypa-dev ou semelhante, para fornecer uma imagem completa de como a embalagem ecossistema atualmente é.
a poesia também pode usar mais atenção e contribuição. Isso seria o melhor para a comunidade, incluindo Pipenv. Com escolhas viáveis, as pessoas podem pesar em suas escolhas em vez de ir para o Pipenv de cabeça e reclamar de não fazer o que eles esperam. A boa competição entre as bibliotecas também pode estimular melhorias técnicas na resolução de dependências, o que tanto o Pipenv quanto a poesia fazem (e nenhum deles perfeitamente). Podemos aprender muito uns com os outros.
@uranusjr Sim, acho que poucas coisas foram esclarecidas e merecem ser compartilhadas com um público mais amplo. Sua ajuda é muito bem-vinda.
E quanto à "redação da documentação do par"? Acho que, neste momento, seria mais eficaz trabalhar nisso em pequena escala de apenas duas pessoas.
As coisas a fazer são (possivelmente com uma ou duas iterações):
Se você quiser escrever por conta própria (com base no que foi discutido) e me tiver como revisor, não reclamaria.
Entrarei em contato com você por e-mail para combinar as próximas ações.
@vlcinsky Também estou disponível como @uranusjr
no PySlackers (um espaço de trabalho do Slack) se você preferir interação em tempo real. Pipenv tem um canal lá ( #pipenv
).
@uranusjr Isso é o que quero dizer com reunir esforços. Python precisa desesperadamente de um bom gerenciador de pacotes como o cargo. O ecossistema Python empalidece em comparação com as outras linguagens devido à falta de uma maneira padrão de fazer as coisas. E pipenv
não vai ajudar com isso, eu acho.
O que me incomoda é que pipenv
anuncia como the officially recommended Python packaging tool
embora não seja uma ferramenta de empacotamento, longe disso, o que é enganoso para os usuários. É apenas um gerenciador de dependências acoplado a um gerenciador virtualenv.
Além disso, você diz que foi inspirado por cargo, npm, yarn, que são ferramentas de empacotamento junto com gerenciadores de dependências, enquanto a tubulação não é.
E aqui está a falha de pipenv
, apenas turva a água, pois as pessoas ainda cometerão os mesmos erros de antes com requirements.txt
vs setup.py
. Os projetos ainda serão mal empacotados com dependências mal definidas em seus setup.py
por causa disso. Isso é o que projetos como carga fazem da maneira certa: eles lidam com todos os aspectos do desenvolvimento de projetos / aplicativos para garantir uma consistência, enquanto um projeto como pipenv
não o faz.
E quando você diz:
que Pipenv e poesia fazem (e nenhuma perfeitamente)
O que você quer dizer? Pelo que tenho visto, seu gerenciador de dependência é muito mais resiliente do que aquele fornecido por pipenv
. A única desvantagem é que eles usam a API JSON do PyPI, que às vezes não tem informações de dependência devido a pacotes publicados incorretamente.
De qualquer forma, acho, como você disse, que os dois projetos podem aprender um com o outro.
E, mais uma coisa, qual é o futuro do pipenv se, em última análise, o pip lida com Pipfile
? Será apenas um gerenciador virtualenv?
Se o gerenciador de dependência de poesia depende da API json, ele não só às vezes está errado devido a 'pacotes mal publicados', mas será muito limitado no que pode realmente resolver corretamente. A API json do warehouse posta as dependências _mais recentes_, mesmo se você estiver lidando com uma versão antiga, e isso se tiver essa informação. Costumávamos incorporar a API json também, era ótimo porque era rápida, mas a equipe de infraestrutura nos disse para não confiarmos nela. Parece um pouco insincero chamar algo de resiliente se ele depende de uma fonte não confiável para começar.
Em última análise, os desafios estão em torno da construção de um gráfico de dependência que executou um arquivo de configuração porque, atualmente, é assim que o empacotamento funciona. Simplesmente não há maneira de contornar isso. Um gráfico de dependência que resolve na minha máquina pode ser diferente daquele que resolve na sua máquina, mesmo para o mesmo pacote.
É fácil acenar com a mão e dizer 'bem, isso não torna pipenv um gerenciador virtualenv se pip pode ler um pipfile?' Não. Pipenv é um gerenciador de dependências. Ele gerencia ambientes idempotentes e gera um arquivo de bloqueio reproduzível. Sei que isso deve parecer trivial para você, porque você está descartando isso e reduzindo essa ferramenta a um gerenciador de virtualenv, mas não é. Resolvemos arquivos de bloqueio e incluímos marcadores para versões de python que você não tem, não está usando e mantemos isso disponível para que você possa implantar e reproduzir com precisão em plataformas e versões de python. Usamos vários métodos de resolução, incluindo manipulação de rodas e arquivos locais, repositórios vcs (resolvemos o gráfico lá também) artefatos remotos, pacotes pypi, índices privados, etc.
No final das contas, pip _will_ manipulará pipfiles, esse é o plano, tem sido o plano desde que o formato foi criado. Mas isso é o mesmo que perguntar 'mas e quando o pip puder lidar com os arquivos de requisitos?' A questão é basicamente idêntica. Pip pode instalar esse formato. Não é realmente relevante para nenhuma das funcionalidades que descrevi, exceto que também instalamos os arquivos (usando pip, a propósito).
@techalchemy
A API json do warehouse posta as dependências mais recentes, mesmo se você estiver lidando com uma versão antiga, e isso se tiver essa informação
Isso é simplesmente errado, você pode obter dependências de uma versão específica chamando https://pypi.org/pypi/{project}/{release}/json
. Se você apenas chamar https://pypi.org/pypi/{project}/json
certamente obterá apenas as últimas dependências, mas poderá obter o conjunto correto de dependências.
E a parte de empacotamento / publicação de projetos Python realmente precisa ser melhorada porque no final isso irá beneficiar a todos, já que tornará possível usar a API JSON de forma confiável.
Ele gerencia ambientes idempotentes e gera um arquivo de bloqueio reproduzível.
Resolvemos arquivos de bloqueio e incluímos marcadores para versões de python que você não tem, não está usando e mantemos isso disponível para que você possa implantar e reproduzir com precisão em plataformas e versões de python.
E o mesmo acontece com poetry
. E você pode fazer com que ele não use a API JSON para fornecer o mesmo método de resolução de pipenv
(usando pip-tools). Consulte https://github.com/sdispater/poetry/issues/37#issuecomment -379071989 e ainda será mais resiliente do que pipenv
(https://github.com/sdispater/poetry#dependency-resolution )
@zface Eu direi isso uma última vez, por favor, leve isso para algum lugar mais alto na hierarquia. Pipenv não se autoproclama ser a ferramenta de empacotamento Python oficialmente recomendada; diz isso porque é . Se você achar que isso é inapropriado, diga aos funcionários que recomendam a Pipenv . Por favor, não coloque essas coisas no Pipenv dev. Este é o lugar errado para reclamar, e você não pode obter resoluções para suas reclamações aqui. Você também pode obter respostas melhores para as perguntas técnicas que possui. Este é um rastreador de problemas para Pipenv, não um fórum de discussão para ferramentas de empacotamento Python e como o empacotamento Python é feito.
Pipenv não depende apenas de ferramentas pip para resolução, por favor, pare de reduzir nosso software a uma linha que demonstra falta de compreensão. Sei muito bem como funciona a api PyPI, conversei diretamente com a equipe que a implementou.
Isso simplesmente errado,
Esse tipo de atitude não é bem-vindo aqui. Não presuma que não entendemos do que estamos falando. Por favor, pratique a cortesia.
ainda será mais resiliente do que pipenv (https://github.com/sdispater/poetry#dependency-resolution)
Atualmente, o Pipenv não simplifica os gráficos de dependência. Apontar para um problema específico em que uma árvore foi achatada e afirmar que a ferramenta inteira é, portanto, melhor e mais resistente é tolice, você está provando repetidamente que está aqui simplesmente para insultar pipenv e promover a poesia. Continue, esse comportamento não é bem-vindo.
Concordo que a discussão está fora do assunto, que estava tentando capitalizar as "boas práticas" espalhadas por pipenv.
Contudo,
[...] ainda cometerá os mesmos erros de antes com requirements.txt versus setup.py. Os projetos ainda serão mal empacotados com dependências mal definidas em seu setup.py por causa disso.
Eu compartilho essa opinião, fazer com que novos desenvolvedores empacotem com sucesso seu próprio código Python é na verdade complexo, muito complexo, requer a leitura de muita documentação online.
Mas não cabe ao pipenv ou a qualquer outra dependência de pacote lidar com isso inteiramente. Não podíamos reescrever a história. Nós, como comunidade, precisamos encontrar uma maneira de modernizar a cadeia de ferramentas Python, passo a passo.
E pipenv (e provavelmente poesia) é um bom passo em frente.
Ter que manter de um lado Pipfile
para aplicação e setup.py
para bibliotecas do outro lado é um acéfalo. Não importa o quão difícil seja explicar com muitas palavras e longos artigos e guias de boas práticas, é muito complexo para o que é. Concordo plenamente que é assim por enquanto, mas isso não deve nos impedir de imaginar um caminho melhor e mais seguro.
No final, como desenvolvedor, quero uma única ferramenta, talvez com dois modos diferentes, para me ajudar e tornar minha vida o mais fácil possível.
Deve ser uma maneira de extrair apenas a parte que faz o requirements.txt/Pipfile
de bibliotecas como PBR para propor um tipo de 'setup.py fácil', um wrapper ciente do Pipfile próximo a install_requires
, sem todo o comportamento indesejado que o pbr traz, e empacote isso em um wrapper de setuptools dedicado que só faz isso.
Assim, seríamos capazes de ter o melhor de cada mundo:
Pipfile
(com versão em bibliotecas e aplicativos)Pipfile.lock
(versão somente para aplicativos)pipfile_setuptools
, install_requires_pipfile
?) que seria uma dependência de primeiro nível cujo trabalho é apenas injetar Pipfile
em install_requires
.Este é outro projeto que não estaria relacionado a pipenv
, mas ainda precisa de uma biblioteca de analisador Pipfile
genérica. O que você acha?
@gsemet Pelo que entendi, o PyPA tem tentado preencher isso com pyproject.toml, liderado por flit . Você precisará falar com eles primeiro (em pypa-dev ou distutils-sig) sobre isso antes de continuar a usar o Pipfile como formato de origem. Quanto à análise do Pipfile (e do arquivo de bloqueio), isso é tratado em pypa / pipfile (cujos fornecedores do Pipenv fornecem a lógica de análise principal).
Edit: Por favor, mande-me uma mensagem se você decidir iniciar uma discussão sobre isso em qualquer uma das listas de e-mail. Tenho algumas ideias de como podemos reunir as duas partes da distribuição de pacotes Python.
Devo admitir que estou um pouco triste ao ver dependências declaradas em pyproject.toml
(que assume as funções como setup.cfg
feitas por PBR), enquanto PyPa também suporta Pipfile
....
Obrigado pelo ponteiro para flit e pipfile. Também existe o pipenvlib de Kennethreitz que parece mais leve.
O setup.cfg do PBR parece mais completo em comparação com a documentação oficial (ex: data_files
) e reutiliza um arquivo já compartilhado com várias ferramentas (flake8, pytest, ...) pode usar o mesmo arquivo, reduzindo o número de arquivo na raiz de um projeto Python)
Comentários muito úteis
@ Moritz90 Várias listas de discussão do Python seriam bons locais para manter essa discussão.
pypa-dev é o mais definitivo para discussões centradas no empacotamento do Python e no ecossistema ao seu redor. Eu provavelmente começaria aqui se fosse postar uma discussão semelhante.
python-ideas é um lugar para discutir ideias e tem grande visibilidade para toda a comunidade Python. Também seria um bom ponto de partida se você quiser levar isso para o nível PEP (eventualmente você o faria, eu acho).