Poetry en Python

Poetry es una herramienta de gestión de dependencias y empaquetado en Python que facilita el desarrollo, la instalación de librerías, la creación de entornos virtuales y la publicación de paquetes. A diferencia de pip y virtualenv, Poetry unifica el manejo de entornos y dependencias en un solo comando, con un archivo central llamado pyproject.toml.

Web oficial: https://python-poetry.org/


✅ ¿Qué es Poetry?

Poetry es una herramienta moderna para:

  • Crear proyectos Python.
  • Gestionar dependencias.
  • Mantener versiones coherentes.
  • Crear entornos virtuales automáticos.
  • Publicar paquetes en PyPI.

Instalación de Poetry

Recomendado: instalar con «pipx»

💡 macOS (Homebrew)

Nota para macOS: Debido a restricciones recientes (PEP 668), la forma recomendada es instalar pipx con Homebrew para evitar errores como externally-managed-environment.

🔎 ¿Qué son brew y pipx?

  • Homebrew (brew): es el gestor de paquetes más popular en macOS. Permite instalar fácilmente herramientas, librerías y utilidades desde la terminal sin tener que compilar o configurar nada manualmente. Si quieres más info y saber como instalarlo deja un comentario o házmelo saber y crearé un post sobre ello.
  • pipx: es una herramienta que permite instalar y ejecutar aplicaciones Python aisladas globalmente, sin interferir con tu instalación principal de Python. Ideal para herramientas como poetry, black, httpie, etc. Ahora veremos como instalarlo.

Instalando pipx y agregando path

brew install pipx
pipx ensurepath

Reinicia la terminal o ejecuta este comando:

source ~/.zshrc

Para instalar Poetry:

pipx install poetry

🐳 Linux

Instalando pipx, agregando path y instalado Poetry

python3 -m pip install --user pipx
python3 -m pipx ensurepath
pipx install poetry

🪦 Windows (PowerShell)

Instalando pipx, agregando path y instalado Poetry

python -m pip install --user pipx
python -m pipx ensurepath
pipx install poetry

Para verifica que todo esté correcto:

poetry --version

Comandos más útiles

ComandoDescripción
poetry new nombre_proyectoCrea un nuevo proyecto
poetry initInicializa un proyecto en un directorio existente
poetry installInstala dependencias desde pyproject.toml
poetry add paqueteAñade una dependencia
poetry remove paqueteElimina una dependencia
poetry updateActualiza todas las dependencias
poetry update paqueteActualiza solo un paquete
poetry lockActualiza el archivo poetry.lock
poetry shellEntra al entorno virtual
poetry run comandoEjecuta un comando dentro del entorno virtual
poetry exportExporta las dependencias a requirements.txt

⚠️ A partir de Poetry 1.8, poetry shell ya no está disponible por defecto. Es necesario instalar el plugin plugin-shell si deseas seguir utilizando este comando para acceder al entorno virtual:

poetry self add poetry-plugin-shell

📁 Crear Proyecto

Accederemos a la carpeta donde queremos crear el proyecto y ejecutamos:

poetry init

Poetry te hará una serie de preguntas sobre el nombre, versión, autor, licencia, Python requerido, y dependencias.

Al finalizar la instalacion nos habrá creado 2 archivos:project.toml y pypoetry.lock (si hemos instalado dependencias)

project.toml:
- Es el archivo principal de configuración del proyecto. Contiene:
	•	Nombre, versión y descripción del proyecto.
	•	Autor y licencia.
	•	Versión mínima de Python requerida.
	•	Dependencias ([tool.poetry.dependencies])
	•	Dependencias de desarrollo ([tool.poetry.dev-dependencies])
	•	Configuraciones de publicación y scripts.

poetry.lock:
- Este archivo se genera automáticamente tras instalar dependencias. Sirve para:
	•	Fijar versiones exactas de todas las dependencias (incluidas subdependencias).
	•	Garantizar que todos los desarrolladores usen las mismas versiones (ideal para equipos y CI/CD).
	•	Evitar que una actualización automática rompa tu proyecto.

📌 Consejo:

  • Puedes editar project.tom manualmente o dejar que poetry lo modifique por ti con poetry add, poetry remove, etc.
  • No edites poetry.lock a mano. Déjalo siempre bajo control de Poetry.

