Como gerar o arquivo requirements.txt
a partir de Pipfile.lock
existente sem travar?
Quando eu executo pipenv lock -r
ele ignora Pipfile.lock
existente e faz o processo de bloqueio novamente.
Existe uma solução para isso:
$ pipenv sync
$ pipenv run pip freeze
Na minha situação particular, estou construindo uma imagem docker e usando requirements.txt
em Dockerfile
. Eu gostaria de evitar a criação de ambiente virtual na máquina host apenas para poder criar requirements.txt
.
O Pipenv não fornece uma maneira para isso, você pode procurar outras bibliotecas de utilitários pipfile, como pipfile-requirements
você pode correr
pipenv run pip freeze > requirements.txt
você pode correr
pipenv run pip freeze > requirements.txt
Isso é o que eu mencionei como uma solução alternativa no primeiro post.
Mas só funciona se você tiver seu ambiente pipenv sincronizado (todos os pacotes estão instalados).
Extrair dependências diretamente de Pipfile.lock
é mais conveniente para mim:
jq -r '.default
| to_entries[]
| .key + .value.version' \
Pipfile.lock > requirements.txt
LOL, eu já mencionei essa biblioteca.
Eu, pessoalmente, não gosto de ter uma biblioteca dedicada a isso. Além disso, há uma chance maior de que um membro da equipe já tenha jq
ou alguma outra ferramenta de uso geral instalada.
você pode até correr
pipenv lock --requirements > requirements.txt
Não funcionará como você espera, porque, como escrevi:
Quando executo
pipenv lock -r
, ele ignora oPipfile.lock
existente e faz o processo de bloqueio novamente.
Em outras palavras, ele executa uma atualização, que potencialmente pode destruir uma distribuição. Imagine, você gera requirements.txt
para usá-lo no Dockerfile para construir uma imagem docker. Localmente, seu aplicativo funciona, mas quando você gera requirements.txt
usando pipenv lock
, os requisitos podem ser atualizados para versões incompatíveis ou apenas quebradas (espero que seja um caso raro). E você não saberá disso antes de executar a imagem. Portanto, você precisará testar o aplicativo novamente após executar pipenv lock
.
Se você não quiser usar jq
, então é melhor usar a abordagem que propus no primeiro post com pipenv sync
(que não atualiza).
@Zebradil sua abordagem jq
oneliner é muito mais simples do que o próprio pacote pipfile-requirements
do @frostming (mais de 100 linhas de código python) desde que eu já instalei jq
, sem outras dependências necessário, o que é ótimo.
No entanto, depois de alguns commits do git, notei a diferença entre o que pipenv lock --requirements
gera e o que jq
coleta através do arquivo Pipfile.lock
e imprime:
jq
não tem -i https://pypi.org/simple
como a primeira linha, ao contrário do que pipenv lock --r
sempre insere como a primeira linha.jq
não inclui a anotação para pacotes. Por exemplo: pipenv lock --r
output tem esta linha appnope==0.1.0 ; sys_platform == 'darwin'
, mas em jq
output, é appnope==0.1.0
. Outro exemplo é pipenv lock -r
gera pexpect==4.7.0 ; sys_platform != 'win32'
enquanto jq
gera pexpect==4.7.0
, não tenho certeza se isso importa ou não.jq
que presumivelmente recebe a ordem do pacote no arquivo Pipfile.lock
, que sempre classifica por ordem crescente em alfabeto e comprimento de caractere, por exemplo, flask
está na frente de flask-sqlalchemy
ou qualquer pacote flask-XXXXX
, enquanto pipenv lock --r
gera flask
atrás flask-sqlalchemy
, que é diferente do pedido em Pipfile.lock
. Isso é um grande aborrecimento porque não gera um git diff mínimo. Eu consideraria que isso é um bug em pipenv
.Oi @ye , boa comparação dos métodos. Pode ajudar as pessoas a escolher a solução adequada para sua situação específica e evitar ressalvas.
Sim, como você disse, a abordagem proposta com jq
tem funcionalidade limitada. É possível estendê-lo para adicionar anotações e URL de índice de pacote, mas não preciso disso agora.
Para evitar diferenças no arquivo requirements.txt gerado, deve-se considerar usar sempre a mesma abordagem. De maneira semelhante, o uso de diferentes ferramentas de formatação de código pode levar a resultados inconsistentes. Então, não vejo problema aqui.
você pode correr
pipenv run pip freeze > requirements.txt
Isso é o que eu mencionei como uma solução alternativa no primeiro post.
Mas só funciona se você tiver seu ambiente pipenv sincronizado (todos os pacotes estão instalados).
Extrair dependências diretamente dePipfile.lock
é mais conveniente para mim:jq -r '.default | to_entries[] | .key + .value.version' \ Pipfile.lock > requirements.txt
Oi,
Obrigado pela sua solução. Eu me deparei com o mesmo problema, mas também preciso da definição de fontes criadas por pipenv lock -r
, ou seja: -i, --extra-index-url. Isso ocorre porque eu trabalho com fontes privadas.
@Zebradil Acho que você mencionou isso.
Então eu criei outro script mínimo sem dependências em python que inclui essa funcionalidade. Ele também expande env vars caso você tenha suas fontes definidas dessa maneira em seu Pipfile.
Se alguém quiser dar uma olhada deixo aqui: https://gist.github.com/rcastill/dab85c234dd10fa7af56755116c75aee
Caso ajude mais alguém, veja como incluir os hashes nos resultados:
jq --raw-output '.default | to_entries[] | .key + .value.version + (.value.hashes | map(" --hash=\(.)") | join(""))' Pipfile.lock
Isso cria entradas como
paramiko==2.6.0 --hash=sha256:99f0179bdc176281d21961a003ffdb2ec369daac1a1007241f53374e376576cf --hash=sha256:f4b2edfa0d226b70bd4ca31fea7e3893257907583da304165d57225790758da304165d57225790758da3044
O que faz pip
impor os hashes.
Se você quiser incluir apenas os requisitos que estavam no arquivo de requisitos original (desde que eles já estivessem bloqueados para uma versão específica com ==
):
jq --raw-output '.default | to_entries[] | .key + .value.version + (.value.hashes | map(" --hash=\(.)") | join(""))' Pipfile.lock | grep --file=<(grep --only-matching --perl-regexp '^.*(?===)' requirements.txt | tr '[:upper:]' '[:lower:]') > new.txt && mv new.txt requirements.txt
tr
é necessário porque os arquivos requirements.txt podem conter nomes de pacotes com letras maiúsculas e minúsculas, mas pipenv install -r requirements.txt
os coloca em letras minúsculas no Pipfile.
Aqui está um pequeno script python caso você queira transformar o Pipfile
(não o arquivo de bloqueio) em um arquivo requirements.txt.
import configparser
def main():
parser = configparser.ConfigParser()
parser.read("Pipfile")
packages = "packages"
with open("requirements.txt", "w") as f:
for key in parser[packages]:
value = parser[packages][key]
f.write(key + value.replace("\"", "") + "\n")
if __name__ == "__main__":
main()
@frostming Oi, achei https://github.com/frostming/pipfile-requirements útil, mas por que não foi integrado ao pipenv?
@linusguan A ferramenta existe para quem não quer instalar a grande biblioteca pipenv, quando tiver instalado o pipenv, pode usar pipenv lock -r
@frostming Acho bastante útil para uso com outras ferramentas que não suportam pipfile.lock.
O problema com pipenv lock -r
é que ele atualiza pipfile.lock então não posso usá-lo para produzir compilação determinística junto com outras ferramentas. Algo como pipenv lock -r --ignore-pipfile
seria o ideal.
Aqui está outro script python para gerar requirements.txt do arquivo Pipfile.lock com hashes:
import os
import json
__dir__ = os.path.dirname(os.path.realpath(__file__))
def read_json_file(path):
with open(path) as f:
return json.load(f)
def main():
root = read_json_file(os.path.join(__dir__, 'Pipfile.lock'))
for name, pkg in root["default"].items():
version = pkg["version"]
sep = lambda i: "" if i == len(pkg["hashes"]) - 1 else " \\"
hashes = [f'--hash={t}{sep(i)}' for i, t in enumerate(pkg["hashes"])]
tail = '' if len(hashes) == 0 else f' {hashes[0]}'
print(f'{name} {version}{tail}')
for h in hashes[1:]:
print(f' {h}')
if __name__ == "__main__":
main()
@Zebradil Obrigado! Sua solução realmente funcionou para mim.
jq
usando brew install jq
requirements.txt
de Pipfile.lock
Parece que isso pode ser resolvido com o sinalizador --keep-outdated
, ou estou enganado?
pipenv lock --keep-outdated -d -r > requirements.txt
PS, esse é um sinalizador irritantemente detalhado para resolver isso
Infelizmente @jacobisaliveandwell o sinalizador --keep-outdated parece atualizar subdependências: https://github.com/pypa/pipenv/issues/3975
@paytonrules Isso é um bug, mas o espírito da bandeira ainda é a resposta para esse problema.
PS Não há necessidade de polegares para baixo para isso :-(
Só quero mencionar que, a partir das soluções alternativas, existem diferenças:
pipenv run pip freeze
retorna nomes de pacotes que diferenciam maiúsculas de minúsculas (por exemplo PyYAML
)
pipenv lock --requirements
retorna todos os nomes de pacotes em letras minúsculas (por exemplo pyyaml
)
@Darkless012 você deve abrir outro ticket descrevendo isso e fazer referência a esse problema conforme relacionado.
Bash puro, apenas pacotes, nada mais, caso alguém não possa ou não queira instalar o jq, caso ajude alguém,
cat Pipfile.lock \
| grep -B1 '"hashes"\|"version": ' \
| grep -v '"markers": \|"hashes": ' \
| grep ": {\|version" \
| sed -e 's/: {$//g' \
| tr '\n' ',' | tr -s ' ' ' ' \
| sed -e 's/, "version": "//g;s/", "/ /g;s/"//g;s/,//g' \
| tr ' ' '\n' \
| grep -v "^$" > requirements.txt
Existe algo que também copia os hashes do Pipfile para requirements.txt (por exemplo, dado algo como uma plataforma str) para que pip install --require-hashes
funcione?
$ pip install --help
# ...
--require-hashes Require a hash to check each requirement against, for repeatable installs. This option is implied when any package in a
requirements file has a --hash option.
Você pode usar micropipenv que pode converter arquivos Pipenv.lock (também poesia.lock) para requirements.txt (raw requirements.txt ou compatível com pip-tools). Veja https://github.com/thoth-station/micropipenv/#micropipenv -requirements--micropipenv-req
Comentários muito úteis
você pode correr