Upgrade dependencies in pyproject.toml files with uv.
For end-users.
Note: For developers, see the dev section.
You need this for both usage and development.
https://docs.astral.sh/uv/getting-started/installation/
On Windows it can be better to use Git Bash terminal.
if ! command -v uv &> /dev/null; then
curl -LsSf https://astral.sh/uv/install.sh | sh;
else
uv self update;
fi
uv --versionRun it from any directory, except the project directory.
This will install or upgrade the tool.
if ! command -v uv-upx &> /dev/null; then
uv tool install uv-upx
else
uv tool upgrade uv-upx
fi
uv-upgrade --versionOr run advanced version with uvx:
uvx uv-upxDev installation: see here
uv tool list --show-pythonIf you need to remove the project with all data, run this command from the project directory:
uv tool uninstall uv-upxAfter installation, you can run the tool from any directory.
uv-upgradeor
uv-upx upgrade runIt is the same. But uv-upx provides more features.
You can run commands with the --help flag with more details.
Exported versions:
- for
uv-upgrade: - for
uv-upx:
This will install completion for the current shell. Available after restarting the shell.
- for
uv-upgrade:-
uv-upgrade --install-completion
-
- for
uv-upx:-
uv-upx --install-completion
-
Note: relatively safe to run multiple times. It just adds extra newlines to your shell config when run multiple times.
Run uv sync --all-groups --all-extras --all-packages --upgrade.
Get dependencies versions from uv.lock.
Put them in pyproject.toml files in related groups.
So, the main responsibility for dependencies resolution is on uv.
It works with workspaces. At least for some basic cases.
Respects:
- both
membersandexcludesections. - glob-based patterns.
For example:
TOMLKit->tomlkitPydantic->pydanticpyTEST_BenchMark->pytest-benchmark
Updates >= dependencies. Like bla>=2.0.0.
Because, in this case, we can simply put the new version instead of the old one.
Update the similar part of the constraint in the multi-constraint.
It doesn't touch pinned versions. Like bla==2.0.0.
It doesn't touch lower bounds. Like:
bla<=2.0.0bla~=2.0.0
It respects simple dependency ranges. Like bla>=1.0.0,<2.0.0.
It moves the lower bound to the new version.
In fact, it handles any part of the constraint with a supported operator.
It respects extras. Like bla[dev]>=1.0.0;python_version>="3.14".
It sets undefined lower bounds to the new version.
For example, before:
dependencies = [
"foo>=1.0.0",
"bla",
]After:
dependencies = [
"foo>=1.0.0",
"bla>=2.0.0",
]It skips unhandled and complex constraints. Like:
bla<1.0.0
It preserves comments in the pyproject.toml file. Like here:
dependencies = [
# Better classes and data validation
"pydantic>=2.12.5",
# TOML parser and writer with preserved formatting
"tomlkit>=0.13.3",
# CLI app framework
"typer>=0.20.0",
]If something goes wrong, it rolls back the changes to the pyproject.toml and uv.lock files.
If nothing from pyproject.toml was changed, it rolls back the changes to the uv.lock file.
So, only top-level dependencies changes trigger a uv.lock update.
This allows you to see all the top-level dependencies that have some special constraints. Like:
- ranges (
bla>=1.0.0,<2.0.0) - not defined bounds (
bla) - pinned dependencies (
bla==2.0.0) - unhandled constraints (
bla<1.0.0)
uv-upx helpers collect-top-level-dependencies-from-project --only-special-casesI needed this for my own projects.
I know these issues:
- Upgrade dependencies in pyproject.toml (uv upgrade)
- What is the intended workflow for updating dependencies with uv?
But I didn't see enough progress.
So, I implemented this tool for my own usage.
Maybe it will be useful for someone else.
Because it's a temporary Proof-of-Concept.
Maybe it will be replaced by Rust in the future.
It uses type annotations anyway. For simpler migration.