From 9e0948828270b69398b5dee55b8addf5618a6ca2 Mon Sep 17 00:00:00 2001 From: Ryan Raasch Date: Mon, 20 Jul 2026 18:34:18 +0000 Subject: [PATCH 1/6] add function for version_spec creation --- cfa/dataops/utils.py | 14 +++++++++++++- tests/test_utils_version_matcher.py | 18 +++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/cfa/dataops/utils.py b/cfa/dataops/utils.py index e1b6883..8c2e7b6 100644 --- a/cfa/dataops/utils.py +++ b/cfa/dataops/utils.py @@ -193,6 +193,18 @@ def normalize(version: str) -> str: return version.replace("T", ".").replace("-", ".") +def construct_version_spec(version: str | None) -> str | None: + """Normalize a version string into a packaging specifier. + + If the input already starts with a comparator character (``>``, ``<``, or ``=``), + it is returned unchanged. Otherwise, an exact-match specifier is created + by prepending ``==``. + """ + if version is None or version.startswith((">", "<", "=")): + return version + return f"=={version}" + + def version_matcher( version_spec: str | None, available_versions: list[str], @@ -223,7 +235,7 @@ def version_matcher( versions = sorted( (Version(normalize(version)), version) for version in available_versions ) - + version_spec = construct_version_spec(version_spec) if version_spec is not None: specset = SpecifierSet(normalize(version_spec)) versions = [ diff --git a/tests/test_utils_version_matcher.py b/tests/test_utils_version_matcher.py index a2021ff..75859ee 100644 --- a/tests/test_utils_version_matcher.py +++ b/tests/test_utils_version_matcher.py @@ -2,7 +2,23 @@ import pytest -from cfa.dataops.utils import version_matcher +from cfa.dataops.utils import construct_version_spec, version_matcher + + +class TestConstructVersionSpec: + """Tests for construct_version_spec helper.""" + + @pytest.mark.parametrize( + "raw_version,expected", + [ + ("2025-12-15T00-00-00", "==2025-12-15T00-00-00"), + (">2025-12-15T00-00-00", ">2025-12-15T00-00-00"), + ("<2025-12-15T00-00-00", "<2025-12-15T00-00-00"), + ("==2025-12-15T00-00-00", "==2025-12-15T00-00-00"), + ], + ) + def test_construct_version_spec(self, raw_version, expected): + assert construct_version_spec(raw_version) == expected class TestVersionMatcher: From 5c65f999859e5ed0b0b4936baad0762332086d16 Mon Sep 17 00:00:00 2001 From: Ryan Raasch <150935395+ryanraaschCDC@users.noreply.github.com> Date: Mon, 20 Jul 2026 19:07:44 +0000 Subject: [PATCH 2/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- cfa/dataops/utils.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cfa/dataops/utils.py b/cfa/dataops/utils.py index 8c2e7b6..1c29829 100644 --- a/cfa/dataops/utils.py +++ b/cfa/dataops/utils.py @@ -196,11 +196,18 @@ def normalize(version: str) -> str: def construct_version_spec(version: str | None) -> str | None: """Normalize a version string into a packaging specifier. - If the input already starts with a comparator character (``>``, ``<``, or ``=``), - it is returned unchanged. Otherwise, an exact-match specifier is created + If the input already starts with a specifier operator (e.g. ``>``, ``<``, ``=``, ``~``, or ``!``), + it is returned unchanged (after stripping whitespace). Otherwise, an exact-match specifier is created by prepending ``==``. """ - if version is None or version.startswith((">", "<", "=")): + if version is None: + return None + + version = version.strip() + if version == "": + return "" + + if version.startswith((">", "<", "=", "~", "!")): return version return f"=={version}" From c5523f496aee9c511e636f64bb8a845c877e79d7 Mon Sep 17 00:00:00 2001 From: Ryan Raasch <150935395+ryanraaschCDC@users.noreply.github.com> Date: Mon, 20 Jul 2026 19:08:02 +0000 Subject: [PATCH 3/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- tests/test_utils_version_matcher.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_utils_version_matcher.py b/tests/test_utils_version_matcher.py index 75859ee..b4b7631 100644 --- a/tests/test_utils_version_matcher.py +++ b/tests/test_utils_version_matcher.py @@ -15,6 +15,10 @@ class TestConstructVersionSpec: (">2025-12-15T00-00-00", ">2025-12-15T00-00-00"), ("<2025-12-15T00-00-00", "<2025-12-15T00-00-00"), ("==2025-12-15T00-00-00", "==2025-12-15T00-00-00"), + ("~=2025-12-15T00-00-00", "~=2025-12-15T00-00-00"), + ("!=2025-12-15T00-00-00", "!=2025-12-15T00-00-00"), + ("", ""), + (" ", ""), ], ) def test_construct_version_spec(self, raw_version, expected): From 7f77eadf996d69f633b093e9cf41096bf2f97df3 Mon Sep 17 00:00:00 2001 From: Ryan Raasch <150935395+ryanraaschCDC@users.noreply.github.com> Date: Mon, 20 Jul 2026 19:08:17 +0000 Subject: [PATCH 4/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- tests/test_utils_version_matcher.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_utils_version_matcher.py b/tests/test_utils_version_matcher.py index b4b7631..c7f5f9a 100644 --- a/tests/test_utils_version_matcher.py +++ b/tests/test_utils_version_matcher.py @@ -24,6 +24,16 @@ class TestConstructVersionSpec: def test_construct_version_spec(self, raw_version, expected): assert construct_version_spec(raw_version) == expected + def test_version_matcher_accepts_raw_version(self): + available_versions = [ + "2025-12-15T00-00-00", + "2025-12-16T00-00-00", + "2025-12-17T00-00-00", + ] + assert ( + version_matcher("2025-12-16T00-00-00", available_versions) + == "2025-12-16T00-00-00" + ) class TestVersionMatcher: """Tests for the version_matcher function.""" From 8c2fc4346a57379337f05419be8a8143c9d861c7 Mon Sep 17 00:00:00 2001 From: Ryan Raasch Date: Mon, 20 Jul 2026 19:11:36 +0000 Subject: [PATCH 5/6] precommit fixes --- tests/test_utils_version_matcher.py | 1 + uv.lock | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_utils_version_matcher.py b/tests/test_utils_version_matcher.py index c7f5f9a..5bc5b30 100644 --- a/tests/test_utils_version_matcher.py +++ b/tests/test_utils_version_matcher.py @@ -35,6 +35,7 @@ def test_version_matcher_accepts_raw_version(self): == "2025-12-16T00-00-00" ) + class TestVersionMatcher: """Tests for the version_matcher function.""" diff --git a/uv.lock b/uv.lock index f46fcb3..e01cbfa 100644 --- a/uv.lock +++ b/uv.lock @@ -655,7 +655,7 @@ dependencies = [ [[package]] name = "cfa-dataops" -version = "2026.6.30.0" +version = "2026.7.20.0" source = { editable = "." } dependencies = [ { name = "altair" }, From be5710475a482b62f3838c3f6a6b56fc455b9bdd Mon Sep 17 00:00:00 2001 From: Ryan Raasch Date: Tue, 21 Jul 2026 19:32:16 +0000 Subject: [PATCH 6/6] update changelog, pyproject --- changelog.md | 4 ++++ pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 4c0a806..f413958 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,10 @@ and this project adheres to [Calendar Versioning](https://calver.org/). The versioning pattern is `YYYY.MM.DD.micro(a/b/{none if release}) --- +## [2026.07.21.0] + +- adds function to translate bare versions to version_spec + ## [2026.07.20.0] - change most print statements to logging diff --git a/pyproject.toml b/pyproject.toml index fa74eec..7e9dca5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cfa.dataops" -version = "2026.07.20.0" +version = "2026.07.21.0" description = "Data cataloging, ETL, modeling, verification, and validation for CFA" authors = [ { name = "Phil Rogers", email = "ap66@cdc.gov" },