| name | poetry |
| description | [Applies to: **/*.py] Definitive guidelines for using Poetry for Python dependency management, packaging, and project structure, emphasizing modern best practices as of 2025. |
| source | cursor_mdc |
poetry Best Practices
Poetry is the de-facto standard for modern Python project management. This guide outlines our team's definitive best practices for leveraging Poetry's full power, ensuring reproducible builds, streamlined development, and robust packaging.
1. Project Initialization & Structure
Always start new projects with poetry new to establish a correct pyproject.toml and project structure.
✅ GOOD: Use src layout by default
Poetry 2.1+ defaults to the src layout, which prevents common import issues and improves package isolation.
poetry new my-project
This creates:
my-project/
├── pyproject.toml
├── README.md
├── my_project/ # Your package source code lives here
│ └── __init__.py
└── tests/
└── __init__.py
└── test_my_project.py
2. pyproject.toml Configuration
pyproject.toml is your project's single source of truth.
✅ GOOD: Prioritize PEP 621 [project] section
Poetry 2.0+ fully supports PEP 621. Use the [project] section for standard metadata (name, version, description, authors, etc.). Only use [tool.poetry] for Poetry-specific features not covered by PEP 621.
❌ BAD: Using deprecated tool.poetry fields
[tool.poetry]
name = "my-project"
version = "0.1.0"
description = "A bad example"
authors = ["Bad Developer <bad@example.com>"]
✅ GOOD: Using [project] for standard metadata
[project]
name = "my-project"
version = "0.1.0"
description = "A good example using PEP 621"
authors = [{name = "Good Developer", email = "good@example.com"}]
readme = "README.md"
requires-python = ">=3.9,<4.0"
license = { text = "MIT" }
keywords = ["python", "poetry", "best-practices"]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
[tool.poetry]
packages = [{ include = "my_project" }]
✅ GOOD: Explicitly declare [build-system]
Always define your build backend explicitly, even if using poetry-core. This ensures consistent builds and prepares for alternative backends.
[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
✅ GOOD: Use alternative build backends when appropriate
For projects with Rust extensions (maturin) or other specific needs, declare the alternative build backend.
[build-system]
requires = ["maturin>=0.8.1,<0.9"]
build-backend = "maturin"
3. Dependency Management
✅ GOOD: Add dependencies with explicit constraints
Always use poetry add and specify PEP 440-compliant version constraints. Avoid unconstrained dependencies (*) to prevent unexpected breakage.
❌ BAD: Unconstrained or overly broad dependencies
poetry add requests
poetry add my-lib@*
✅ GOOD: Explicit, well-defined dependency constraints
poetry add requests@^2.30.0
poetry add rich@~13.0
poetry add pandas@">=2.0.0,<2.1.0"
✅ GOOD: Group development dependencies
Isolate development tools (linters, formatters, test runners) into a dev group. This keeps production environments lean.
poetry add --group dev pytest black isort flake8 mypy
[project]
[tool.poetry.group.dev.dependencies]
pytest = "^7.0"
black = "^23.0"
isort = "^5.0"
flake8 = "^6.0"
mypy = "^1.0"
✅ GOOD: Commit poetry.lock
Always commit poetry.lock to ensure reproducible environments across all development, CI/CD, and production systems.
git add pyproject.toml poetry.lock
git commit -m "feat: Add initial project setup"
❌ BAD: Manually editing poetry.lock
Never manually edit poetry.lock. It's generated by Poetry and should only be updated via poetry add, poetry remove, or poetry update.
4. Virtual Environments & Execution
✅ GOOD: Use pipx for Poetry installation
Install Poetry itself in an isolated environment using pipx to avoid conflicts with project dependencies.
pipx install poetry
pipx upgrade poetry
✅ GOOD: Activate environments with poetry env activate
Use poetry env activate to get the shell command for activating the virtual environment. This is more robust than the deprecated poetry shell.
eval $(poetry env activate)
poetry python install 3.11
poetry env use 3.11
eval $(poetry env activate)
✅ GOOD: Execute commands with poetry run
For one-off commands or scripts, use poetry run to execute them within the project's virtual environment without explicit activation.
poetry run pytest
poetry run black .
5. Code Quality & Automation
✅ GOOD: Integrate pre-commit hooks
Enforce code quality standards (formatting, linting, typing) on every commit using pre-commit hooks.
-
Install pre-commit:
poetry add --group dev pre-commit
poetry run pre-commit install
-
Configure .pre-commit-config.yaml:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/psf/black
rev: 23.12.1
hooks:
- id: black
- repo: https://github.com/PyCQA/isort
rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
hooks:
- id:
[]
6. Packaging & Publishing
✅ GOOD: Build packages with poetry build
Use poetry build to create sdist and wheel distributions. Ensure your pyproject.toml's [build-system] is correctly configured.
poetry build
✅ GOOD: Publish to PyPI or private repositories
Use poetry publish to distribute your package. Configure credentials securely.
poetry publish --build
poetry publish -r my-private-repo --build
7. Performance & Troubleshooting
✅ GOOD: Update dependencies regularly
Run poetry update to refresh dependencies, but always review changelogs and run tests before committing.
poetry update
✅ GOOD: Clear cache for resolution issues
If dependency resolution is slow or problematic, clear Poetry's cache.
poetry cache clear --all pypi