Metadata-Version: 2.4
Name: bump-minimum-dependencies
Version: 0.2.0
Summary: Command line tool to bump minimum dependencies in pyproject.toml
Author: Nick Murphy
Author-email: Nick Murphy <namurphy@cfa.harvard.edu>
License-File: LICENSE
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: charset-normalizer==3.3.2
Requires-Dist: click>=8.4.2,<9
Requires-Dist: dep-logic>=0.7.1
Requires-Dist: pyproject-parser~=0.14
Requires-Dist: requests>=2.34.2
Requires-Dist: uv>=0.12.5
Requires-Python: >=3.13
Project-URL: Source, https://github.com/namurphy/bump-minimum-dependencies
Description-Content-Type: text/markdown

# bump-minimum-dependencies

Automatically bump the minimum allowed minor versions of Python package dependencies based on the time since first release, with a cooldown period.

## Motivation

Determining the minimum allowed version of a dependency requires balancing competing tradeoffs. ⚖️
Supporting older versions increases maintenance burden because of the need to support and test a wide range of versions, while also limiting developers from using newer features and assuming bugfixes.
When the range of allowed versions is too large, code can become more complicated to account for various contingencies.
Support windows that are too brief increase the risk of dependency conflicts and may cause problems for end users.
The developer maintenance burden is further increased when developers repeatedly discuss when to drop older versions of dependencies.

[SPEC 0] recommends that projects across the scientific pythoniverse adopt a common time-based policy for dropping support for older versions of dependencies.
SPEC 0 recommends core package dependencies be dropped 24 months after their initial minor release.
NumPy `v2.1.0` was released on 2024-08-18, so SPEC 0 recommends that packages drop support for `v2.1.*` of NumPy after 2026-08-18.

A limitation of SPEC 0 is that when a dependency goes more than 24 months between releases, a new release can immediately become the minimum supported version.
This limitation can be mitigated by providing a cooldown period so that new releases do not become the minimum supported version until a certain time period has passed (such as 12 months).

Because dependency updates have often needed to be performed manually (such as by looking up release times on the Python Package Index and editing `pyproject.toml` accordingly), a tool that automates these updates will save developer time, especially when accounting for edge cases.

## Usage

```groff
Usage: bump-minimum-dependencies [OPTIONS]

  Bump the minimum allowed minor versions of package dependencies.

  This tool updates pyproject.toml via `uv add --frozen` to drop support for
  minor versions of package dependencies based on the time since the minor
  version was first released, where package versions may be given by
  `<MAJOR>.<MINOR>` or `<MAJOR>.<MINOR>.<PATCH>`. Additional constraints such
  as upper limits are preserved.

  For example, if version `3.4.0` of a package dependency was released 25
  months ago and version `3.5.0` was released 23 months ago, running `bump-
  minimum-dependencies` will update the requirement from `>=3.4.0` to
  `>=3.5.0`.

  Requirements with markers or that cannot be updated will be skipped with a
  warning.

Options:
  --pyproject-file FILE          Path to pyproject.toml. Default is
                                 pyproject.toml in current directory.
  --drop-months FLOAT RANGE      Drop minor releases older than this many
                                 months ago. Defaults to 24.  [x>=0]
  --cooldown-months FLOAT RANGE  Ensure that there is at least one release
                                 this many months old, if possible. Defaults
                                 to 12 or the value provided to --drop-months,
                                 whichever is smaller.  [x>=0]
  --only-package TEXT            Name of a package to update. May be provided
                                 multiple times. When this option is used, all
                                 other packages will be skipped.
  --skip-package TEXT            Name of a package to skip when performing
                                 updates. May be provided multiple times.
  --extra TEXT                   Name of an optional dependencies category to
                                 update. May be provided multiple times.
  --all-extras                   If provided, all optional dependency
                                 categories will be updated.
  --group TEXT                   Name of a dependency group to update. May be
                                 provided multiple times.
  --all-groups                   If provided, all dependency groups will be
                                 updated.
  --skip-core                    If provided, core project dependencies will
                                 not be updated.
  --version                      Show the version and exit.
  --help                         Show this message and exit.
```

## Examples

To bump core package dependencies using default settings, run:

```shell
bump-minimum-dependencies
```

To bump only plasmapy, run:

```shell
bump-minimum-dependencies --only-package plasmapy
```

To skip updates for numpy and plasmapy, run:

```shell
bump-minimum-dependencies --skip-package numpy --skip-package plasmapy
```

To drop minor versions older than 36 months with a cooldown of 24 months, run:

