Basic Usage & Project Setup

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the Python Reference bibliography.

This page walks through the everyday Poetry cycle: create or adopt a project, add dependencies, install, run, update. It was written against Poetry 2.5.1 with poetry-core 2.5.0; every command ran on CPython 3.14.6 on 2026-10-22 with POETRY_VIRTUALENVS_IN_PROJECT=true, so that each project’s venv is the .venv next to its pyproject.toml. Scratch paths are shortened to …. Installing Poetry itself is on Installation & Self-Management.

flowchart LR A["edit code and pyproject.toml"] --> B["poetry add / remove"] B --> C["poetry lock (writes poetry.lock)"] C --> D["poetry install / sync (updates .venv)"] D --> E["poetry run pytest, poetry run birdtally"] E --> A F["poetry update"] --> C

poetry add and poetry remove lock and install for you; poetry lock on its own is needed after you edit pyproject.toml by hand.

Creating a project: poetry new

poetry new --author "The birdtally authors" birdtally
find birdtally | sort
cat birdtally/pyproject.toml
Created package birdtally in birdtally
birdtally
birdtally/README.md
birdtally/pyproject.toml
birdtally/src
birdtally/src/birdtally
birdtally/src/birdtally/__init__.py
birdtally/tests
birdtally/tests/__init__.py
[project]
name = "birdtally"
version = "0.1.0"
description = ""
authors = [
    {name = "The birdtally authors"}
]
readme = "README.md"
requires-python = ">=3.14"
dependencies = [
]

[tool.poetry]
packages = [{include = "birdtally", from = "src"}]