💡 Ambos archivos deben incluirse en control de versiones (Git) para garantizar reproducibilidad.

Inicialización rápida:

poetry init --no-interaction


Ejemplos comunes para la pregunta de licencia y versión

Licencia:

EntradaDescripción
MITMuy permisiva. Puedes usar, copiar, modificar y distribuir con pocos requisitos.
Apache-2.0Similar a MIT, pero con protección de patentes.
GPL-3.0Licencia copyleft. Los derivados deben también ser código abierto.
BSD-3-ClausePermisiva, usada en entornos académicos y empresas.
ProprietaryPara proyectos cerrados con derechos reservados.
(vacío)No defines licencia, por tanto legalmente nadie podrá usar tu proyecto.

Versiones compatibles de Python:

EntradaSignificado
^3.9Compatible con 3.9.x, 3.10.x, 3.11.x, etc., pero no con 4.0
>=3.9Requiere al menos Python 3.9 (puede ser compatible con 4.0 en adelante)
>=3.9,<3.12Compatible desde 3.9 hasta (pero sin incluir) 3.12
~3.10Solo versiones 3.10.x
==3.10.*Igual: exactamente versiones 3.10.x
>=3.10,!=3.11.0Desde 3.10, excluyendo la versión 3.11.0
>=3.9,<4.0Muy común: desde Python 3.9 hasta justo antes de Python 4.0

Añadir, actualizar, eliminar dependencias

➕ Añadir un paquete

poetry add requests

🔄 Actualizar un paquete específico

poetry update requests

🔄 Actualizar todo

poetry update

🔄 En caso de tener las dependencias en el archivo toml podemos instalarlo todo a la vez

poetry install

➖ Eliminar un paquete

poetry remove requests

Creación y uso del entorno virtual

El entorno virtual se crea cuando instalas una dependencia por primera vez, ya sea con:

poetry add paquete   |   poetry install    o   bien al introducirlas cuando hacemos el init

(si ya hay dependencias definidas en el archivo pyproject.toml), Poetry crea automáticamente un entorno virtual aislado para tu proyecto.

Puedes trabajar dentro de ese entorno virtual de dos formas:

  1. Entrar en el entorno interactivo: (recuerda que hay que instalar su plugin como hemos visto más arriba)
poetry shell

Una vez dentro, puedes ejecutar scripts normalmente con:

python3 main.py
  1. Ejecutar comandos directamente sin activar el entorno:
poetry run python3 main.py

Esto es útil en entornos automatizados o si prefieres no cambiar de shell.

📂 Ubicación de los entornos virtuales

Poetry guarda los entornos virtuales en distintas rutas según el sistema operativo:

  • macOS / Linux:/Users/<usuario>/Library/Caches/pypoetry/virtualenvs/
  • Windows:%APPDATA%\pypoetry\virtualenvs\

Puedes listar todos los entornos detectados con:

poetry env list

Y eliminar uno con:

poetry env remove python

Si algún entorno no aparece en la lista, pero sabes que ya no se usa, puedes eliminar la carpeta manualmente desde la ruta correspondiente.


Exportar dependencias

Para compartir el proyecto con pip, puedes generar un archivo requirements.txt:

poetry export -f requirements.txt --output requirements.txt --without-hashes

Agrega –dev si quieres incluir dependencias de desarrollo.


Importar desde requirements.txt

Si ya tienes un archivo requirements.txt, puedes convertirlo fácilmente a dependencias en Poetry.

Opción rápida (línea de comandos)

poetry add $(cat requirements.txt)

