Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion cfa/dataops/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,25 @@ 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 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:
return None

version = version.strip()
if version == "":
return ""

if version.startswith((">", "<", "=", "~", "!")):
return version
return f"=={version}"
Comment thread
Copilot marked this conversation as resolved.


def version_matcher(
version_spec: str | None,
available_versions: list[str],
Expand Down Expand Up @@ -223,7 +242,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 = [
Expand Down
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -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" },
Expand Down
33 changes: 32 additions & 1 deletion tests/test_utils_version_matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,38 @@

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"),
("~=2025-12-15T00-00-00", "~=2025-12-15T00-00-00"),
("!=2025-12-15T00-00-00", "!=2025-12-15T00-00-00"),
("", ""),
(" ", ""),
],
Comment thread
Copilot marked this conversation as resolved.
)
def test_construct_version_spec(self, raw_version, expected):
assert construct_version_spec(raw_version) == expected

Comment thread
Copilot marked this conversation as resolved.
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:
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.