[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
  • Since Poetry 2.1 the src layout is the default; --src is now a deprecated no-op and --flat creates birdtally/birdtally/ instead (the trade-offs are on Preparing a Library).

  • requires-python defaults to the minor version of the Python that Poetry finds (here 3.14). For a library, lower it to the oldest Python you support, >=3.10 for birdtally.

  • Without --author, the author comes from your Git configuration.

  • Other options: --name (package name if it differs from the directory), --readme md|rst|txt, --description, --python, --dependency, --dev-dependency, -l/--license, and -i/--interactive to be asked for each value.

poetry new --flat --name flatbirds --readme rst flatbirds
find flatbirds | sort
Created package flatbirds in flatbirds
flatbirds
flatbirds/README.rst
flatbirds/flatbirds
flatbirds/flatbirds/__init__.py
flatbirds/pyproject.toml
flatbirds/tests
flatbirds/tests/__init__.py

Adopting an existing project: poetry init

poetry init writes a pyproject.toml in the current directory, asking questions unless you pass --no-interaction. It accepts the same metadata options as new plus --dependency and --dev-dependency. A worked migration of a requirements.txt project is on Choosing & Migrating.

Setting the Python version

requires-python is the range the project supports; it constrains resolution (every dependency must support the whole range) and becomes Requires-Python in the metadata. Which interpreter the environment uses is a separate choice, made with poetry env use python3.14 or by running Poetry from an already active venv. If no environment exists yet, Poetry 2.5.1 starts from the python on your PATH (or from the Python Poetry itself runs on, with virtualenvs.use-poetry-python = true) and, if that does not satisfy requires-python, tries to find one that does; failing that it asks you to choose one with env use. See Managing Environments.

Package mode and non-package mode

Package mode (default) Non-package mode (package-mode = false, Poetry 1.8)

Use for

Libraries and anything you build or publish

Applications, scripts, notebooks, services

name, version

Required

Optional

poetry install

Also installs the project itself, in editable mode

Installs only the dependencies (as --no-root)

poetry build, poetry publish

Work

Not possible

birdtally-report is an application, so its file says:

[project]
name = "birdtally-report"
version = "0.1.0"
description = "Weekly survey report built on birdtally."
requires-python = ">=3.10"
dependencies = ["birdtally[pretty] (>=0.1.0)"]

[tool.poetry]
package-mode = false

[tool.poetry.dependencies]
birdtally = { source = "birdwatch" }

[[tool.poetry.source]]
name = "birdwatch"
url = "http://localhost:8080/simple/"
priority = "explicit"
poetry install
poetry run python report.py
…
Package operations: 5 installs, 0 updates, 0 removals

  - Installing birdtally (0.1.0)
  - Installing markdown-it-py (4.2.0)
  - Installing mdurl (0.1.2)
  - Installing pygments (2.21.0)
  - Installing rich (15.0.0)
   Weekly survey
┏━━━━━━━━━━┳━━━━━━━┓
┃ Species  ┃ Count ┃
┡━━━━━━━━━━╇━━━━━━━┩
│ lapwing  │ 7     │
│ redshank │ 2     │
└──────────┴───────┘

Adding dependencies

poetry add rich resolves, writes "rich (>=15.0.0,<16.0.0)" into [project] dependencies, updates poetry.lock and installs. Groups, extras, Git and path dependencies are on Managing Dependencies & Groups, and the constraint syntax on Dependency Specification. In short, [project] dependencies takes PEP 508 strings ("rich (>=13)"), and Poetry’s caret (^13) and tilde (~13.7) shorthands are allowed only in [tool.poetry] tables and on the poetry add command line.

Using the environment

poetry run

poetry run <command> runs a command inside the project’s environment without activating it:

poetry run birdtally survey.csv --by site
{
  "north-marsh": 6,
  "east-dunes": 3
}

The errors you meet with it all come from the environment being out of step with pyproject.toml:

  • a command that is not installed in the environment, for example a script added to [project.scripts] without running poetry install again:

    Command not found: nosuch
  • a script entry that names a module that does not exist (birdtally-old = "birdtally.commandline:main"):

    Traceback (most recent call last):
      File "…/pscr/.venv/bin/birdtally-old", line 3, in <module>
        from birdtally.commandline import main
    ModuleNotFoundError: No module named 'birdtally.commandline'
  • a script entry with a misspelt function (birdtally-typo = "birdtally.cli:mian"); with Poetry 2.5.1’s generated launcher this is an ImportError, not an AttributeError:

    Traceback (most recent call last):
      File "…/pscr/.venv/bin/birdtally-typo", line 3, in <module>
        from birdtally.cli import mian
    ImportError: cannot import name 'mian' from 'birdtally.cli' (…/pscr/src/birdtally/cli.py)

Activating the environment

poetry shell left the core in Poetry 2.0. poetry env activate prints the command that activates the environment; feed it to your shell:

poetry env activate
source …/poetry-flavour/birdtally/.venv/bin/activate
eval $(poetry env activate)          # bash, zsh, csh
eval (poetry env activate)           # fish
Invoke-Expression (poetry env activate)

If you prefer the old sub-shell behaviour, install the poetry-plugin-shell plugin (see Plugins). When a venv is already active, or you manage one yourself (conda, a hand-made venv), Poetry uses it and poetry run is not needed.

Installing

Without poetry.lock, poetry install resolves the dependencies, writes the lock and installs. With poetry.lock, it installs exactly the locked versions and does not resolve; if pyproject.toml changed in a way that makes the lock stale, it stops and asks you to run poetry lock (see Lock File: install, update & sync).

In package mode poetry install also installs the project itself, in editable mode. --no-root skips it (dependencies only), --only-root installs only the project:

poetry install --no-root --only main -E pretty
poetry run python -c "import birdtally"
poetry install --only-root
poetry run python -c "import birdtally; print('ok')"
Updating dependencies
Resolving dependencies...

Package operations: 4 installs, 0 updates, 0 removals

  - Installing mdurl (0.1.2)
  - Installing markdown-it-py (4.2.0)
  - Installing pygments (2.21.0)
  - Installing rich (15.0.0)

Writing lock file
…
ModuleNotFoundError: No module named 'birdtally'
Installing dependencies from lock file

Installing the current project: birdtally (0.1.0)
ok

The first call had no lock file, so it resolved and wrote one ("Updating dependencies", "Writing lock file"); the second installed "from lock file". --no-root is the first step of the Docker pattern on CI Caching & Containers.

Committing the lock file

Commit poetry.lock for an application: everybody, CI and production then install the same versions. For a library it is optional, because the lock has no effect on your users; if you commit it, refresh it regularly. The reasoning is on Lock Files & Reproducible Installs.

Updating

poetry update re-resolves all dependencies to the newest versions the constraints allow and rewrites the lock; poetry update rich does it for one package (and what it needs). Constraints are not changed: to move beyond <16.0.0, use poetry add rich@latest.

pip install -e . ignores the lock

pip does not read poetry.lock. In a project whose lock pins rich 14.3.3 (locked with a long cooldown to make the point), Poetry installs that version and an editable pip install of the same directory gets the newest one:

poetry install --only main -E pretty
poetry run python -c "import importlib.metadata as m; print('poetry env:', m.version('rich'))"
python -m venv ../pipvenv && ../pipvenv/bin/python -m pip install -q -e ".[pretty]"
../pipvenv/bin/python -c "import importlib.metadata as m; print('pip -e env:', m.version('rich'))"
  - Downgrading rich (15.0.0 -> 14.3.3)
poetry env: 14.3.3
pip -e env: 15.0.0

If someone must use pip, give them an export of the lock (poetry export) and pip install --no-deps -e . after it; see Exporting Requirements & Bundling.