Python Dependency Management: pip vs Poetry Cheat Sheet

pip and Poetry commands side by side: install, inspect, upgrade and remove packages, reproduce an environment, manage virtualenvs and register your own command-line scripts.
Python Dependency Management: pip vs Poetry Cheat Sheet

Every Python project has to answer the same two questions: how do I install the packages I need, and how do I make sure the next machine gets exactly the same ones? pip answers the first well and the second badly. Poetry answers both, at the cost of learning a new tool. This cheat sheet puts the everyday commands side by side so you can switch between them without looking anything up.

The examples install Iotcore, an MQTT broker package I maintain, but any package name works.

When to use which

Use pip directly when you are inside an existing virtual environment, writing a quick script or working in a project that already has a requirements.txt. Use Poetry when you are starting a project that other people will install, publishing a package or when “it works on my machine” has bitten you once too often. Poetry’s lock file records the exact version of every dependency and sub-dependency, which pip alone does not do.

Both tools can coexist. Poetry uses pip under the hood to install wheels, and you can always pip install inside a Poetry environment in a pinch.

pip: the everyday commands

Prefer python3 -m pip over a bare pip. It guarantees the package lands in the interpreter you think it does, which matters on machines with more than one Python.

Install a package:

python3 -m pip install iotcore

Show where a package is installed, its version and what it depends on:

python3 -m pip show iotcore

Remove it:

python3 -m pip uninstall iotcore

List everything in the current environment:

python3 -m pip list

Upgrade one package to the latest release (-U is the short form):

python3 -m pip install --upgrade iotcore
# or
python3 -m pip install -U iotcore

Snapshot the environment so another machine can reproduce it, then install from that snapshot:

python3 -m pip freeze > requirements.txt
python3 -m pip install -r requirements.txt

pip freeze pins versions, but it records only what is installed right now, with no record of which packages you asked for and which came along as dependencies. That is the gap Poetry fills.

Poetry: the everyday commands

Create a new project. Poetry scaffolds a package directory, a tests/ folder and a pyproject.toml:

poetry new poetry_demo

Add a dependency. This writes it to pyproject.toml, resolves the full dependency tree, pins it in poetry.lock and installs it:

poetry add arrow

Add a development-only dependency, such as a test runner, so it is not installed in production:

poetry add --group dev pytest

Show what is installed, as a tree so you can see which top-level package pulled in what:

poetry show --tree

Remove a package:

poetry remove arrow

Install everything from the lock file on a fresh machine or in CI. The --sync flag also removes anything in the environment that the lock file does not list:

poetry install --sync

Update dependencies within the ranges allowed by pyproject.toml and rewrite the lock file:

poetry update

Commit poetry.lock. It is the whole point.

Virtual environments in Poetry

Poetry creates and manages a virtual environment per project. You rarely need to think about it, but three commands cover the cases where you do.

Open a shell inside the environment:

poetry shell

Leave it the same way you leave any shell:

exit

Run a single command inside the environment without opening a shell, which is the right form for scripts and CI:

poetry run python project/script.py

If you prefer the environment to live inside the project folder, set it once and Poetry will create .venv/ there instead of in its cache directory:

poetry config virtualenvs.in-project true

Define your own commands

Poetry can register Python functions as command-line entry points, which replaces a pile of Makefile targets or shell scripts. Create a script, for example scripts/timer.py:

import time


def main():
    time.sleep(3)
    print("Timer expired")


if __name__ == "__main__":
    main()

Register it in pyproject.toml:

[tool.poetry.scripts]
timer = "scripts.timer:main"

Run it:

poetry run timer

When the package is installed with pip, the same entry becomes a real timer executable on the user’s path, which is how command-line tools distributed on PyPI are built.

Quick reference

Task pip Poetry
Install a package python3 -m pip install X poetry add X
Remove a package python3 -m pip uninstall X poetry remove X
List installed python3 -m pip list poetry show --tree
Upgrade python3 -m pip install -U X poetry update X
Reproduce an environment pip install -r requirements.txt poetry install --sync
Run inside the environment activate venv, then run poetry run ...

Summary

pip is the right tool for installing things into an environment you already have. Poetry is the right tool for owning a project: it keeps a lock file, separates development dependencies from runtime ones and turns functions into commands. Learn the handful of commands above and the choice stops being a debate.