Pipenv: Gere requirements.txt do Pipfile.lock

Criado em 31 jan. 2019  ·  25Comentários  ·  Fonte: pypa/pipenv

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 .

Comentários muito úteis

você pode correr

pipenv run pip freeze > requirements.txt

Todos 25 comentários

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

Postagem do blog
ferramenta jq

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 o Pipfile.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:

  • A saída 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.
  • A saída 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.
  • a ordenação do pacote de arquivos de requisitos é diferente entre as duas saídas. 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 de Pipfile.lock é mais conveniente para mim:

jq -r '.default
        | to_entries[]
        | .key + .value.version' \
    Pipfile.lock > requirements.txt

Postagem do blog
ferramenta jq

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.

  • Primeiro instalo a ferramenta jq usando brew install jq
  • Em seguida, use seu script para gerar 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

Esta página foi útil?
0 / 5 - 0 avaliações