From cc66da2fa698affc543ca5bcfbe5ea847464c479 Mon Sep 17 00:00:00 2001 From: MsShawnP Date: Wed, 8 Jul 2026 16:27:21 -0400 Subject: [PATCH 1/2] ci: bump GitHub Actions to Node 24 native versions GitHub is deprecating Node 20 on Actions runners, so actions pinned to Node-20 majors were being force-run on Node 24 with a warning. Bump each to its latest major that natively targets Node 24 (runs.using: node24): - actions/checkout v4 -> v7 - actions/setup-python v5 -> v6 - actions/upload-artifact v4 -> v7 - actions/download-artifact v4 -> v8 upload v7 and download v8 both use the @actions/artifact v6 backend, so they stay compatible. pypa/gh-action-pypi-publish@release/v1 is a Docker action (no Node runtime) and emits no warning, so it is left unchanged. CI config only: no package version bump, no PyPI release. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 4 ++-- .github/workflows/publish.yml | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b30cc10..d132ee7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,10 +14,10 @@ jobs: python-version: ["3.9", "3.12", "3.13"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2766c74..3f865bb 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,9 +11,9 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: "3.12" @@ -24,7 +24,7 @@ jobs: run: python -m build - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: dist path: dist/ @@ -32,9 +32,9 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: "3.12" @@ -50,7 +50,7 @@ jobs: runs-on: ubuntu-latest environment: pypi steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist path: dist/ From fa3ea0b8fad29e53aa2645b61e6d0d895588b049 Mon Sep 17 00:00:00 2001 From: MsShawnP Date: Wed, 8 Jul 2026 16:34:47 -0400 Subject: [PATCH 2/2] fix(typing): make mypy pass on the Python 3.9 CI leg The CI 3.9 matrix leg was failing at the mypy step (and thus red on main), which blocked pytest from ever running on 3.9: - core.py used PEP 604 `X | Y` union syntax in annotations, which mypy rejects for a 3.9 target and which raises TypeError at import time on 3.9. Add `from __future__ import annotations` (matches the other modules in the package) so the annotations are lazy and valid on 3.9. - rules.py passed a compiled `re.Pattern` to `Series.str.fullmatch`, whose stub expects `str`. The pattern is already validated at rule-load time and pandas compiles internally, so pass the pattern string directly and drop the redundant `re.compile` call. Behavior unchanged. Verified: ruff clean, mypy clean, 233 tests pass. Co-Authored-By: Claude Opus 4.8 --- data_hygiene_auditor/core.py | 2 ++ data_hygiene_auditor/rules.py | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data_hygiene_auditor/core.py b/data_hygiene_auditor/core.py index d408121..7d1e67f 100644 --- a/data_hygiene_auditor/core.py +++ b/data_hygiene_auditor/core.py @@ -1,5 +1,7 @@ """Core audit orchestrator and data loading.""" +from __future__ import annotations + import os from datetime import datetime from pathlib import Path diff --git a/data_hygiene_auditor/rules.py b/data_hygiene_auditor/rules.py index b2665af..d066bb4 100644 --- a/data_hygiene_auditor/rules.py +++ b/data_hygiene_auditor/rules.py @@ -188,8 +188,7 @@ def evaluate_rule(rule: Rule, series: pd.Series, col_name: str) -> Optional[Dict return None if rule.condition == 'regex_match': - pattern = re.compile(rule.threshold) - violations = non_empty[~non_empty.str.fullmatch(pattern, na=False)] + violations = non_empty[~non_empty.str.fullmatch(rule.threshold, na=False)] if len(violations) == 0: return None examples = violations.head(5).tolist() @@ -212,8 +211,7 @@ def evaluate_rule(rule: Rule, series: pd.Series, col_name: str) -> Optional[Dict } if rule.condition == 'not_regex_match': - pattern = re.compile(rule.threshold) - violations = non_empty[non_empty.str.fullmatch(pattern, na=False)] + violations = non_empty[non_empty.str.fullmatch(rule.threshold, na=False)] if len(violations) == 0: return None examples = violations.head(5).tolist()