¿Cómo generar un archivo requirements.txt
a partir de Pipfile.lock
existente sin bloquear?
Cuando ejecuto pipenv lock -r
, ignora los Pipfile.lock
existentes y vuelve a realizar el proceso de bloqueo.
Hay una solución para esto:
$ pipenv sync
$ pipenv run pip freeze
En mi situación particular, estoy creando una imagen acoplable y usando requirements.txt
en Dockerfile
. Me gustaría evitar crear un entorno virtual en la máquina host solo para poder crear requirements.txt
.
Pipenv no proporciona una forma para esto, puede buscar otras bibliotecas de utilidades de pipfile como pipfile-requirements
Tu puedes correr
pipenv run pip freeze > requirements.txt
Tu puedes correr
pipenv run pip freeze > requirements.txt
Eso es lo que mencioné como solución en la primera publicación.
Pero solo funciona si tiene su entorno pipenv sincronizado (todos los paquetes están instalados).
Extraer dependencias directamente de Pipfile.lock
es más conveniente para mí:
jq -r '.default
| to_entries[]
| .key + .value.version' \
Pipfile.lock > requirements.txt
LOL, ya he mencionado esa biblioteca.
Personalmente, no me gusta tener una biblioteca dedicada a eso. Además, existe una mayor probabilidad de que un miembro del equipo ya tenga jq
o alguna otra herramienta de propósito general instalada.
incluso puedes correr
pipenv lock --requirements > requirements.txt
No funcionará como esperas, porque, como escribí:
Cuando ejecuto
pipenv lock -r
, ignora elPipfile.lock
existente y vuelve a realizar el proceso de bloqueo.
En otras palabras, realiza una actualización, que potencialmente puede destruir una distribución. Imagínese, genera requirements.txt
para usarlo en Dockerfile para construir una imagen acoplable. Localmente, su aplicación funciona, pero cuando genera requirements.txt
usando pipenv lock
, los requisitos pueden actualizarse a versiones incompatibles o simplemente rotas (con suerte, es un caso raro). Y no sabrá esto antes de ejecutar la imagen. Por lo tanto, deberá volver a probar la aplicación después de ejecutar pipenv lock
.
Si no quieres usar jq
, mejor usa el enfoque que propuse en la primera publicación con pipenv sync
(que no se actualiza).
@Zebradil su enfoque jq
oneliner es mucho más simple que el propio paquete pipfile-requirements
de @frostming (más de 100 líneas de código Python) ya que ya instalé jq
, no hay otras dependencias requerido, lo cual es genial.
Sin embargo, después de algunas confirmaciones de git, noté la diferencia entre lo que sale pipenv lock --requirements
y lo que jq
obtiene a través del archivo Pipfile.lock
e imprime:
jq
no tiene -i https://pypi.org/simple
como la primera línea, a diferencia de lo que pipenv lock --r
siempre inserta como la primera línea.jq
no incluye la anotación de los paquetes. Por ejemplo: la salida pipenv lock --r
tiene esta línea appnope==0.1.0 ; sys_platform == 'darwin'
, pero en la salida jq
, es appnope==0.1.0
. Otro ejemplo es pipenv lock -r
genera pexpect==4.7.0 ; sys_platform != 'win32'
mientras que jq
genera pexpect==4.7.0
, no estoy seguro si esto importa o no.jq
que presumiblemente toma el orden del paquete en el archivo Pipfile.lock
, que siempre ordena en orden ascendente en alfabetos y longitud de caracteres, por ejemplo, flask
está delante de flask-sqlalchemy
o cualquier flask-XXXXX
paquetes, mientras que pipenv lock --r
genera flask
detrás flask-sqlalchemy
, que es diferente del orden en Pipfile.lock
. Esta es una gran molestia porque no genera una diferencia mínima de git. Consideraría que esto es un error en pipenv
.Hola @ye , buena comparación de los métodos. Podría ayudar a las personas a elegir la solución adecuada para su situación particular y evitar advertencias.
Sí, como dijiste, el enfoque propuesto con jq
tiene una funcionalidad limitada. Es posible extenderlo para agregar anotaciones y URL de índice de paquete, pero no necesito esto ahora.
Para evitar tener diferencias en los requisitos generados.txt, se debe considerar usar el mismo enfoque cada vez. De manera similar, el uso de diferentes herramientas de formato de código puede generar resultados inconsistentes. Por lo tanto, no veo un problema aquí.
Tu puedes correr
pipenv run pip freeze > requirements.txt
Eso es lo que mencioné como solución en la primera publicación.
Pero solo funciona si tiene su entorno pipenv sincronizado (todos los paquetes están instalados).
Extraer dependencias directamente dePipfile.lock
es más conveniente para mí:jq -r '.default | to_entries[] | .key + .value.version' \ Pipfile.lock > requirements.txt
Hola,
Gracias por tu solución. Me encontré con el mismo problema, pero también necesito la definición de las fuentes creadas por pipenv lock -r
, es decir: -i, --extra-index-url. Esto se debe a que trabajo con fuentes privadas.
@Zebradil Creo que lo mencionaste.
Así que creé otro script mínimo sin dependencias en python que incluye esa funcionalidad. También expande env vars en caso de que tenga sus fuentes definidas de esa manera en su Pipfile.
Si alguien quiere echarle un vistazo lo dejo aquí: https://gist.github.com/rcastill/dab85c234dd10fa7af56755116c75aee
En caso de que ayude a alguien más, aquí se explica cómo incluir los hash en los resultados:
jq --raw-output '.default | to_entries[] | .key + .value.version + (.value.hashes | map(" --hash=\(.)") | join(""))' Pipfile.lock
Esto crea entradas como
paramiko==2.6.0 --hash=sha256:99f0179bdc176281d21961a003ffdb2ec369daac1a1007241f53374e376576cf --hash=sha256:f4b2edfa0d226b70bd4ca31ea7e38932599026f376576cf
Lo que hace que pip
haga cumplir los hashes.
Si desea incluir solo los requisitos que estaban en el archivo de requisitos original (siempre que ya estuvieran bloqueados en una versión específica con ==
):
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
es necesario porque los archivos requirements.txt pueden contener nombres de paquetes en mayúsculas y minúsculas, pero pipenv install -r requirements.txt
los pone en minúsculas en Pipfile.
Aquí hay una pequeña secuencia de comandos de Python en caso de que desee convertir el Pipfile
(no el archivo de bloqueo) en un archivo de requisitos.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 Hola, encontré https://github.com/frostming/pipfile-requirements útil, pero ¿por qué no se integró en pipenv?
@linusguan La herramienta existe para aquellos que no quieren instalar la gran biblioteca pipenv, cuando haya instalado pipenv, puede usar pipenv lock -r
@frostming Lo encuentro bastante útil para usar con otras herramientas que no son compatibles con pipfile.lock.
El problema con pipenv lock -r
es que actualiza pipfile.lock, por lo que no puedo usarlo para producir una compilación determinista junto con otras herramientas. Algo como pipenv lock -r --ignore-pipfile
sería ideal.
Aquí hay otra secuencia de comandos de python para generar requisitos.txt desde el archivo Pipfile.lock con 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 ¡Gracias! Su solución realmente funcionó para mí.
jq
usando brew install jq
requirements.txt
a partir de Pipfile.lock
Parece que esto se puede resolver con la --keep-outdated
, ¿o me equivoco?
pipenv lock --keep-outdated -d -r > requirements.txt
PD, esa es una bandera molestamente detallada para resolver esto
Desafortunadamente , @jacobisaliveandwell , el indicador --keep-outdated parece actualizar las subdependencias: https://github.com/pypa/pipenv/issues/3975
@paytonrules Eso es un error, pero el espíritu de la bandera sigue siendo la respuesta a este problema.
PD No hay necesidad de pulgares hacia abajo para eso :-(
Solo quiero mencionar que de las soluciones alternativas indicadas, hay diferencias:
pipenv run pip freeze
devuelve nombres de paquetes que distinguen entre mayúsculas y minúsculas (p. ej. PyYAML
)
pipenv lock --requirements
devuelve todos los nombres de paquetes en minúsculas (por ejemplo, pyyaml
)
@Darkless012 , debe abrir otro ticket que describa eso y hacer referencia a este problema como relacionado.
Puro bash, solo paquetes, nada mas, por si alguien no puede o no quiere instalar jq, por si a alguien le sirve,
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
¿Hay algo que también copie los valores hash del Pipfile a los requisitos.txt (por ejemplo, dado algo como una cadena de plataforma) 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.
Puede usar micropipenv que puede convertir archivos Pipenv.lock (también poesía.lock) a requisitos.txt (requisitos sin formato.txt o compatible con pip-tools). Consulte https://github.com/thoth-station/micropipenv/#micropipenv -requirements--micropipenv-req
Comentario más útil
Tu puedes correr