Skip to main content

Manage rolling minimum-supported versions (SPEC 0 style) for Python projects, as a CLI and GitHub Action.

Project description

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

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.

Recommended CI for floors

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dependency_support_policy-0.1.0.tar.gz (108.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dependency_support_policy-0.1.0-py3-none-any.whl (26.9 kB view details)

Uploaded Python 3

File details

Details for the file dependency_support_policy-0.1.0.tar.gz.

File metadata

  • Download URL: dependency_support_policy-0.1.0.tar.gz
  • Upload date:
  • Size: 108.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","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}

File hashes

Hashes for dependency_support_policy-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ab84eb282675834aa2d344fff443597e95df7e2436d084c479cef85446b29605
MD5 8d26a4ff6a721863b98212d3cb23720f
BLAKE2b-256 092698c07ef91f8fe87ed343b20b69645c4b7b5063957fbb6b98d73d5aed6940

See more details on using hashes here.

File details

Details for the file dependency_support_policy-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: dependency_support_policy-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 26.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","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}

File hashes

Hashes for dependency_support_policy-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1a49c86dc721d5f8d2e5380eb6c5276a38d54e3e13158ebd940a84f93092a5b4
MD5 c89650b79ed108457b3862e4e8b9b2c1
BLAKE2b-256 3405dce087379292b2dfd236fc8ba5c4df1b4f0c0be7df382364244770cf9ea1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page