ganzua constraints reset
Usage: ganzua constraints reset [OPTIONS] [PYPROJECT]
Remove or relax any dependency version constraints from the pyproject.toml.
This can be useful for allowing uv/Poetry to update to the most recent versions, ignoring the previous constraints. Approximate recipe:
ganzua constraints reset --to=minimum --backup=pyproject.toml.bak
uv lock --upgrade # perform the upgrade
mv pyproject.toml.bak pyproject.toml # restore old constraints
ganzua constraints bump
uv lock
The PYPROJECT argument should point to a pyproject.toml file,
or to a directory containing such a file.
If this argument is not specified,
the one in the current working directory will be used.
Options:
--backup PATHStore a backup in this file.--to [none|minimum]How to reset constraints.none(default): remove all constraintsminimum: set constraints to the currently locked minimum, removing upper bounds
--lockfile PATHWhere to load current versions from (for--to=minimum). Inferred if possible.- file: use the path as the lockfile
- directory: use the lockfile in that directory
- default: use the lockfile in the
PYPROJECTdirectory
--name FILTERInclude/exclude constraints to edit by package name. [default: edit all]--helpShow this help message and exit.
Examples
Removing constraints
By default, ganzua constraints reset will remove all version constraints.
This is useful when we want poetry lock/uv lock to compute a completely unconstrainted, up-to-date dependency solution.
Let's set up an example with a pyproject.toml file.
$ cp $CORPUS/new-uv-project/pyproject.toml $EXAMPLE/pyproject.toml
$ cat $EXAMPLE/pyproject.toml
[project]
name = "example"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"annotated-types>=0.7.0",
"typing-extensions>=4",
]
We can now reset the constraints and create a backup:
$ ganzua constraints reset $EXAMPLE --backup=$EXAMPLE/old.pyproject.toml
$ ls $EXAMPLE
old.pyproject.toml
pyproject.toml
This edits the pyproject.toml file.
All dependencies are still present, but they no longer constrain any versions:
$ cat $EXAMPLE/pyproject.toml
[project]
name = "example"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"annotated-types",
"typing-extensions",
]
We can more directly compare the changes to the constriants via ganzua constraints inspect:
constraints in the backup
| package | version |
|---|---|
| annotated-types | >=0.7.0 |
| typing-extensions | >=4 |
constraints in the edited project
| package | version |
|---|---|
| annotated-types | |
| typing-extensions |
Removing constraints in extras and dependency groups
The ganzua constraints reset tool will also look into [project.optional-dependencies] and dependency-groups.
Let's set up a new example with a more complicated pyproject.toml file.
$ cp $CORPUS/constraints-uv-pyproject.toml $EXAMPLE/pyproject.toml
$ cat $EXAMPLE/pyproject.toml
[project]
name = "example"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"Typing.Extensions>=3,<4", # moar type annotations
"merrily-ignored",
[42, "also ignored"], # we ignore invalid junk
]
[project.optional-dependencies]
extra1 = [
"annotated-types >=0.6.1, ==0.6.*",
]
extra2 = false # known invalid
extra3 = ["ndr"]
[dependency-groups]
group-a = ["typing-extensions ~=3.4"]
group-b = [{include-group = "group-a"}, "annotated-types ~=0.6.1"]
Note that the file contains an invalid structure, such as an array where the schema would expect a string.
Running the reset succeeds. Any errors in the file are ignored silently.
$ ganzua constraints reset $EXAMPLE
The resulting pyproject.toml file is stripped of all dependency version constraints.
$ cat $EXAMPLE/pyproject.toml
[project]
name = "example"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"Typing.Extensions", # moar type annotations
"merrily-ignored",
[42, "also ignored"], # we ignore invalid junk
]
[project.optional-dependencies]
extra1 = [
"annotated-types",
]
extra2 = false # known invalid
extra3 = ["ndr"]
[dependency-groups]
group-a = ["typing-extensions"]
group-b = [{include-group = "group-a"}, "annotated-types"]
Removing constraints for Poetry
When using Poetry with dependencies in the [tool.poetry] table,
resetting a constraint will change it to *.
Let's set up a new example. This example file also demonstrates Poetry dependency groups.
$ cp $CORPUS/constraints-poetry-pyproject.toml $EXAMPLE/pyproject.toml
$ cat $EXAMPLE/pyproject.toml
[tool.poetry.dependencies]
Typing_Extensions = "^3.2"
ignored-garbage = { not-a-version = true }
[build-system]
[tool.poetry.group.poetry-a.dependencies]
typing-extensions = { version = "^3.4" }
already-unconstrained = "*"
We can now reset the constraints:
$ ganzua constraints reset $EXAMPLE
The versions will now be set to *, including for dependencies in groups:
| package | version | group/extra |
|---|---|---|
| already-unconstrained | * | group poetry-a |
| typing-extensions | * | |
| typing-extensions | * | group poetry-a |
$ cat $EXAMPLE/pyproject.toml
[tool.poetry.dependencies]
Typing_Extensions = "*"
ignored-garbage = { not-a-version = true }
[build-system]
[tool.poetry.group.poetry-a.dependencies]
typing-extensions = { version = "*" }
already-unconstrained = "*"
Resetting constraints to minimum
If we want to upgrade dependencies in a project, it's usually desirable to prevent unexpected downgrades.
Ganzua can assist here with the --to=minimum option.
Instead of removing all version constraints, we rewrite the constraints to use the currently locked version as a lower bound.
Let's set up an example using UV:
$ cp $CORPUS/constraints-uv-pyproject.toml $EXAMPLE/pyproject.toml
Current constraints:
| package | version | group/extra |
|---|---|---|
| annotated-types | ==0.6.*,>=0.6.1 | extra extra1 |
| annotated-types | ~=0.6.1 | group group-b |
| merrily-ignored | ||
| ndr | extra extra3 | |
| typing-extensions | <4,>=3 | |
| typing-extensions | ~=3.4 | group group-a, group group-b |
Current locked versions:
| name | version |
|---|---|
| annotated-types | 0.7.0 |
| example | 0.2.0 |
| typing-extensions | 4.14.1 |
Now let's reset the constraints:
$ ganzua constraints reset --to=minimum $EXAMPLE
The constraints in the pyproject.toml file have been reset to a lower bound with the locked version:
| package | version | group/extra |
|---|---|---|
| annotated-types | >=0.7.0 | extra extra1 |
| annotated-types | >=0.7.0 | group group-b |
| merrily-ignored | ||
| ndr | extra extra3 | |
| typing-extensions | >=4.14.1 | |
| typing-extensions | >=4.14.1 | group group-a, group group-b |
$ cat $EXAMPLE/pyproject.toml
[project]
name = "example"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"Typing.Extensions>=4.14.1", # moar type annotations
"merrily-ignored",
[42, "also ignored"], # we ignore invalid junk
]
[project.optional-dependencies]
extra1 = [
"annotated-types>=0.7.0",
]
extra2 = false # known invalid
extra3 = ["ndr"]
[dependency-groups]
group-a = ["typing-extensions>=4.14.1"]
group-b = [{include-group = "group-a"}, "annotated-types>=0.7.0"]
We can do the same using Poetry:
$ cp $CORPUS/constraints-poetry-pyproject.toml $EXAMPLE/pyproject.toml
Current constraints:
| package | version | group/extra |
|---|---|---|
| already-unconstrained | * | group poetry-a |
| typing-extensions | ^3.2 | |
| typing-extensions | ^3.4 | group poetry-a |
Current locked versions:
| name | version |
|---|---|
| annotated-types | 0.7.0 |
| example | 0.2.0 |
| typing-extensions | 4.14.1 |
Now let's reset the constraints:
$ ganzua constraints reset --to=minimum $EXAMPLE
The constraints in the pyproject.toml file have been reset to a lower bound with the locked version:
| package | version | group/extra |
|---|---|---|
| already-unconstrained | * | group poetry-a |
| typing-extensions | >=4.14.1 | |
| typing-extensions | >=4.14.1 | group poetry-a |
Resetting to minimum with split versions
If a project has split versions for a package, all requirements will be reset to the minimum of all candidate versions.
This is not entirely correct and might break subsequent package resolution, because markers/extras/groups are not currently taken into account. It can also lead to implicit downgrades.
The exact behavior here is not considered stable and might change in the future, as ways are found to resolve these problems.
Let's look at an example project with split version:
$ cp $CORPUS/split/pyproject.toml $EXAMPLE/pyproject.toml
$ cp $CORPUS/split/uv.lock $EXAMPLE/uv.lock
Current pyproject.toml file:
$ cat $EXAMPLE/pyproject.toml
[project]
name = "split"
version = "0.1.0"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"typing_extensions >=4 ; python_version >= '3.14'",
"typing_extensions >=3,<4 ; python_version < '3.14'",
]
Currently locked versions:
| package | version |
|---|---|
| split | 0.1.0 |
| typing-extensions | 3.10.0.2 |
| typing-extensions | 4.15.0 |
Now we reset their constraints to the minimum, which will show a warning about the potential conflict:
$ ganzua constraints reset --to=minimum $EXAMPLE
ganzua: package `typing-extensions` has multiple candidate versions: 3.10.0.2, 4.15.0
Constraints afterwards:
$ cat $EXAMPLE/pyproject.toml
[project]
name = "split"
version = "0.1.0"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"typing_extensions>=3.10.0.2; python_version >= \"3.14\"",
"typing_extensions>=3.10.0.2; python_version < \"3.14\"",
]
same for Poetry
Set up a fresh example:
$ cp $CORPUS/split/pyproject.toml $EXAMPLE/pyproject.toml
$ cp $CORPUS/split/poetry.lock $EXAMPLE/poetry.lock
Run Ganzua, which will again emit a warning:
$ ganzua constraints reset --to=minimum $EXAMPLE
ganzua: package `typing-extensions` has multiple candidate versions: 3.10.0.2, 4.15.0
Constraints afterwards:
$ cat $EXAMPLE/pyproject.toml
[project]
name = "split"
version = "0.1.0"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"typing_extensions>=3.10.0.2; python_version >= \"3.14\"",
"typing_extensions>=3.10.0.2; python_version < \"3.14\"",
]
Resolving the minimum version requires a lockfile
When we try to reset versions to their minimum but the project doesn't have a lockfile, then we get an error.
$ cp $CORPUS/new-poetry-project/pyproject.toml $EXAMPLE/pyproject.toml
$ ganzua constraints reset --to=minimum $EXAMPLE
Usage: ganzua constraints reset [OPTIONS] [PYPROJECT]
Try 'ganzua constraints reset --help' for help.
Error: Could not infer `--lockfile` for `${EXAMPLE}`.
Note: Using `--to=minimum` requires a `--lockfile`.
[command exited with status 2]
But this succeeds when passing an explicit lockfile, or to a directory containing a lockfile:
$ ganzua constraints reset --to=minimum --lockfile=$CORPUS/new-uv-project/uv.lock $EXAMPLE
$ ganzua constraints reset --to=minimum --lockfile=$CORPUS/new-uv-project $EXAMPLE
This also works if the lockfile can be inferred from the pyproject.toml file.
$ cp $CORPUS/new-uv-project/uv.lock $EXAMPLE/uv.lock
$ ganzua constraints reset --to=minimum $EXAMPLE
Inferring pyproject.toml location
Let's consider an empty example project:
$ ls $EXAMPLE
Running Ganzua within this directory will fail, as there's no pyproject.toml file:
$ env -C $EXAMPLE ganzua constraints reset
Usage: ganzua constraints reset [OPTIONS] [PYPROJECT]
Try 'ganzua constraints reset --help' for help.
Error: Did not find default `pyproject.toml`.
[command exited with status 2]
Once we add a pyproject.toml, it will be picked up implicitly,
and all oft he below Ganzua commands are equivalent.
$ cp $CORPUS/old-uv-project/pyproject.toml $EXAMPLE/pyproject.toml
$ env -C $EXAMPLE ganzua constraints reset
$ env -C $EXAMPLE ganzua constraints reset pyproject.toml
$ env -C $EXAMPLE ganzua constraints reset .
$ ganzua constraints reset $EXAMPLE/pyproject.toml
$ ganzua constraints reset $EXAMPLE
That is, we can specify a directory or a file path, and omit this argument entirely if we want to act on the project in the current working directory.
Filters
Can use filters to only reset certain constraints. Read the filter manual for further details on how filters work.
Added in Ganzua 0.4.0: --name filters.
Let's set up a fresh example project.
$ cp $CORPUS/constraints-uv-pyproject.toml $EXAMPLE/pyproject.toml
We can look at the current constraints:
$ ganzua constraints inspect $EXAMPLE --format=markdown
| package | version | group/extra |
|-------------------|-----------------|----------------------------------|
| annotated-types | ==0.6.*,>=0.6.1 | extra `extra1` |
| annotated-types | ~=0.6.1 | group `group-b` |
| merrily-ignored | | |
| ndr | | extra `extra3` |
| typing-extensions | <4,>=3 | |
| typing-extensions | ~=3.4 | group `group-a`, group `group-b` |
We can use the --name filter to only reset the Typing-Extensions versions:
$ ganzua constraints reset $EXAMPLE --name typing-extensions
In the updated constraints, we see that the version numbers have been removed, but not for other dependencies:
$ ganzua constraints inspect $EXAMPLE --format=markdown
| package | version | group/extra |
|-------------------|-----------------|----------------------------------|
| annotated-types | ==0.6.*,>=0.6.1 | extra `extra1` |
| annotated-types | ~=0.6.1 | group `group-b` |
| merrily-ignored | | |
| ndr | | extra `extra3` |
| typing-extensions | | |
| typing-extensions | | group `group-a`, group `group-b` |