Una disculpa poética
O por qué deberías usar Poetry para administrar las dependencias de Python

Si alguna vez has pasado algún tiempo intentando escribir una aplicación de Python, es probable que hayas experimentado el infame infierno de dependencias de Python en algún momento. Probablemente ya te hayas dado cuenta de que se ha convertido en una tradición popular empezar cualquier artículo sobre este tema con el siguiente famoso cómic xkcd.

Por suerte para ti (y para todos nosotros), en el momento de escribir este artículo, hay algunas buenas soluciones para el enredo de dolores que se muestran brillantemente en la imagen de arriba. De hecho, lo más probable es que ya sepas que si quieres desarrollar con varias versiones de Python, puedes usar fácilmente pyenv para empezar a desentrañar tu retorcido entorno. Es posible que también hayas aprendido que si trabajas al mismo tiempo en varios proyectos con dependencias conflictivas, puedes emplear entornos virtuales para aislar las bibliotecas que chocan. En este documento, presentaremos otra herramienta, Poesía, y argumente por qué probablemente debería agregarlo a su propio conjunto de herramientas.
El problema
Imagina que una noche solitaria decides iniciar un simple proyecto ficticio de Python llamado con precisión foo con la siguiente estructura
pie/
├── pie/
│ ├── bar/
│ ├── data.py
│ ├── constants.py
── README.md
Como este no es tu primer proyecto de Python y quieres evitar pasar más noches interminables arreglando incompatibilidades entre tu sistema y los módulos del proyecto, inicias diligentemente un entorno virtual desde tu shell con y actívalo dentro del proyecto recién creado con equipado con un entorno aislado, procedes triunfalmente a instalar la omnipresente biblioteca de datos de Pandas. Para lograrlo, utiliza el administrador de paquetes de facto de Python, pip, y fija cuidadosamente la versión de la biblioteca para garantizar la replicabilidad.
Como te da un poco de pereza realizar análisis exploratorios de datos, también instalas el ingenioso módulo de creación de perfiles de pandas para ayudarte con ese tedioso trabajo.
Después de todo este coqueteo, por fin empiezas a programar (suponiendo que añadir las siguientes líneas al archivo data.py pueda, de hecho, llamarse así)
desde pandas_profiling importar ProfileReport
importar pandas como pdf
df = pd.read_csv («data.csv»)
perfil = ProfileReport (df)
profile.to_file («foo.html»)
Dado que sus días de abusar de las declaraciones impresas con fines de depuración han quedado atrás, instala el hermoso y práctico pdbpp biblioteca para comprobar que estas líneas funcionan según lo previsto y ejecutar su código en modo de depuración post mortem con python.
Satisfecho con la ejecución limpia, ahora te das cuenta de que, para lanzar tu voluptuosa aplicación sin caer en la trampa de «funciona en mi máquina», necesitas una forma de recopilar todas tus dependencias. Una búsqueda rápida en Google te mostrará que el subcomando freeze de pip permite grabar el paquete de entorno actual en un archivo requirements.txt mediante el siguiente encantamiento
pip freeze > requirements.txt
Lo que permite a cualquier persona ejecutar su proyecto simplemente instalando dependencias con:
pip install -r requirements.txt
Justo cuando estás a punto de revelar tu proyecto de obra maestra al mundo, te das cuenta de que el módulo de depuración mejorado solo lo utilizas tú durante el desarrollo. Con la idea de dividir los requisitos inactivos en archivos de producción y desarrollo independientes, echas un vistazo al archivo generado y descubres que todas y cada una de las subdependencias de la aplicación aparecen en él y están bloqueadas en una versión específica. Previendo la pesadilla de mantener esta inmensa lista, desinstala la biblioteca pdbpp para garantizar que el archivo de requisitos vuelva a estar limpio mediante
pip uninstall -y pdbpp && pip freeze > requirements.txt
Sin embargo, un vistazo rápido al archivo de requisitos modificado muestra que las cosas no salieron como se esperaba: pdbpp se eliminó, pero sus dependencias, como fancycompleter, siguen instaladas. Como esto parece un callejón sin salida, opta por empezar desde cero creando manualmente un archivo requirements.txt con solo dependencias de producción
pandas == 0.25.3
creación de perfiles de pandas==2.5.0
y un archivo de desarrollo equivalente, requirements_dev.txt, que contenga únicamente
pdbpp==0.10.2
Impresionado por la inteligencia que aparentemente te ha ayudado a evitar el temido infierno de las dependencias de Python al mantener un registro de los paquetes aislados de alto nivel, decides dar por terminado el día y darle una última vuelta a tu aplicación al día siguiente.
Cuando te levantas por la mañana, las noticias están por todas partes: Pandas v1 finalmente ha salido (¡después de solo doce años!). Tras un par de horas sin hacer las cosas con un registro de cambios increíblemente largo, llegarás a la conclusión de que tu complejo foo-project seguramente obtendrá mejoras notables al actualizarse a la nueva versión. Ahora que has bloqueado la versión exacta de Pandas, no puedes simplemente ejecutar
pip install -U -r requirements.txt
En su lugar, debe ejecutar
pip install pandas==1.0.0
lo que lleva a una situación particularmente extraña y confusa: aparece un error en tu terminal
ERROR: pandas-profiling 2.5.0 tiene el requisito pandas==0.25.3,
pero de todos modos se lleva a cabo la instalación de pandas 1.0.0. Suponiendo que se trata de una advertencia de que pip confunde con un error, actualice su archivo requirements.txt en consecuencia y, con mucho gusto, proceda a ejecutar su módulo data.py por última vez, solo para descubrir que arroja un enigmático TypeError. Sintiéndote ahora traicionado por la aparente incapacidad de pip para resolver dependencias, anulas tus cambios y te quedas con la versión (ahora) obsoleta de Pandas.
En este punto, parece que tiene un proyecto en funcionamiento, pero i) no está seguro de si la reversión de la versión de Pandas podría haber interrumpido la replicabilidad deseada de su aplicación, ii) el código definitivamente podría tener un aspecto mejor y iii) después de una buena noche de sueño, reconoce que la funcionalidad general de su aplicación no es tan compleja y rica como pensaba que era la noche anterior. Para solucionar los dos primeros problemas, primero añada el formateador negro a su archivo requirements_dev.txt
negro == 19.10b0
y luego, dentro del directorio de su proyecto, recrea su entorno virtual con
rm -rf ~/Desktop/venv/foo-venv
python -m venv ~/escritorio/venv/foo-venv
fuente ~/desktop/venv/foo-venv/bin/activate
pip install -r requirements_dev.txt
pip install -r requirements.txt
Ahora usas negro en la raíz de tu proyecto (con negro) y estás más que satisfecho con el bonito trabajo que hizo, pero para cumplir con el estilo de formato de Mutt Data (que casualmente concuerda con tu aversión por hacer que cada comilla sea una comilla doble), agregas un pyproject.toml que le dice a black que se salte una configuración predeterminada de normalización de cadenas tan espantosa
[herramienta. negra]
normalización de cadenas de omisión = verdadera
El código se ve muy bien ahora y una nueva versión de depuración post mortem muestra que las cosas parecen funcionar bien en el nuevo entorno (replicable). Lo único que queda por hacer antes de implementar el código en el servidor o compartirlo con el mundo es evitar tener constantes codificadas en todo el código, como el nombre del informe. Por lo tanto, decide añadir las siguientes líneas a su módulo vacío de constants.py
ARCHIVO_REPORT= «foo.html»
y modifique el data.py para importar dicha constante desde el archivo principal relativo con
desde.. constantsImportReport_File
Sin embargo, una nueva ejecución de data.py ahora, desafortunadamente, muestra el siguiente error
ImportError: intento de importación relativa sin ningún paquete principal conocido
lo cual, según el omnisciente SO, tiene sentido, ya que las importaciones relativas de Python solo funcionan dentro de un paquete y, por lo tanto, si desea importar desde un directorio principal, debe crear dicho paquete o hackear el sys.path. Como verdadero pythonista purista, eliges la ruta anterior y creas un setup.py con el siguiente contenido
desde setuptools importar configuración
con open ('requirements.txt') como f: install_requires = f.read () .splitlines ()
con open ('requirements_dev.txt') como f: extras_dev_requires = f.read () .splitlines ()
setup (name='foo', version='0.0.1', author='mutt', author_email=' info@muttdata.ai ', install_requires=install_requires, extras_require= {' dev ': extras_dev_requires}, packages= [' foo '],)
Ahora, en un entorno virtual completamente nuevo, instala su paquete en modo editable con pip install -e. [dev], cambia la línea de importación en data.py para tener en cuenta la estructura del paquete
desde foo.constants importar REPORT_FILE
y cruza los dedos esperando que todo funcione por fin...
De hecho, todo funciona (de manera quebradiza), pero de alguna manera todos los saltos de aro para que funcione te hacen sentir incómodo. Una breve introspección revela varias razones de la ola de aprensión:
- Dado que planeas trabajar en varios proyectos de Python al mismo tiempo, el aislamiento es una pieza fundamental de tu flujo de trabajo. Los entornos virtuales resuelven este problema, pero el proceso de activación/desactivación es engorroso y fácil de olvidar.
- El hecho de aislar las dependencias entre proyectos no aborda el conflicto de dependencias dentro de un proyecto. La resolución adecuada de dependencias es la principal característica requerida de cualquier administrador de paquetes, digna de respeto, pero pip solo tendrá esa función en octubre de 2020. Garantizar manualmente la coherencia de las dependencias en proyectos complejos es un punto muerto.
- Si desea instalar su aplicación/proyecto como un paquete, debe realizar la tarea de agregar un archivo setup.py además de sus ya múltiples archivos de requisitos. Sin embargo, has leído los PEP 517-518 y quieres probar los mecanismos de construcción más sencillos y seguros que se mencionan en él.
- Pensó en probar su aplicación en una máquina diferente, pero se dio cuenta de que ejecutaba Python 3.7 mientras que su caja local ejecutaba 3.8. Para usar pyenv con sus entornos virtuales aislados, necesita un complemento adicional, pyenv-virtualenv, lo que hace que la administración de venvs sea aún más engorrosa.
- Jugaste brevemente con Tubería v que prometía llevar a Python las características envidiadas de los gestores de paquetes más maduros de otros lenguajes (como yarn/npm de Javascript o Cargo de Rust) solo para decepcionarse rápidamente. Pipenv no solo afirmó engañosamente que era la herramienta de empaquetado oficial recomendada por Python (cuando en realidad estaba diseñada para escribir aplicaciones y no paquetes), sino que tampoco lanzó lanzamientos durante más de un año y aún se bloquea sin parar al crear el archivo de bloqueo que garantiza compilaciones repetibles y deterministas.
En un estado de desesperación desesperada, empiezas a buscar frenéticamente en Internet para ver si ya existe una solución que aborde todos estos problemas. En medio de una plétora de candidatos parciales o incompletos, por fin te encuentras con uno que los supera a todos: se llama Poesía.
La solución
Instalación (con Pipx)
Poetry es una aplicación CLI escrita en Python, por lo que simplemente puede instalarla con pip install --user poetry. Sin embargo, es probable que ya hayas instalado o vayas a instalar otras aplicaciones de la CLI de Python (por ejemplo, el sofisticado cliente de PostgreSQL pgcli o youtube-dl para descargar vídeos de YouTube). Si las instalas con el administrador de paquetes de tu sistema (por ejemplo, apt, yay o brew), se instalarán a nivel global y sus dependencias podrían entrar en conflicto. En su lugar, podrías crear un venv individual para cada uno, pero para poder usarlos tendrías que pasarte primero por la molestia de activar el entorno...
Para sortear este molesto escenario, puedes usar pips que instalará con precisión los paquetes en un entorno virtual aislado y, al mismo tiempo, los hará fácilmente disponibles en su shell (es decir, añadirá el ejecutable a sus binarios $PATH). Además de exponer las aplicaciones CLI al acceso global, también facilita la enumeración, actualización y desinstalación de estas aplicaciones. Para instalar Poetry con pipx, primero instala pipx con
python -m pip install —usuario pipx
python -m pipx asegura la ruta
y luego directamente hacer
pipx install —pip-args=» —pre» poesía
Si prefieres vivir al límite (como yo), también puedes instalar una versión preliminar con pipx install --pip-args='--pre' poetry.
Uso
Ahora, estás listo para probar las maravillas que promete la poesía. Para ello, creas una nueva carpeta/proyecto llamada foo-poetry con tus archivos.py arriba y, a continuación, ejecutas poetry init. Un mensaje interactivo empezará a pedirte que proporciones información básica sobre tu paquete (nombre, autor, etc.) que se utilizará para crear un archivo pyproject.toml. Básicamente, se trata de los mismos metadatos que agregaste anteriormente al setup.py, con algunas variaciones mínimas
Nombre del paquete [foo-poetry]: foo
Versión [0.1.0]: 0.0.1
Autor: Mutt info@muttdata.ai
Licencia:
Versiones de Python compatibles [^3.8]: ~3.7
¿Definir dependencias de forma interactiva? no
¿Definir las dependencias de desarrollo de forma interactiva? no
Archivo generado:
[tool.poesía]
nombre = «foo»
versión = «0.0.1»
autores = [«Mutt info@muttdata.ai»]
[tool.poetry.dependencies]
pitón = «^3.7»
[tool.poetry.dev-dependencies]
[sistema de construcción]
requiere = [«poetry-core >= 1.0.0a5»]
build-backend = «poetry.core.masonry.api»
¿Confirmar la generación? sí
Los dos ajustes relevantes a destacar son el sistema de compilación y la especificación de la versión de Python. Lo único que debes saber por el momento sobre la primera es que usa los estándares de los PEP 517-518 para definir una forma alternativa de construir un proyecto a partir del código fuente sin necesidad de herramientas de configuración (y, por lo tanto, elimina la necesidad de un archivo setup.py). En cuanto a la segunda configuración, para entender la sintaxis que especifica las restricciones de la versión de Python, deberías leer Versiones de poesía, documentos donde descubrirá que el requisito de signo de intercalación (^) significa que solo se permiten actualizaciones menores y de parches (es decir, que nuestra aplicación funcionará con Python 3.7 y 3.8 pero no con 4.0).
Hasta ahora, solo tiene un archivo TOML (que también puede usar para centralizar su configuración negra). ¿Cómo se especifican las dependencias? Simplemente ejecuta
poesía agregar pandas==0.25.3
lo que resulta en
Creación de virtualenv foo-klac03ac-py3.8 en /home/pedro/.cache/pypoetry/virtualenvs
Actualización de dependencias
Resolviendo dependencias... (0.6s)
Archivo de bloqueo de escritura
Operaciones de paquetes: 5 instalaciones, 0 actualizaciones, 0 eliminaciones
• Instalación de seis (1.15.0)
• Instalación de numpy (1.19.1)
• Instalación de python-dateutil (2.8.1)
• Instalación de pytz (2020.1)
• Instalación de pandas (0.25.3)
En otras palabras, un comando de adición inicial i) creará un entorno virtual, ii) instalará los paquetes solicitados y sus subdependencias, iii) escribirá la versión exacta de cada dependencia descargada en el archivo poetry.lock (que debe confirmar en su VCS para garantizar la replicabilidad) y iv) añadirá una línea con el paquete recién agregado a la sección tool.poetry.dependencies del archivo pyproject.toml. El último elemento también indica que, si desea instalar una nueva dependencia, puede reutilizar el comando add o agregar directamente dicha línea a su archivo pyproject.toml. Por ejemplo, si ahora quieres añadir la biblioteca de creación de perfiles de panda, puedes modificar el pyproject para tener
pandas-profiling="2.5.0"
Como en este momento ya existe un archivo poetry.lock, si ahora ejecuta poetry install, Poetry resolverá e instalará las dependencias utilizando las versiones especificadas en dicho archivo de bloqueo (para garantizar la coherencia de las versiones). Sin embargo, debido a que ha agregado una nueva dependencia manualmente al archivo pyproject.toml, el comando de instalación fallará. Por lo tanto, en este caso, debe ejecutar poetry update, lo que básicamente equivale a eliminar el archivo de bloqueo y ejecutar poetry install nuevamente.
Agregar una dependencia de desarrollo funciona de manera similar, con la única salvedad de que debes usar el indicador --dev al ejecutar el comando add.
poesía agregar pdbpp==0.10.2 —dev
poesía agregar negro == 19.10b0 —dev
y los paquetes resultantes se añadirán a la sección tool.poetry.dev-dependencies.
Ahora que las dependencias están configuradas, puede ejecutar su archivo de código data.py ejecutando
poetry run python data.py
que ejecutará el comando dentro del virtualenv del proyecto. Alternativamente, puedes generar un shell dentro del venv activo simplemente ejecutando
$>concha de poesía
Ahora imagine que desea actualizar la versión de Pandas como lo hizo antes al comprobar la incapacidad de pip para hacer cumplir la resolución de dependencias. Para hacer eso, actualiza la restricción de la siguiente manera
$>poetryaddpandas==1.0.0
que esta vez falla correctamente con el siguiente error
[Error de solucionador de problemas]
Porque la elaboración de perfiles de pandas (2.5.0) depende de los pandas (0.25.3)
y la comida depende de los pandas (1.0.0),
la creación de perfiles de panda es incompatible.
Fallo al resolver la versión.
A estas alturas, te has dado cuenta de que Poetry parece abordar las dos solicitudes iniciales que enumeraste en la sección anterior (a saber, un fácil aislamiento del proyecto y una resolución automática de dependencias adecuada). Antes de hacerte ilusiones, compruebas si puede empaquetar tu código de forma sencilla (especialmente sin un archivo setup.py). Cabe destacar que este sencillo se reduce a la inclusión de la siguiente línea (la sección tool.poetry) del archivo pyproject.toml
paquetes= [{include="foo "}]
seguido de la ejecución de una nueva instalación de poesía que, de forma predeterminada, instalará el proyecto en modo editable.
Emocionado por la simplicidad y facilidad de uso de Poetry, comienza a preguntarse si Poetry es la herramienta definitiva que ha estado buscando. ¿Puede marcar todas las casillas? Para responder de manera concluyente a esa pregunta, querrá ver si es fácil cambiar entre diferentes versiones de Python. Dado que tu máquina local usa Python 3.8 de forma predeterminada, entonces instalas 3.7.7 con pyenv install 3.7.7 (instalar una versión anterior no habría funcionado en el futuro, ya que configuraste 3.7 como el límite inferior de tu aplicación pyproject.toml). Para que esta versión esté disponible localmente, agrega un archivo.python a la raíz de su proyecto que contenga una sola línea con 3.7.7 y luego le dice a Poetry que cree y use un virtualenv con esa versión con
$>poesía en vuse 3.7
Una vez que compruebes que está correctamente activado con poetry env list, instalas todas las dependencias con poetry install y, finalmente, ejecutas tu código que (como era de esperar) finaliza sin problemas.
Maravillado por su sencillez intuitiva, llegas a la conclusión de que la poesía es exactamente lo que necesitabas. De hecho, aún no lo sabes, pero tienes mucho más de lo que esperabas, ya que solo has arañado la superficie de los rasgos. Aún tienes que descubrir que instala paquetes en paralelo, lanza bonitas excepciones de colores cuando se desata el infierno, se integra con tu IDE o editor preferido (si es vim, puedes probar con el de tu humilde servidor) visión desvergonzada del asunto), tiene un comando para publicar directamente un paquete y, entre otras innumerables delicias, está programado para tener un sistema de complementos para una mayor extensibilidad.
Una cosa está muy clara: Poetry es el gestor de paquetes de Python del mañana. También podrías empezar a usarlo hoy mismo.
Nota: este artículo pertenece a nuestros documentos de incorporación internos y se ha ajustado ligeramente para el público en general.
Latest Insights
¿Cómo sabes que es hora de hacer evolucionar tu marca?
.webp)
El lenguaje natural se une a los datos en tiempo real: análisis sin cuellos de botella

No todos los optimizadores de medios online están diseñados de la misma manera
