diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 31b016de..579b95d5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,8 +2,6 @@ version: 2 updates: - package-ecosystem: pip directory: "/" - exclude-paths: - - "requirements/**" schedule: interval: daily open-pull-requests-limit: 10 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f76de72..eafc3138 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,16 +20,13 @@ jobs: python-version: "3.x" - name: Cache pip packages uses: actions/cache@v5 - env: - cache-name: cache-pypi-modules with: - # pip cache files are stored in `~/.cache/pip` on Linux path: ~/.cache/pip - key: ${{ runner.os }}-pydocstyle-${{ env.cache-name }}-${{ hashFiles('pyproject.toml', 'requirements/production.in', 'requirements/testing.in', 'requirements/production.txt', 'requirements/testing.txt') }} + key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} restore-keys: | - ${{ runner.os }}-pydocstyle-${{ env.cache-name }}- + ${{ runner.os }}-pip- - name: Install dependencies - run: pip install -r requirements/testing.txt + run: pip install -e .[dev] - name: Pydocstyle run: pydocstyle pyvlx test/*.py examples/*.py flake8: @@ -42,16 +39,13 @@ jobs: python-version: "3.x" - name: Cache pip packages uses: actions/cache@v5 - env: - cache-name: cache-pypi-modules with: - # pip cache files are stored in `~/.cache/pip` on Linux path: ~/.cache/pip - key: ${{ runner.os }}-flake8-${{ env.cache-name }}-${{ hashFiles('pyproject.toml', 'requirements/production.in', 'requirements/testing.in', 'requirements/production.txt', 'requirements/testing.txt') }} + key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} restore-keys: | - ${{ runner.os }}-flake8-${{ env.cache-name }}- + ${{ runner.os }}-pip- - name: Install dependencies - run: pip install -r requirements/testing.txt + run: pip install -e .[dev] - name: Flake8 run: flake8 pylint: @@ -64,16 +58,13 @@ jobs: python-version: "3.x" - name: Cache pip packages uses: actions/cache@v5 - env: - cache-name: cache-pypi-modules with: - # pip cache files are stored in `~/.cache/pip` on Linux path: ~/.cache/pip - key: ${{ runner.os }}-pylint-${{ env.cache-name }}-${{ hashFiles('pyproject.toml', 'requirements/production.in', 'requirements/testing.in', 'requirements/production.txt', 'requirements/testing.txt') }} + key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} restore-keys: | - ${{ runner.os }}-pylint-${{ env.cache-name }}- + ${{ runner.os }}-pip- - name: Install dependencies - run: pip install -r requirements/testing.txt + run: pip install -e .[dev] - name: Linter Pylint run: pylint pyvlx test/*.py examples/*.py isort: @@ -86,16 +77,13 @@ jobs: python-version: "3.x" - name: Cache pip packages uses: actions/cache@v5 - env: - cache-name: cache-pypi-modules with: - # pip cache files are stored in `~/.cache/pip` on Linux path: ~/.cache/pip - key: ${{ runner.os }}-isort-${{ env.cache-name }}-${{ hashFiles('pyproject.toml', 'requirements/production.in', 'requirements/testing.in', 'requirements/production.txt', 'requirements/testing.txt') }} + key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} restore-keys: | - ${{ runner.os }}-isort-${{ env.cache-name }}- + ${{ runner.os }}-pip- - name: Install dependencies - run: pip install -r requirements/testing.txt + run: pip install -e .[dev] - name: Isort run: isort --check-only test examples pyvlx mypy: @@ -111,16 +99,13 @@ jobs: python-version: ${{ matrix.python-version }} - name: Cache pip packages uses: actions/cache@v5 - env: - cache-name: cache-pypi-modules with: - # pip cache files are stored in `~/.cache/pip` on Linux path: ~/.cache/pip - key: ${{ runner.os }}-mypy-${{ env.cache-name }}-${{ hashFiles('pyproject.toml', 'requirements/production.in', 'requirements/testing.in', 'requirements/production.txt', 'requirements/testing.txt') }} + key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} restore-keys: | - ${{ runner.os }}-mypy-${{ env.cache-name }}- + ${{ runner.os }}-pip- - name: Install dependencies - run: pip install -r requirements/testing.txt + run: pip install -e .[dev] - name: Mypy run: mypy pyvlx pytest: @@ -136,16 +121,13 @@ jobs: python-version: ${{ matrix.python-version }} - name: Cache pip packages uses: actions/cache@v5 - env: - cache-name: cache-pypi-modules with: - # pip cache files are stored in `~/.cache/pip` on Linux path: ~/.cache/pip - key: ${{ runner.os }}-pytest-${{ env.cache-name }}-${{ hashFiles('pyproject.toml', 'requirements/production.in', 'requirements/testing.in', 'requirements/production.txt', 'requirements/testing.txt') }} + key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} restore-keys: | - ${{ runner.os }}-pytest-${{ env.cache-name }}- + ${{ runner.os }}-pip- - name: Install dependencies - run: pip install -r requirements/testing.txt + run: pip install -e .[dev] - name: pytest # run the tests, produce a .coverage.$pyversion file run: pytest --cov diff --git a/.github/workflows/dependabot-refresh-requirements.yml b/.github/workflows/dependabot-refresh-requirements.yml index 01fba609..f1a87119 100644 --- a/.github/workflows/dependabot-refresh-requirements.yml +++ b/.github/workflows/dependabot-refresh-requirements.yml @@ -28,7 +28,7 @@ jobs: python-version: "3.x" - name: Install uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@v7 - name: Regenerate requirements run: | diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 09181987..502a12d1 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -7,8 +7,7 @@ This document describes local checks, dependency management, and release-related Install development dependencies: ```bash -# Fully locked test/lint environment (including package install) -pip install -r requirements/testing.txt +pip install -e .[dev] ``` Run the full local check suite: @@ -36,49 +35,21 @@ make coverage ## Dependency model -- `pyproject.toml` is the **single source of truth** for all dependency declarations: - - `project.dependencies` — runtime requirements with capped major versions (`>=X.Y,<(X+1).0`), keeping the library flexible for consumers. - - `project.optional-dependencies.test`, `.lint`, `.release` — dev/CI dependencies pinned to exact versions (`==X.Y.Z`) so builds are reproducible and Dependabot can detect and propose updates. -- `requirements/*.in` describe locked environment inputs for `uv pip compile`. -- `requirements/*.txt` are fully resolved lock files (including transitive dependencies) for reproducible installs in CI and local development. -- Generated requirements files are committed. +`pyproject.toml` is the single source of truth for all dependency declarations: -## Requirements handling - -Regenerate lock files after dependency changes in `pyproject.toml` or updates to `requirements/*.in`: - -```bash -make requirements -``` - -PR checklist: - -- If `pyproject.toml` dependency versions changed, run `make requirements` and commit updated `requirements/*.txt` in the same PR. -- If `requirements/*.in` changed, run `make requirements` and commit updated `requirements/*.txt` in the same PR. -- If dependencies did not change, do not modify `requirements/*.txt`. -- For Dependabot PRs, this is handled automatically by the refresh workflow, see below. - -Equivalent direct commands: - -```bash -python3 -m pip install uv -uv pip compile --strip-extras requirements/production.in --output-file requirements/production.txt -uv pip compile --strip-extras requirements/testing.in --output-file requirements/testing.txt -uv pip compile --strip-extras requirements/release.in --output-file requirements/release.txt -``` +- **Runtime deps** (`project.dependencies`) use `>=X.Y,<(X+1).0` — flexible for library consumers, capped at the next major version to prevent surprise breakage. +- **Dev deps** (`project.optional-dependencies.dev`, `.release`) are pinned to exact versions (`==X.Y.Z`) so CI builds are reproducible and Dependabot can detect and propose updates. ### How Dependabot updates work 1. Dependabot monitors `pyproject.toml` for outdated `==` pins and creates a PR bumping them. -2. The `dependabot-refresh-requirements` workflow auto-triggers on the PR, regenerates `requirements/*.txt` lock files via `uv pip compile`, and pushes the updated files. -3. CI runs against the fully locked environment. You review and merge. +2. CI runs against the updated pins. You review and merge. ## CI vs manual operations | Task | Normally handled by CI | Manual equivalent | |---|---|---| | Run linting and tests | `.github/workflows/ci.yml` | `make ci` | -| Regenerate requirements for Dependabot pip PRs | `.github/workflows/dependabot-refresh-requirements.yml` | `make requirements` | | Build distributions | `.github/workflows/publish.yml` | `make build` | | Publish distributions | `.github/workflows/publish.yml` via `pypa/gh-action-pypi-publish` | `make pypi` | diff --git a/Makefile b/Makefile index 3168f854..e9e79b90 100644 --- a/Makefile +++ b/Makefile @@ -21,8 +21,6 @@ all: @echo "" @echo "build -- build python package" @echo "" - @echo "requirements -- generate requirements/*.txt from requirements/*.in" - @echo "" @echo "pypi -- upload package to pypi" @echo "" @@ -57,10 +55,4 @@ pydocstyle: coverage: pytest --cov --cov-report html --verbose -requirements: - @python3 -m pip install uv - @python3 -m uv pip compile --strip-extras requirements/production.in --output-file requirements/production.txt - @python3 -m uv pip compile --strip-extras requirements/testing.in --output-file requirements/testing.txt - @python3 -m uv pip compile --strip-extras requirements/release.in --output-file requirements/release.txt - -.PHONY: test build requirements +.PHONY: test build diff --git a/pyproject.toml b/pyproject.toml index 79811d32..d5c89f86 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,14 +27,12 @@ dependencies = [ ] [project.optional-dependencies] -test = [ +dev = [ "pytest==9.0.2", "pytest-cov==7.0.0", "mypy==1.19.1", "types-PyYAML==6.0.12.20250915", "types-Deprecated==1.3.1.20260130", -] -lint = [ "isort==7.0.0", "flake8==7.3.0", "flake8-isort==7.0.0", diff --git a/requirements/production.in b/requirements/production.in deleted file mode 100644 index ecf975e2..00000000 --- a/requirements/production.in +++ /dev/null @@ -1 +0,0 @@ --e . \ No newline at end of file diff --git a/requirements/production.txt b/requirements/production.txt deleted file mode 100644 index 3c64d0ba..00000000 --- a/requirements/production.txt +++ /dev/null @@ -1,14 +0,0 @@ -# This file was autogenerated by uv via the following command: -# uv pip compile --strip-extras requirements/production.in --output-file requirements/production.txt --e . - # via -r requirements/production.in -deprecated==1.3.1 - # via pyvlx -ifaddr==0.2.0 - # via zeroconf -pyyaml==6.0.3 - # via pyvlx -wrapt==2.1.1 - # via deprecated -zeroconf==0.148.0 - # via pyvlx diff --git a/requirements/release.in b/requirements/release.in deleted file mode 100644 index 729e82f0..00000000 --- a/requirements/release.in +++ /dev/null @@ -1,2 +0,0 @@ --r production.txt --e .[release] \ No newline at end of file diff --git a/requirements/release.txt b/requirements/release.txt deleted file mode 100644 index d45e872d..00000000 --- a/requirements/release.txt +++ /dev/null @@ -1,85 +0,0 @@ -# This file was autogenerated by uv via the following command: -# uv pip compile --strip-extras requirements/release.in --output-file requirements/release.txt --e . - # via - # -r requirements/production.txt - # -r requirements/release.in -build==1.4.0 - # via pyvlx -certifi==2026.1.4 - # via requests -charset-normalizer==3.4.4 - # via requests -deprecated==1.3.1 - # via - # -r requirements/production.txt - # pyvlx -docutils==0.22.4 - # via readme-renderer -id==1.6.1 - # via twine -idna==3.11 - # via requests -ifaddr==0.2.0 - # via - # -r requirements/production.txt - # zeroconf -jaraco-classes==3.4.0 - # via keyring -jaraco-context==6.1.0 - # via keyring -jaraco-functools==4.4.0 - # via keyring -keyring==25.7.0 - # via twine -markdown-it-py==4.0.0 - # via rich -mdurl==0.1.2 - # via markdown-it-py -more-itertools==10.8.0 - # via - # jaraco-classes - # jaraco-functools -nh3==0.3.3 - # via readme-renderer -packaging==26.0 - # via - # build - # twine -pygments==2.19.2 - # via - # readme-renderer - # rich -pyproject-hooks==1.2.0 - # via build -pyyaml==6.0.3 - # via - # -r requirements/production.txt - # pyvlx -readme-renderer==44.0 - # via twine -requests==2.32.5 - # via - # requests-toolbelt - # twine -requests-toolbelt==1.0.0 - # via twine -rfc3986==2.0.0 - # via twine -rich==14.3.3 - # via twine -twine==6.2.0 - # via pyvlx -urllib3==2.6.3 - # via - # id - # requests - # twine -wrapt==2.1.1 - # via - # -r requirements/production.txt - # deprecated -zeroconf==0.148.0 - # via - # -r requirements/production.txt - # pyvlx diff --git a/requirements/testing.in b/requirements/testing.in deleted file mode 100644 index db8e557e..00000000 --- a/requirements/testing.in +++ /dev/null @@ -1,2 +0,0 @@ --r production.txt --e .[test,lint] \ No newline at end of file diff --git a/requirements/testing.txt b/requirements/testing.txt deleted file mode 100644 index fb3d7124..00000000 --- a/requirements/testing.txt +++ /dev/null @@ -1,94 +0,0 @@ -# This file was autogenerated by uv via the following command: -# uv pip compile --strip-extras requirements/testing.in --output-file requirements/testing.txt --e . - # via - # -r requirements/production.txt - # -r requirements/testing.in -astroid==4.0.4 - # via pylint -coverage==7.13.4 - # via pytest-cov -deprecated==1.3.1 - # via - # -r requirements/production.txt - # pyvlx -dill==0.4.1 - # via pylint -flake8==7.3.0 - # via - # flake8-isort - # flake8-pyproject - # pyvlx -flake8-isort==7.0.0 - # via pyvlx -flake8-pyproject==1.2.4 - # via pyvlx -ifaddr==0.2.0 - # via - # -r requirements/production.txt - # zeroconf -iniconfig==2.3.0 - # via pytest -isort==7.0.0 - # via - # flake8-isort - # pylint - # pyvlx -librt==0.8.1 - # via mypy -mccabe==0.7.0 - # via - # flake8 - # pylint -mypy==1.19.1 - # via pyvlx -mypy-extensions==1.1.0 - # via mypy -packaging==26.0 - # via pytest -pathspec==1.0.4 - # via mypy -platformdirs==4.9.2 - # via pylint -pluggy==1.6.0 - # via - # pytest - # pytest-cov -pycodestyle==2.14.0 - # via flake8 -pydocstyle==6.3.0 - # via pyvlx -pyflakes==3.4.0 - # via flake8 -pygments==2.19.2 - # via pytest -pylint==4.0.3 - # via pyvlx -pytest==9.0.2 - # via - # pytest-cov - # pyvlx -pytest-cov==7.0.0 - # via pyvlx -pyyaml==6.0.3 - # via - # -r requirements/production.txt - # pyvlx -snowballstemmer==3.0.1 - # via pydocstyle -tomlkit==0.14.0 - # via pylint -types-deprecated==1.3.1.20260130 - # via pyvlx -types-pyyaml==6.0.12.20250915 - # via pyvlx -typing-extensions==4.15.0 - # via mypy -wrapt==2.1.1 - # via - # -r requirements/production.txt - # deprecated -zeroconf==0.148.0 - # via - # -r requirements/production.txt - # pyvlx