⚠️ Este método puede fallar si el archivo contiene comentarios (#) o líneas vacías. Para evitar errores:

grep -vE '^\s*#|^\s*$' requirements.txt > clean-req.txt
poetry add $(cat clean-req.txt)

Opción alternativa con plugin oficial

Puedes usar el plugin poetry-plugin-import:

poetry self add poetry-plugin-import
poetry import requirements.txt

Esto añadirá las dependencias al pyproject.toml de forma segura y limpia.


Con esta guía ya puedes empezar a trabajar con proyectos Python usando Poetry!

Espero que os sirva de ayuda.

Salu2.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Warning: Undefined array key "rerror" in /volume1/web/WebTomoNota/wp-content/plugins/wp-recaptcha-bp/recaptcha.php on line 300 Call Stack: 0.0001 360936 1. {main}() /volume1/web/WebTomoNota/index.php:0 0.0001 361248 2. require('/volume1/web/WebTomoNota/wp-blog-header.php') /volume1/web/WebTomoNota/index.php:17 0.4804 14476120 3. require_once('/volume1/web/WebTomoNota/wp-includes/template-loader.php') /volume1/web/WebTomoNota/wp-blog-header.php:19 0.4867 14644512 4. include('/volume1/web/WebTomoNota/wp-content/themes/yuki/index.php') /volume1/web/WebTomoNota/wp-includes/template-loader.php:106 2.6668 19022864 5. yuki_do_elementor_location($elementor_location = 'single', $template_part = 'template-parts/special', $name = 'single') /volume1/web/WebTomoNota/wp-content/themes/yuki/index.php:20 2.6668 19022864 6. get_template_part($slug = 'template-parts/special', $name = 'single', $args = ???) /volume1/web/WebTomoNota/wp-content/themes/yuki/inc/helpers.php:34 2.6668 19023440 7. locate_template($template_names = [0 => 'template-parts/special-single.php', 1 => 'template-parts/special.php'], $load = TRUE, $load_once = FALSE, $args = []) /volume1/web/WebTomoNota/wp-includes/general-template.php:206 2.6669 19023552 8. load_template($_template_file = '/volume1/web/WebTomoNota/wp-content/themes/yuki/template-parts/special-single.php', $load_once = FALSE, $args = []) /volume1/web/WebTomoNota/wp-includes/template.php:745 2.6671 19029664 9. require('/volume1/web/WebTomoNota/wp-content/themes/yuki/template-parts/special-single.php') /volume1/web/WebTomoNota/wp-includes/template.php:812 2.7582 19032440 10. do_action($hook_name = 'yuki_action_after_single_post') /volume1/web/WebTomoNota/wp-content/themes/yuki/template-parts/special-single.php:58 2.7583 19032816 11. WP_Hook->do_action($args = [0 => '']) /volume1/web/WebTomoNota/wp-includes/plugin.php:517 2.7583 19032816 12. WP_Hook->apply_filters($value = '', $args = [0 => '']) /volume1/web/WebTomoNota/wp-includes/class-wp-hook.php:348 2.8513 19118760 13. yuki_show_post_comments('') /volume1/web/WebTomoNota/wp-includes/class-wp-hook.php:324 2.8515 19118760 14. comments_template($file = ???, $separate_comments = ???) /volume1/web/WebTomoNota/wp-content/themes/yuki/inc/template-functions.php:354 2.8537 19134432 15. require('/volume1/web/WebTomoNota/wp-content/themes/yuki/comments.php') /volume1/web/WebTomoNota/wp-includes/comment-template.php:1631 2.8537 19134432 16. comment_form($args = ['class_form' => 'comment-form yuki-form form-default'], $post = ???) /volume1/web/WebTomoNota/wp-content/themes/yuki/comments.php:66 2.8561 19146152 17. do_action($hook_name = 'comment_form', ...$arg = variadic(1605)) /volume1/web/WebTomoNota/wp-includes/comment-template.php:2896 2.8561 19146528 18. WP_Hook->do_action($args = [0 => 1605]) /volume1/web/WebTomoNota/wp-includes/plugin.php:517 2.8561 19146528 19. WP_Hook->apply_filters($value = '', $args = [0 => 1605]) /volume1/web/WebTomoNota/wp-includes/class-wp-hook.php:348 2.8562 19147280 20. ReCAPTCHAPlugin->show_recaptcha_in_comments(1605) /volume1/web/WebTomoNota/wp-includes/class-wp-hook.php:324
 
Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST https://api.aspose.cloud/connect/token` resulted in a `400 Bad Request` response: {"error":"invalid_client"} in /volume1/web/WebTomoNota/wp-content/plugins/aspose-doc-exporter/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php on line 113 GuzzleHttp\Exception\ClientException: Client error: `POST https://api.aspose.cloud/connect/token` resulted in a `400 Bad Request` response: {"error":"invalid_client"} in /volume1/web/WebTomoNota/wp-content/plugins/aspose-doc-exporter/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php on line 113 Call Stack: 2.8860 19138768 1. shutdown_action_hook() /volume1/web/WebTomoNota/wp-includes/load.php:0 2.8860 19138768 2. do_action($hook_name = 'shutdown') /volume1/web/WebTomoNota/wp-includes/load.php:1304 2.8860 19139144 3. WP_Hook->do_action($args = [0 => '']) /volume1/web/WebTomoNota/wp-includes/plugin.php:517 2.8860 19139144 4. WP_Hook->apply_filters($value = '', $args = [0 => '']) /volume1/web/WebTomoNota/wp-includes/class-wp-hook.php:348 2.8861 19070544 5. AsposeWords\AutoExport->export('') /volume1/web/WebTomoNota/wp-includes/class-wp-hook.php:324 2.9428 21167608 6. AsposeWords\ExportEngine->convert() /volume1/web/WebTomoNota/wp-content/plugins/aspose-doc-exporter/src/AsposeWords/AutoExport.php:26 2.9443 21245552 7. AsposeWords\Util::getWordsApi() /volume1/web/WebTomoNota/wp-content/plugins/aspose-doc-exporter/src/AsposeWords/ExportEngine.php:87 3.0373 29664368 8. Aspose\Words\WordsApi->__construct($clientId = '875775BC-8A52-49BA-8C65-7F4BDFA6802E', $clientSecret = '69f869e481bfde19e81735d12ddc3db4', $baseUrl = 'https://api.aspose.cloud/') /volume1/web/WebTomoNota/wp-content/plugins/aspose-doc-exporter/src/AsposeWords/Util.php:27 3.0467 30335056 9. Aspose\Words\WordsApi->_checkRsaKey() /volume1/web/WebTomoNota/wp-content/plugins/aspose-doc-exporter/vendor/aspose-cloud/aspose-words-cloud/src/Aspose/Words/WordsApi.php:80 3.0467 30335056 10. Aspose\Words\WordsApi->_getKey() /volume1/web/WebTomoNota/wp-content/plugins/aspose-doc-exporter/vendor/aspose-cloud/aspose-words-cloud/src/Aspose/Words/WordsApi.php:50666 3.0467 30335056 11. Aspose\Words\WordsApi->_checkAuthToken() /volume1/web/WebTomoNota/wp-content/plugins/aspose-doc-exporter/vendor/aspose-cloud/aspose-words-cloud/src/Aspose/Words/WordsApi.php:50654 3.0467 30335056 12. Aspose\Words\WordsApi->_requestToken() /volume1/web/WebTomoNota/wp-content/plugins/aspose-doc-exporter/vendor/aspose-cloud/aspose-words-cloud/src/Aspose/Words/WordsApi.php:50648 3.0531 30674728 13. GuzzleHttp\Client->send($request = class GuzzleHttp\Psr7\Request { private $method = 'POST'; private $requestTarget = NULL; private $uri = class GuzzleHttp\Psr7\Uri { private $scheme = 'https'; private $userInfo = ''; private $host = 'api.aspose.cloud'; private $port = NULL; private $path = '/connect/token'; private $query = ''; private $fragment = ''; private $composedComponents = 'https://api.aspose.cloud/connect/token' }; private $headers = ['Host' => [...]]; private $headerNames = ['host' => 'Host']; private $protocol = '1.1'; private $stream = class GuzzleHttp\Psr7\MultipartStream { private $boundary = 'd55f5f2b83a1058a313560cef6adf90bf94c0914'; public $stream = class GuzzleHttp\Psr7\AppendStream { ... } } }, $options = ???) /volume1/web/WebTomoNota/wp-content/plugins/aspose-doc-exporter/vendor/aspose-cloud/aspose-words-cloud/src/Aspose/Words/WordsApi.php:50640 3.5071 30855800 14. GuzzleHttp\Promise\Promise->wait($unwrap = ???) /volume1/web/WebTomoNota/wp-content/plugins/aspose-doc-exporter/vendor/guzzlehttp/guzzle/src/Client.php:123