```shell
bump-minimum-dependencies --drop-months 36 --cooldown-months 24
```

To bump all optional dependencies (extras), run:

```shell
bump-minimum-dependencies --all-extras
```

To bump all dependency groups, run:

```shell
bump-minimum-dependencies --all-groups
```

To bump the optional dependency (extras) category 'optionals' and
skip updates of core dependencies, run:

```shell
bump-minimum-dependencies --skip-core --extra optionals
```

To bump the dependency group named dev and core dependencies, run:

```shell
bump-minimum-dependencies --extra dev
```

## Usage notes

- Please review and test all updates to `pyproject.toml` before accepting them.

- This tool invokes `uv add --frozen` to update dependencies in `pyproject.toml` without updating lock files or syncing virtual environments.

- Using [`dep-logic`](https://github.com/pdm-project/dep-logic) allows bump-minimum-dependencies to handle a wide variety of requirements specifiers and perform logical operations to combine multiple requirements specifiers. For example, `>=4.1,<5` and `>=4.2` will be combined into `>=4.2,<5`.

- If the time-based requirement is mutually exclusive with the original requirement, the original requirement will be preserved.

- If a particular requirement cannot be updated, it will be skipped with a warning.

- Within a given category, dependencies with markers (such as `'setuptools; python_version > "3.11"'`) will not be updated.

- Requirements may be normalized upon updates by `uv add`. Opinionated autoformatters [pyproject-fmt](https://pyproject-fmt.readthedocs.io/en/latest/index.html) will reduce or eliminate the need for requirements normalization. Example normalizations include:

  - `.0` suffixes may be removed, since `X.Y` and `X.Y.0` "are not considered distinct release numbers" as per [PEP 440](https://peps.python.org/pep-0440).
  - Package names, which are case-insensitive, may be made lower case.
  - Single quotes may be changed to double quotes.
  - Changes to spacing, indentation, and line breaks.

## Limitations and caveats

- This tool may be unable to update certain dependencies that:

  - Do not follow a standard pattern (e.g., `<MAJOR>.<MINOR>`, `<MAJOR>.<MINOR>.<PATCH>`, or `<MAJOR>.<MINOR>.<PATCH>.<MICRO>`).
  - Have resulting requirements with multiple `!=` operators (as of `dep-logic==0.7.1`).
  - Do not have metadata in the expected form.
  - Are unavailable from the Python Package Index.

- This tool does _not_ guarantee that an environment can be created that includes the minimum allowed versions of all direct dependencies (such as when updates are skipped for a dependency without a minimum allowed version).

  - Run `uv lock --dry-run` to test that the requirements can produce a self-consistent environment.

  - Run `uv lock --resolution=lowest-direct --dry-run` to test that the minimum allowed versions of direct dependencies can produce a self-consistent environment.

- This tool does not update `build-system.requires`, as these updates cannot be performed with `uv add` as of `uv==0.12.5`.

- This tool does not check whether minimum allowed versions of dependencies have been yanked.

- If README and/or license files are declared in `pyproject.toml`, they must be present so that `pyproject.toml` can be loaded by [pyproject-parser.PyProject.load()](https://pyproject-parser.readthedocs.io/en/latest/api/pyproject-parser.html#pyproject_parser.PyProject.load).

- This tool does not upgrade the minimum required version of Python.

## Feature requests and bug reports

To make a feature request, please [raise an issue].

If you discover a bug, please [raise an issue] with a minimal reproducible example (i.e., the `pyproject.toml` file and the `bump-minimum-dependencies` command that was used).

## Related projects

- [scientific-python/spec0-action](https://github.com/scientific-python/spec0-action) — a GitHub action to create quarterly pull requests to perform SPEC 0 updates using a published drop schedule. Unlike `bump-minimum-dependencies`, this tool distinguishes between SPEC 0 core packages and other packages.

- [cgordberg/bump-dependencies](https://github.com/cgoldberg/bump-dependencies) — updates dependency specifiers in `pyproject.toml` to latest compatible versions.

- [hmaarrfk/nep29](https://github.com/hmaarrfk/nep29) — calculator tools for [NEP 29](https://github.com/hmaarrfk/nep29), a precursor to SPEC 0. `nep29` can be used to check the results of `bump-minimum-dependencies`, as in the following example (if uv is installed):

  ```shell
  uvx --python=3.14 --with=setuptools nep29 --n_minor=1 --n_months=12 scipy
  ```

[raise an issue]: https://github.com/namurphy/bump-minimum-dependencies/issues/new
[spec 0]: https://scientific-python.org/specs/spec-0000
