Chapter 6, Environment
Poetry: projects, dependencies and lockfile
Poetry combines environment creation, dependency resolution, lock file, and publishing in a single command. I will show how it works today, in version 2.
Code for this chapter: ambiente/cap06_poetry.py
What Poetry solves
The pip installs. Poetry manages: declares the project's dependencies in the pyproject.toml, resolves the complete tree of indirect dependencies, records the exact versions in poetry.lock and creates the virtual environment for you. Two colleagues running poetry install get exactly the same packages.
A point of attention in version 2: Poetry started to respect the section [project] of the pyproject.toml, which is the community standard (PEP 621). The command poetry shell has been moved to a plugin, and the replacement is poetry env activate.
Install
The path I recommend is to install Poetry with pipx, so it stays isolated:
pipx install poetry
poetry --version
The official installer also works:
curl -sSL https://install.python-poetry.org | python3 -
Create a project
Poetry creates the structure and the pyproject.toml. In current versions, the code goes to the folder src/ by default, which is the layout I recommend in the packaging chapter. The option --src, which you still see in old tutorials, is being deprecated precisely because it has become the default behavior:
poetry new meu-projeto
cd meu-projeto
To transform an existing folder into a Poetry project, use poetry init, which asks questions in the terminal. After poetry add requests and poetry add --group dev pytest, the file looks like this. Note that the development group goes to [dependency-groups], the same standard that uv uses, and that the author fields come with example values for you to change:
[project]
name = "meu-projeto"
version = "0.1.0"
description = ""
authors = [
{name = "Your Name",email = "you@example.com"}
]
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"requests (>=2.34.2,<3.0.0)"
]
[tool.poetry]
packages = [{include = "meu_projeto", from = "src"}]
[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
[dependency-groups]
dev = [
"pytest (>=9.1.1,<10.0.0)"
]
Everyday commands
poetry add requests
poetry add --group dev pytest
poetry remove requests
poetry install
poetry sync
poetry run python -m meu_projeto
poetry run pytest
poetry show --tree
poetry update
poetry lock
The difference between install and sync: the install ensures that the necessary is installed. The sync makes the environment identical to the lockfile, removing what remains.
Activate the environment
You can always use poetry run, without activating anything. If you prefer to activate the environment in your session, in Poetry 2 the command prints the activation instruction, and you execute it. On macOS and Linux, eval $(poetry env activate) does both things at once:
poetry env activate
poetry env info --path
poetry env use 3.13
. /caminho/do/projeto/.venv/bin/activate
The block above shows what the first command prints in a project with .venv inside the folder.
For Poetry to create the .venv inside the project folder (which editors detect on their own), configure it once:
poetry config virtualenvs.in-project true
Read the pyproject.toml with Python
Since Python 3.11 there is the module tomllib in the standard library, which reads TOML:
import tomllib
texto = """
[project]
name = "meu-projeto"
dependencies = ["requests>=2.32"]
"""
dados = tomllib.loads(texto)
print(dados["project"]["name"])
print(dados["project"]["dependencies"])
meu-projeto
['requests>=2.32']
Commit the poetry.lock
In applications, the
poetry.lockgoes to Git. It ensures that your production server installs the same as you tested. In published libraries, the discussion is more subtle, and I will return to it in the packaging chapter.