Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 PATH Store a backup in this file.
  • --to [none|minimum] How to reset constraints.
    • none (default): remove all constraints
    • minimum: set constraints to the currently locked minimum, removing upper bounds
  • --lockfile PATH Where 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 PYPROJECT directory
  • --name FILTER Include/exclude constraints to edit by package name. [default: edit all]
  • --help Show 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
packageversion
annotated-types>=0.7.0
typing-extensions>=4
constraints in the edited project
packageversion
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:

packageversiongroup/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:

packageversiongroup/extra
annotated-types==0.6.*,>=0.6.1extra extra1
annotated-types~=0.6.1group group-b
merrily-ignored
ndrextra extra3
typing-extensions<4,>=3
typing-extensions~=3.4group group-a, group group-b

Current locked versions:

nameversion
annotated-types0.7.0
example0.2.0
typing-extensions4.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:

packageversiongroup/extra
annotated-types>=0.7.0extra extra1
annotated-types>=0.7.0group group-b
merrily-ignored
ndrextra extra3
typing-extensions>=4.14.1
typing-extensions>=4.14.1group 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:

packageversiongroup/extra
already-unconstrained*group poetry-a
typing-extensions^3.2
typing-extensions^3.4group poetry-a

Current locked versions:

nameversion
annotated-types0.7.0
example0.2.0
typing-extensions4.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:

packageversiongroup/extra
already-unconstrained*group poetry-a
typing-extensions>=4.14.1
typing-extensions>=4.14.1group 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:

packageversion
split0.1.0
typing-extensions3.10.0.2
typing-extensions4.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` |