Skip to main content

dependency-support-policy-action

CI CodeQL Documentation pre-commit.ci status PyPI Version Python Versions License: BSD-3-Clause Ruff SPEC 0 — Minimum Supported Dependencies

Manage rolling minimum-supported versions for Python projects, as a standalone CLI and a GitHub Action.

The tool reads dependency constraints from pyproject.toml, evaluates a support policy — Scientific Python SPEC 0 is built in — against package release history, and raises dependency lower bounds and the requires-python floor accordingly. Everything else in your requirements (upper bounds, exclusions, extras, environment markers) and your TOML formatting/comments is preserved character-for-character. Existing minimums are never lowered.

How it works

The support-window model

For every managed package, releases are grouped into minor series (major.minor), each dated by its first stable release (prereleases, dev releases, and yanked files are ignored). A series is supported at a reference date if its first release falls within the support window — a number of calendar months looking back from the reference date, boundary inclusive. The policy floor is the first version of the oldest supported series. If every series is older than the window, the newest series is the floor, so at least one release line always remains supported. Series released after the reference date are ignored, which makes evaluation with an explicit --reference-date reproducible.

SPEC 0

The built-in spec0 policy implements Scientific Python SPEC 0 defaults:

  • Python: support window 36 months — requires-python is floored at the oldest CPython minor series released within 3 years.
  • Packages: support window 24 months.

Both windows, and per-package windows, are configurable (see below), so you can follow SPEC 0 strictly, or run "SPEC 0 with a 30-month window for numpy". The policy layer is extensible: additional named policies can be registered in dependency_support_policy.policies.

CLI usage

The CLI is published on PyPI as dependency-support-policy:

uvx dependency-support-policy check --reference-date 2026-07-01
uvx dependency-support-policy plan   # prints the machine-readable change plan (JSON)
uvx dependency-support-policy update --lock minimal

Modes:

Mode Writes files Exit codes
check never 0 compliant, 1 drift found, 2 error
plan never 0 (prints plan JSON to stdout), 2 error
update yes 0 success (even if no-op), 2 error

Common flags (all modes): --pyproject PATH, --reference-date YYYY-MM-DD, --policy spec0, --python-support-months N, --package-support-months N, --package-override NAME=MONTHS, --include/--exclude NAMES, --groups project,optional:docs,group:dev, --manage-python true|false, --lock off|minimal|upgrade, --output-json PATH, --quiet.

Configuration

Defaults live in pyproject.toml; CLI flags / action inputs override them.

[tool.dependency-support-policy]
policy = "spec0"
python-support-months = 36           # override the policy's Python window
package-support-months = 24          # override the policy's package window
groups = ["project"]                  # dependency collections to manage
include = []                          # if non-empty, only these packages
exclude = ["some-fast-moving-lib"]
manage-python = true
lock = "off"                          # off | minimal | upgrade

[tool.dependency-support-policy.package-support]
numpy = 30                            # per-package window, in months

[tool.dependency-support-policy.python-releases]
"3.15" = 2026-10-01                   # extend the built-in CPython table

Managed dependency collections (groups): project (project.dependencies), optional:<extra>, group:<dependency-group>, or the shorthands optional, group, and all.

GitHub Action

- uses: isaac-cf-wong/dependency-support-policy-action@v1
  id: policy
  with:
      mode: update # check | plan | update
      lock: minimal # off | minimal | upgrade

Inputs

All inputs are optional and default to empty, meaning "use the value from [tool.dependency-support-policy], or the policy default". The table shows the effective default after that resolution.

Input Effective default Description
mode check check, plan, or update.
working-directory . Directory containing the project.
pyproject pyproject.toml Path to pyproject.toml, relative to the directory.
reference-date today Evaluate windows as of this date (reproducible runs).
policy spec0 Support policy.
python-support-months policy default Python support window override.
package-support-months policy default Package support window override.
package-overrides — Newline-separated name=months per-package windows.
include / exclude — Comma-separated package names.
groups project Comma-separated dependency collections.
manage-python true Manage the requires-python floor.
lock off uv.lock regeneration mode.
fail-on-outdated true In check mode, fail the step when drift is detected.

Outputs

Output Description
changed true if any floor is below policy (check/plan) or was updated.
python-floor-changed true if requires-python changed (or would change).
dependency-floors-changed JSON list of {name, group, old, new} floor changes.
files-changed JSON list of files written (update mode).
plan Full machine-readable change plan (JSON).

Permissions

The action itself only edits files in the workspace — it needs no secrets and works with the default contents: read. Workflows that push a branch and open a PR (see the examples) need contents: write and pull-requests: write for the create-pull-request step, and PR creation by Actions must be allowed in the repository settings (Settings → Actions → General → Allow GitHub Actions to create and approve pull requests).

Example workflows

Ready-to-copy workflows live in examples/workflows/:

