From b724f3a28c30b595abd9fa854e15f8c6d70f8b27 Mon Sep 17 00:00:00 2001 From: nickmoreton Date: Fri, 4 Jul 2025 17:29:58 +0100 Subject: [PATCH 1/9] General dependency maintenance --- .github/workflows/CI-tests.yml | 32 +++++++++--------- .pre-commit-config.yaml | 10 +++--- .secrets.baseline | 59 +++++++++++++++++++++++++--------- pyproject.toml | 21 ++++++------ 4 files changed, 75 insertions(+), 47 deletions(-) diff --git a/.github/workflows/CI-tests.yml b/.github/workflows/CI-tests.yml index c55ddbc..bd63783 100644 --- a/.github/workflows/CI-tests.yml +++ b/.github/workflows/CI-tests.yml @@ -3,13 +3,13 @@ name: CI tests on: [push] env: - poetry-version: 1.8.2 + poetry-version: 1.8.5 jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python "3.9" uses: actions/setup-python@v4 with: @@ -20,13 +20,13 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.9", "3.10", "3.11", "3.12"] - django-version: ["4.2.16", "5.0.9", "5.1.2"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + django-version: ["4.2", "5.1", "5.2"] exclude: # Django too new - - django-version: "5.0.9" + - django-version: "5.1" python-version: "3.9" - - django-version: "5.1.2" + - django-version: "5.2" python-version: "3.9" steps: - uses: actions/checkout@v4 @@ -35,11 +35,11 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: Run image - uses: abatilo/actions-poetry@v2 + uses: abatilo/actions-poetry@v4 with: poetry-version: ${{ env.poetry-version }} - name: Cache Poetry virtual env - uses: actions/cache@v2 + uses: actions/cache@v4 env: cache-name: cache-poetry-virtualenv with: @@ -58,26 +58,26 @@ jobs: needs: [build, lint] strategy: matrix: - python-version: ["3.9", "3.10", "3.11", "3.12"] - django-version: ["4.2.16", "5.0.9", "5.1.2"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + django-version: ["4.2", "5.1", "5.2"] exclude: # Django too new - - django-version: "5.0.9" + - django-version: "5.1" python-version: "3.9" - - django-version: "5.1.2" + - django-version: "5.2" python-version: "3.9" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Run image - uses: abatilo/actions-poetry@v2.0.0 + uses: abatilo/actions-poetry@v4 with: poetry-version: ${{ env.poetry-version }} - name: Cache Poetry virtual env - uses: actions/cache@v2 + uses: actions/cache@v4 env: cache-name: cache-poetry-virtualenv with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 65c07c6..d10d02b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,16 +1,16 @@ repos: - repo: https://github.com/pycqa/isort - rev: 5.12.0 + rev: 6.0.1 hooks: - id: isort language_version: python3.9 - repo: https://github.com/pycqa/flake8 - rev: 5.0.4 + rev: 7.3.0 hooks: - id: flake8 language_version: python3.9 - repo: https://github.com/python/black - rev: 23.10.1 + rev: 25.1.0 hooks: - id: black language_version: python3.9 @@ -36,14 +36,14 @@ repos: hooks: - id: prettier - repo: https://github.com/awebdeveloper/pre-commit-stylelint - rev: c4c991cd38b0218735858716b09924f8b20e3812 + rev: 0.0.2 hooks: - id: stylelint additional_dependencies: - stylelint@10.1.0 - stylelint-config-torchbox@0.5.0 - repo: https://github.com/Yelp/detect-secrets - rev: v0.13.0 + rev: v1.5.0 hooks: - id: detect-secrets args: ["--baseline", ".secrets.baseline"] diff --git a/.secrets.baseline b/.secrets.baseline index 96634c6..b510ba7 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -1,8 +1,4 @@ { - "exclude": { - "files": null, - "lines": null - }, "generated_at": "2020-05-29T17:40:29Z", "plugins_used": [ { @@ -12,15 +8,15 @@ "name": "ArtifactoryDetector" }, { - "base64_limit": 4.5, - "name": "Base64HighEntropyString" + "name": "Base64HighEntropyString", + "limit": 4.5 }, { "name": "BasicAuthDetector" }, { - "hex_limit": 3, - "name": "HexHighEntropyString" + "name": "HexHighEntropyString", + "limit": 3 }, { "name": "JwtTokenDetector" @@ -48,16 +44,49 @@ "results": { "poetry.lock": [ { + "type": "Hex High Entropy String", + "filename": "poetry.lock", "hashed_secret": "ad21572f9e3b4576a754f88e9873b445e8bb0660", "is_verified": false, - "line_number": 494, - "type": "Hex High Entropy String" + "line_number": 494 } ] }, - "version": "0.13.0", - "word_list": { - "file": null, - "hash": null - } + "version": "1.5.0", + "filters_used": [ + { + "path": "detect_secrets.filters.allowlist.is_line_allowlisted" + }, + { + "path": "detect_secrets.filters.heuristic.is_sequential_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_potential_uuid" + }, + { + "path": "detect_secrets.filters.heuristic.is_likely_id_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_templated_secret" + }, + { + "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign" + }, + { + "path": "detect_secrets.filters.heuristic.is_indirect_reference" + }, + { + "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", + "min_level": 2 + }, + { + "path": "detect_secrets.filters.heuristic.is_lock_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_swagger_file" + } + ] } diff --git a/pyproject.toml b/pyproject.toml index 22da1b9..17b94ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,30 +15,29 @@ classifiers = [ "Topic :: Communications :: Email", "Framework :: Django", "Framework :: Django :: 4.2", - "Framework :: Django :: 5.0", "Framework :: Django :: 5.1", + "Framework :: Django :: 5.2", "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] license = "BSD-2-Clause" [tool.poetry.dependencies] -python = ">=3.9,<3.13" -django = [ - {version = ">=4.2", python = ">=3.9,<3.13"}, -] +python = ">=3.9" +django = ">=4.2" notifications-python-client = "^8.1.0" [tool.poetry.dev-dependencies] -black = "^23.10.1" -isort = "^5.12.0" -flake8 = "^5.0.4" -pre-commit = "^3.5.0" -detect-secrets = "1.4.0" -factory-boy = "^3.2.0" +black = "^25.1.0" +isort = "^6.0.1" +flake8 = "^7.3.0" +pre-commit = "^4.2.0" +detect-secrets = "1.5.0" +factory-boy = "^3.3.3" [build-system] requires = ["poetry-core"] From 6d1e5ecdbcc8a8f6dc49fffcf8430b870a98c14c Mon Sep 17 00:00:00 2001 From: nickmoreton Date: Fri, 4 Jul 2025 17:34:48 +0100 Subject: [PATCH 2/9] Use # pragma: allowlist secret for fake keys --- tests/settings.py | 4 ++-- tests/test_backend.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/settings.py b/tests/settings.py index 050b6b0..1150dad 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -40,7 +40,7 @@ MEDIA_ROOT = os.path.join(BASE_DIR, "test-media") MEDIA_URL = "http://media.example.com/media/" -SECRET_KEY = "not needed" +SECRET_KEY = "not needed" # pragma: allowlist secret -GOVUK_NOTIFY_API_KEY = "not a real API key" +GOVUK_NOTIFY_API_KEY = "not a real API key" # pragma: allowlist secret GOVUK_NOTIFY_PLAIN_EMAIL_TEMPLATE_ID = str(uuid.uuid4()) diff --git a/tests/test_backend.py b/tests/test_backend.py index a2983d6..094afe9 100644 --- a/tests/test_backend.py +++ b/tests/test_backend.py @@ -14,7 +14,9 @@ class EmailBackendTest(TestCase): def setUp(self): self.backend = NotifyEmailBackend(govuk_notify_api_key="not a real key") - @override_settings(GOVUK_NOTIFY_API_KEY="fake settings key") + @override_settings( + GOVUK_NOTIFY_API_KEY="fake settings key" # pragma: allowlist secret + ) def test_default_key(self, mock_client): backend = NotifyEmailBackend() self.assertEqual(backend.api_key, "fake settings key") From 50c2c8ced76c968f9f6bd942d3f774fca166450a Mon Sep 17 00:00:00 2001 From: nickmoreton Date: Fri, 4 Jul 2025 17:38:59 +0100 Subject: [PATCH 3/9] Don't test django 4.2 with Python 3.13 --- .github/workflows/CI-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/CI-tests.yml b/.github/workflows/CI-tests.yml index bd63783..cfb90cf 100644 --- a/.github/workflows/CI-tests.yml +++ b/.github/workflows/CI-tests.yml @@ -66,6 +66,9 @@ jobs: python-version: "3.9" - django-version: "5.2" python-version: "3.9" + # Django too old + - django-version: "4.2" + python-version: "3.13" steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} From 27557c4ac182db98e1a2813e203cc2af73095e43 Mon Sep 17 00:00:00 2001 From: nickmoreton Date: Fri, 4 Jul 2025 17:51:03 +0100 Subject: [PATCH 4/9] Add basic tox configuration --- .gitignore | 1 + tox.ini | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index 6131e3b..a286120 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ wheels/ *.egg builds/ poetry.lock +.tox diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..3b658fb --- /dev/null +++ b/tox.ini @@ -0,0 +1,29 @@ +[tox] +envlist = + py39-django42 + py310-django{42,51,52} + py311-django{42,51,52} + py312-django{42,51,52} + py313-django{51,52} + lint +minversion = 4.0 +isolated_build = true + +[testenv] +deps = + django42: django>=4.2,<5.0 + django51: django>=5.1,<5.2 + django52: django>=5.2,<5.3 + notifications-python-client>=8.1.0 + factory-boy>=3.3.3 +commands = python runtests.py {posargs} + +[flake8] +max-line-length = 88 +extend-ignore = E203, W503 +exclude = .git,__pycache__,build,dist,.tox,.venv,venv + +[tool:isort] +profile = black +multi_line_output = 3 +line_length = 88 From f6edf83aacec9e5350edec7b000ba12c7e77b709 Mon Sep 17 00:00:00 2001 From: nickmoreton Date: Fri, 4 Jul 2025 17:53:23 +0100 Subject: [PATCH 5/9] Add missing too old Django version to CI tests --- .github/workflows/CI-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/CI-tests.yml b/.github/workflows/CI-tests.yml index cfb90cf..f42b44a 100644 --- a/.github/workflows/CI-tests.yml +++ b/.github/workflows/CI-tests.yml @@ -28,6 +28,9 @@ jobs: python-version: "3.9" - django-version: "5.2" python-version: "3.9" + # Django too old + - django-version: "4.2" + python-version: "3.13" steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} From 980926889495680fac42133807c0839530bb3178 Mon Sep 17 00:00:00 2001 From: nickmoreton Date: Fri, 4 Jul 2025 17:57:44 +0100 Subject: [PATCH 6/9] Initial tox-gh-actions --- .github/workflows/CI-tests.yml | 20 +++++++------------ tox.ini | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/.github/workflows/CI-tests.yml b/.github/workflows/CI-tests.yml index f42b44a..1e0c324 100644 --- a/.github/workflows/CI-tests.yml +++ b/.github/workflows/CI-tests.yml @@ -72,23 +72,17 @@ jobs: # Django too old - django-version: "4.2" python-version: "3.13" + env: + DJANGO: ${{ matrix.django-version }} steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - name: Run image - uses: abatilo/actions-poetry@v4 - with: - poetry-version: ${{ env.poetry-version }} - - name: Cache Poetry virtual env - uses: actions/cache@v4 - env: - cache-name: cache-poetry-virtualenv - with: - path: .venv - key: ${{ runner.os }}-python-${{ matrix.python-version }}-django-${{ matrix.django-version }}-${{ hashFiles('pyproject.toml') }} - - name: Test + - name: Install tox and tox-gh-actions run: | - poetry run python runtests.py + python -m pip install --upgrade pip + pip install tox tox-gh-actions + - name: Test with tox + run: tox diff --git a/tox.ini b/tox.ini index 3b658fb..02eabb8 100644 --- a/tox.ini +++ b/tox.ini @@ -9,6 +9,20 @@ envlist = minversion = 4.0 isolated_build = true +[gh-actions] +python = + 3.9: py39 + 3.10: py310 + 3.11: py311 + 3.12: py312 + 3.13: py313 + +[gh-actions:env] +DJANGO = + 4.2: django42 + 5.1: django51 + 5.2: django52 + [testenv] deps = django42: django>=4.2,<5.0 @@ -18,6 +32,27 @@ deps = factory-boy>=3.3.3 commands = python runtests.py {posargs} +[testenv:lint] +deps = + black>=25.1.0 + isort>=6.0.1 + flake8>=7.3.0 + pre-commit>=4.2.0 + detect-secrets==1.5.0 +commands = + black --check --diff . + isort --check-only --diff . + flake8 . + detect-secrets scan + +[testenv:format] +deps = + black>=25.1.0 + isort>=6.0.1 +commands = + black . + isort . + [flake8] max-line-length = 88 extend-ignore = E203, W503 From 290621f947984b118adbbeabb7b12eea0cd62189 Mon Sep 17 00:00:00 2001 From: nickmoreton Date: Fri, 4 Jul 2025 18:03:19 +0100 Subject: [PATCH 7/9] Apparently this actions file can use tox config entirely. --- .github/workflows/CI-tests.yml | 62 ++++++++-------------------------- 1 file changed, 14 insertions(+), 48 deletions(-) diff --git a/.github/workflows/CI-tests.yml b/.github/workflows/CI-tests.yml index 1e0c324..26dbe96 100644 --- a/.github/workflows/CI-tests.yml +++ b/.github/workflows/CI-tests.yml @@ -2,63 +2,20 @@ name: CI tests on: [push] -env: - poetry-version: 1.8.5 - jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Set up Python "3.9" - uses: actions/setup-python@v4 + - name: Set up Python 3.9 + uses: actions/setup-python@v5 with: python-version: "3.9" - - uses: pre-commit/action@v3.0.0 - - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] - django-version: ["4.2", "5.1", "5.2"] - exclude: - # Django too new - - django-version: "5.1" - python-version: "3.9" - - django-version: "5.2" - python-version: "3.9" - # Django too old - - django-version: "4.2" - python-version: "3.13" - steps: - - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - name: Run image - uses: abatilo/actions-poetry@v4 - with: - poetry-version: ${{ env.poetry-version }} - - name: Cache Poetry virtual env - uses: actions/cache@v4 - env: - cache-name: cache-poetry-virtualenv - with: - path: .venv - key: ${{ runner.os }}-python-${{ matrix.python-version }}-django-${{ matrix.django-version }}-${{ hashFiles('pyproject.toml') }} - - name: Install packages - run: | - poetry config virtualenvs.in-project true - poetry remove django - poetry add django==${{ matrix.django-version }} --python ${{ matrix.python-version }} - poetry install - poetry show django + - uses: pre-commit/action@v3.0.1 test: runs-on: ubuntu-latest - needs: [build, lint] + needs: lint strategy: matrix: python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] @@ -77,9 +34,18 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + - name: Cache tox environments + uses: actions/cache@v4 + with: + path: .tox + key: ${{ runner.os }}-tox-py${{ matrix.python-version }}-django${{ matrix.django-version }}-${{ hashFiles('pyproject.toml', 'tox.ini') }} + restore-keys: | + ${{ runner.os }}-tox-py${{ matrix.python-version }}-django${{ matrix.django-version }}- + ${{ runner.os }}-tox-py${{ matrix.python-version }}- + ${{ runner.os }}-tox- - name: Install tox and tox-gh-actions run: | python -m pip install --upgrade pip From 695c4cf31eb4dda4c520b8a43458a3b125c2777d Mon Sep 17 00:00:00 2001 From: nickmoreton Date: Fri, 4 Jul 2025 18:10:33 +0100 Subject: [PATCH 8/9] Get the tox lint and format working --- tox.ini | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tox.ini b/tox.ini index 02eabb8..315d2e4 100644 --- a/tox.ini +++ b/tox.ini @@ -32,26 +32,23 @@ deps = factory-boy>=3.3.3 commands = python runtests.py {posargs} -[testenv:lint] +[testenv:lint] # run with `tox -e lint` deps = black>=25.1.0 isort>=6.0.1 flake8>=7.3.0 - pre-commit>=4.2.0 - detect-secrets==1.5.0 commands = - black --check --diff . - isort --check-only --diff . + black --check --diff --exclude=".tox" . + isort --check-only --diff --skip=.tox . flake8 . - detect-secrets scan -[testenv:format] +[testenv:format] # run with `tox -e format` deps = black>=25.1.0 isort>=6.0.1 commands = - black . - isort . + black --exclude=".tox" . + isort --skip=.tox . [flake8] max-line-length = 88 From 182d17d654cde0539d9c70fb968c37fbfe485d22 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Fri, 4 Jul 2025 21:56:51 +0100 Subject: [PATCH 9/9] Update compatibility versions and CHANGELOG --- CHANGELOG.md | 7 +++++++ README.md | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d881915..f16622d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## 0.6.0 (2024-10-25) +## Unreleased + +- Support Python 3.13 +- Support Django 5.2 +- Drop support for Django 5.0 +- Add tox configuration for testing + ### Features - Drop support for Python 3.8 diff --git a/README.md b/README.md index 044b10c..693f348 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ This is implemented as a custom Django email backend. It presents a similar inte django-gov-notify supports: -- Python 3.9, 3.10, 3.11 and 3.12 -- Django 4.2, 5.0 and 5.1 +- Python 3.9, 3.10, 3.11, 3.12 and 3.13 +- Django 4.2, 5.1 and 5.2 ## Installation