Как сгенерировать файл requirements.txt
из существующего Pipfile.lock
без блокировки?
Когда я запускаю pipenv lock -r
, он игнорирует существующие Pipfile.lock
и снова выполняет процесс блокировки.
Для этого есть обходной путь:
$ pipenv sync
$ pipenv run pip freeze
В моей конкретной ситуации я создаю образ докера и использую requirements.txt
в Dockerfile
. Я бы не хотел создавать виртуальную среду на хост-компьютере только для того, чтобы иметь возможность создавать requirements.txt
.
Pipenv не предоставляет для этого способа, вы можете искать другие служебные библиотеки pipfile, такие как pipfile-requirements
Вы можете запустить
pipenv run pip freeze > requirements.txt
Вы можете запустить
pipenv run pip freeze > requirements.txt
Это то, что я упомянул в качестве обходного пути в первом посте.
Но это работает, только если у вас синхронизирована среда pipenv (установлены все пакеты).
Извлечение зависимостей напрямую из Pipfile.lock
мне удобнее:
jq -r '.default
| to_entries[]
| .key + .value.version' \
Pipfile.lock > requirements.txt
LOL, я уже упоминал эту библиотеку.
Лично мне не нравится иметь для этого специальную библиотеку. Кроме того, существует более высокая вероятность того, что член команды уже установил jq
или какой-либо другой инструмент общего назначения.
ты даже можешь бежать
pipenv lock --requirements > requirements.txt
Это не сработает так, как вы ожидаете, потому что, как я уже писал:
Когда я запускаю
pipenv lock -r
, он игнорирует существующийPipfile.lock
и снова выполняет процесс блокировки.
Другими словами, он выполняет обновление, которое потенциально может уничтожить дистрибутив. Представьте, вы генерируете requirements.txt
, чтобы использовать его в Dockerfile для создания образа Docker. Локально ваше приложение работает, но когда вы генерируете requirements.txt
с помощью pipenv lock
, требования могут быть обновлены до несовместимых или просто сломанных версий (хотя, надеюсь, это редкий случай). И вы этого не узнаете до запуска образа. Итак, вам нужно снова протестировать приложение после запуска pipenv lock
.
Если вы не хотите использовать jq
, то лучше используйте подход, который я предложил в первом посте с pipenv sync
(который не выполняет обновление).
@Zebradil, ваш подход jq
oneliner намного проще, чем собственный пакет @frostming pipfile-requirements
(100+ строк кода Python), поскольку я уже установил jq
, никаких других зависимостей требуется, и это здорово.
Однако после нескольких коммитов git я заметил разницу между тем, что выводит pipenv lock --requirements
, и тем, что jq
подбирает через файл Pipfile.lock
и распечатывает:
jq
не содержит -i https://pypi.org/simple
в качестве самой первой строки, в отличие от того, что pipenv lock --r
всегда вставляется в качестве самой первой строки.jq
не включает аннотацию для пакетов. Например: вывод pipenv lock --r
имеет эту строку appnope==0.1.0 ; sys_platform == 'darwin'
, но в выводе jq
это appnope==0.1.0
. Другой пример: pipenv lock -r
генерирует pexpect==4.7.0 ; sys_platform != 'win32'
, тогда как jq
генерирует pexpect==4.7.0
, не уверен, имеет ли это значение или нет.jq
, который предположительно принимает порядок пакетов в файле Pipfile.lock
, который всегда сортируется по возрастанию алфавитов и длины символов, например, flask
стоит перед flask-sqlalchemy
или любые пакеты flask-XXXXX
, тогда как pipenv lock --r
выводит flask
после flask-sqlalchemy
, что отличается от порядка в Pipfile.lock
. Это серьезное раздражение, потому что оно не генерирует минимальный git diff. Я бы посчитал, что это ошибка в pipenv
.Привет @ye , хорошее сравнение методов. Это может помочь людям выбрать правильное решение для их конкретной ситуации и избежать предостережений.
Да, как вы сказали, предлагаемый подход с jq
имеет ограниченную функциональность. Его можно расширить, добавив аннотации и URL-адрес индекса пакета, но сейчас мне это не нужно.
Чтобы избежать различий в генерируемом файле requirements.txt, следует каждый раз использовать один и тот же подход. Точно так же использование разных инструментов форматирования кода может привести к противоречивым результатам. Так что я не вижу здесь проблемы.
Вы можете запустить
pipenv run pip freeze > requirements.txt
Это то, что я упомянул в качестве обходного пути в первом посте.
Но это работает, только если у вас синхронизирована среда pipenv (установлены все пакеты).
Извлечение зависимостей напрямую изPipfile.lock
мне удобнее:jq -r '.default | to_entries[] | .key + .value.version' \ Pipfile.lock > requirements.txt
Привет,
Спасибо за ваше решение. Я столкнулся с той же проблемой, но мне также нужно определение источников, созданных pipenv lock -r
, то есть: -i, --extra-index-url. Это потому, что я работаю с частными источниками.
@Zebradil , я думаю, ты упомянул об этом.
Поэтому я создал еще один минимальный скрипт без зависимостей на python, который включает эту функциональность. Он также расширяет env vars, если у вас есть источники, определенные таким образом в вашем Pipfile.
Если кто-то хочет взглянуть, я оставлю это здесь: https://gist.github.com/rcastill/dab85c234dd10fa7af56755116c75aee .
Если это поможет кому-то еще, вот как включить хэши в результаты:
jq --raw-output '.default | to_entries[] | .key + .value.version + (.value.hashes | map(" --hash=\(.)") | join(""))' Pipfile.lock
Это создает такие записи, как
paramiko==2.6.0 --hash=sha256:99f0179bdc176281d21961a003ffdb2ec369daac1a1007241f53374e376576cf --hash=sha256:f4b2edfa0d226b70bd4ca31ea7e389325709906158d570990283d5234
Что заставляет pip
применять хэши.
Если вы хотите включить только те требования, которые были в исходном файле требований (при условии, что они уже были привязаны к определенной версии с помощью ==
):
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
необходим, потому что файлы requirements.txt могут содержать имена пакетов в смешанном регистре, но pipenv install -r requirements.txt
в Pipfile пишут их строчными буквами.
Вот небольшой скрипт на Python на случай, если вы захотите превратить Pipfile
(не файл блокировки) в файл 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 Привет, я нашел https://github.com/frostming/pipfile-requirements полезным, но почему он не был интегрирован в pipenv?
@linusguan Инструмент существует для тех, кто не хочет устанавливать большую библиотеку pipenv, когда вы установили pipenv, вы можете использовать pipenv lock -r
@frostming Я считаю его весьма полезным для использования с другими инструментами, которые не поддерживают pipfile.lock.
Проблема с pipenv lock -r
заключается в том, что он обновляет pipfile.lock, поэтому я не могу использовать его для создания детерминированной сборки вместе с другими инструментами. Что-то вроде pipenv lock -r --ignore-pipfile
было бы идеально.
Вот еще один скрипт на Python для создания файла requirements.txt из файла Pipfile.lock с хэшами:
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()
@Зебрадил Спасибо! Ваше решение действительно сработало для меня.
jq
, используя brew install jq
requirements.txt
из Pipfile.lock
Похоже, это можно решить с помощью флага --keep-outdated
, или я ошибаюсь?
pipenv lock --keep-outdated -d -r > requirements.txt
PS это раздражающе многословный флаг, чтобы решить эту проблему
К сожалению , @jacobisaliveandwell флаг --keep-outdated появляется для обновления подзависимостей: https://github.com/pypa/pipenv/issues/3975
@paytonrules Это ошибка, но дух флага по-прежнему является ответом на эту проблему.
PS Не надо минусовать за это :-(
Сразу хочу отметить, что от заявленных обходных путей есть отличия:
pipenv run pip freeze
возвращает имена пакетов с учетом регистра (например, PyYAML
)
pipenv lock --requirements
возвращает все имена пакетов в нижнем регистре (например, pyyaml
)
@ Darkless012 , вы должны открыть еще один тикет, описывающий это, и сослаться на эту проблему как на связанную.
Чистый bash, только пакеты, ничего больше, на тот случай, если кто-то не может или не хочет ставить jq, на всякий случай кому-то поможет,
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
Есть ли что-нибудь, что также копирует хэши из Pipfile в requirements.txt (например, с учетом что-то вроде платформы str), чтобы pip install --require-hashes
работало?
$ 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.
Вы можете использовать micropipenv, который может конвертировать файлы Pipenv.lock (также поэзия.lock) в требования.txt (необработанные требования.txt или совместимые с pip-tools). См. https://github.com/thoth-station/micropipenv/#micropipenv-requirements--micropipenv-req
Самый полезный комментарий
Вы можете запустить