pre-commit hook

The CLI is also published as a pre-commit hook. Add it to .pre-commit-config.yaml:

- repo: https://github.com/isaac-cf-wong/dependency-support-policy-action
  rev: v0.1.1 # pin a tag; `pre-commit autoupdate` bumps it
  hooks:
      - id: dependency-support-policy

Two hook ids are available:

Hook id Mode Behaviour
dependency-support-policy check Fails the commit if floors drifted below the policy
dependency-support-policy-update update Rewrites pyproject.toml to the current floors

Both trigger on changes to any pyproject.toml and run once at the repo root (pass_filenames: false). Pass CLI flags via args: — for example, to target a nested project or pin a reference date:

hooks:
    - id: dependency-support-policy
      args:
          [
              --pyproject,
              packages/foo/pyproject.toml,
              --reference-date,
              '2026-07-01',
          ]

Note: the hook resolves CPython and package release dates, so it needs network access when it runs. In offline or air-gapped environments prefer the GitHub Action, or pin --reference-date and extend the built-in tables via [tool.dependency-support-policy.python-releases].

uv.lock handling

With lock: minimal (recommended), uv lock re-locks after the pyproject edit — uv only changes what the new floors require. With lock: upgrade, uv lock --upgrade refreshes everything (usually better left to Renovate's lockfile maintenance). If regeneration fails, both pyproject.toml and uv.lock are rolled back to their previous contents and the run fails; if no uv.lock exists, regeneration is skipped with a note. uv must be on PATH for the CLI (the action installs it).

Coexisting with Renovate

Renovate and this action own different halves of the problem — keep both:

Concern Owner
New upstream releases (bump upper ranges, lockfile) Renovate
GitHub Actions, Docker, pre-commit, dev-tool updates Renovate
Lockfile maintenance Renovate
Rolling lower-bound policy (SPEC 0 support windows) this action
requires-python floor this action

Renovate does not implement time-based minimum-version policies; this action never touches upper bounds or unmanaged ecosystems. To avoid Renovate "fixing" your floors back, keep rangeStrategy at "bump" (raises upper constraints) or "replace" — not "widen" — for pep621. The PRs this action opens (via create-pull-request) use a dedicated branch (dependency-support-policy/update), which Renovate ignores.

A floor is only honest if you test it. Recommended matrix:

  • Minimum versions: uv sync --resolution lowest-direct then run tests — proves the floors actually work.
  • Latest versions: uv sync --upgrade (or Renovate-maintained lockfile) — proves you're compatible with current releases.

Known limitations

  • Only PEP 508 requirement strings in project.dependencies, project.optional-dependencies, and [dependency-groups] are managed; tool.uv.sources, path/URL dependencies, and non-PyPI indexes are not.
  • Pinned requirements (==, ===, ~=) are reported and skipped, never rewritten.
  • A policy floor that conflicts with an existing upper bound or exclusion is reported and skipped — resolve the conflict manually.
  • Release metadata comes from the PyPI JSON API; private registries are not supported yet (registry failures abort the run with exit code 2).
  • Trove classifiers (Programming Language :: Python :: 3.x) are not updated when the Python floor moves.
  • The CPython release table is built in; extend it via [tool.dependency-support-policy.python-releases] when new series ship.

Development

uv sync --all-groups
uv run prek run --all-files
uv run pytest
uv run mypy src
uv build

See CONTRIBUTING.md. Released under the BSD 3-Clause License.

Metadata

Release files for dependency-support-policy 0.2.9

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dependency-support-policy 0.2.9
File Size Uploaded
dependency_support_policy-0.2.9.tar.gz 131.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dependency-support-policy 0.2.9
File Interpreter ABI Platform
dependency_support_policy-0.2.9-py3-none-any.whl Python 3 none any Details

Total release size: 159.2 kB

Release files / dependency_support_policy-0.2.9.tar.gz

Download URL dependency_support_policy-0.2.9.tar.gz
Size 131.9 kB
Tags Source
SHA-256 checksum
How to use checksums
66ab29c9564e493de3611a0789e98558911d51d73e35dd33eaf22b59ba324f3c
BLAKE2b-256 checksum
How to use checksums
be0a7550485698e144633a3a5d3665c65cf151e91b26b3cbe43a45a76e03e3ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / dependency_support_policy-0.2.9-py3-none-any.whl

Download URL dependency_support_policy-0.2.9-py3-none-any.whl
Size 27.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0b359e8c46a442a9bc432fed777c607508f8377af63367fcdfe2c06e35add0c0
BLAKE2b-256 checksum
How to use checksums
44c8314604f6888ff2aaf4032c1584916fe297728ce17183432f36fd4f978a3c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.2.13

2 release files

0.2.11

2 release files

0.2.10

2 release files

This release

0.2.9 This release

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page