From e2f27a3a362e3b31a042d3ce89f88986a7392c10 Mon Sep 17 00:00:00 2001 From: Mariam Ahhttouche Date: Fri, 13 Feb 2026 12:26:18 +0100 Subject: [PATCH] uv_python module: add _list_python and _get_latest_patch_release methods --- plugins/modules/uv_python.py | 53 +++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/plugins/modules/uv_python.py b/plugins/modules/uv_python.py index a3f2602a44..0504c150d7 100644 --- a/plugins/modules/uv_python.py +++ b/plugins/modules/uv_python.py @@ -52,38 +52,29 @@ python: ''' import re +import json from enum import Enum from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.compat.version import StrictVersion -MINOR_RELEASE = re.compile(r"^\d+\.\d+$") -PATCH_RELEASE = re.compile(r"^\d+\.\d+\.\d+$") - -class Release(Enum): - PATCH = 1 - MINOR = 2 - -def extract_python_version(version: str, module): - if PATCH_RELEASE.match(version): - return Release.PATCH, version - elif MINOR_RELEASE.match(version): - return Release.MINOR, version - else: - module.fail_json( - msg=( - f"Invalid version '{version}'. " - "Expected X.Y or X.Y.Z." - ) - ) - return None, None - class UV: """ Documentation for uv python https://docs.astral.sh/uv/concepts/python-versions/#installing-a-python-version """ def __init__(self, module, **kwargs): self.module = module - self.python_version_type, self.python_version = extract_python_version(module.params["version"], module) + python_version = module.params["version"] + try: + self.python_version = StrictVersion(python_version) + self.python_version_str = self.python_version.__str__() + except ValueError: + module.fail_json( + msg=( + f"Invalid version '{python_version}'. " + "Expected X.Y or X.Y.Z." + ) + ) def install_python(self): rc, out, _ = self._find_python() @@ -92,7 +83,7 @@ class UV: if self.module.check_mode: return True, "" - cmd = [self.module.get_bin_path("uv", required=True), "python", "install", self.python_version] + cmd = [self.module.get_bin_path("uv", required=True), "python", "install", self.python_version_str] _, out, _ = self.module.run_command(cmd, check_rc=True) return True, out @@ -103,15 +94,27 @@ class UV: if self.module.check_mode: return True, "" - cmd = [self.module.get_bin_path("uv", required=True), "python", "uninstall", self.python_version] + cmd = [self.module.get_bin_path("uv", required=True), "python", "uninstall", self.python_version_str] _, out, _ = self.module.run_command(cmd, check_rc=True) return True, out def _find_python(self): - cmd = [self.module.get_bin_path("uv", required=True), "python", "find", self.python_version] + cmd = [self.module.get_bin_path("uv", required=True), "python", "find", self.python_version_str] + rc, out, err = self.module.run_command(cmd) + return rc, out, err + + def _list_python(self): + # By default, only the latest patch version is shown for each minor version. + # https://docs.astral.sh/uv/reference/cli/#uv-python-list + cmd = [self.module.get_bin_path("uv", required=True), "python", "list", self.python_version_str, "--output-format", "json"] rc, out, err = self.module.run_command(cmd) return rc, out, err + def _get_latest_patch_release(self): + _, out, _ = self._list_python() + result = json.loads(out) + return result[-1]["version"] + def main(): module = AnsibleModule(