From bc2acac666d63ba3bff0bc3b6d6577c21d8553a3 Mon Sep 17 00:00:00 2001 From: xhon-pelushi Date: Sun, 16 Aug 2026 23:33:33 -0400 Subject: [PATCH] Add pythonrelease and pythonrelease_info grains The pythonversion grain is a list, which breaks the release / release_info convention used by the other version grains such as osrelease / osrelease_info. Add pythonrelease (the dotted version string, e.g. 3.11.0) and pythonrelease_info (the equivalent list) alongside it. The change is purely additive: pythonversion keeps its existing value and type, so nothing that reads it today is affected. Fixes #59594 --- changelog/59594.added.md | 5 +++++ salt/grains/core.py | 14 +++++++++++++- tests/pytests/unit/grains/test_core.py | 21 +++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 changelog/59594.added.md diff --git a/changelog/59594.added.md b/changelog/59594.added.md new file mode 100644 index 000000000000..47c9da3ac168 --- /dev/null +++ b/changelog/59594.added.md @@ -0,0 +1,5 @@ +Added ``pythonrelease`` and ``pythonrelease_info`` grains, which follow the +``release`` / ``release_info`` convention already used by grains such +as ``osrelease`` / ``osrelease_info``. ``pythonrelease`` is the dotted version +string (for example ``3.11.0``) and ``pythonrelease_info`` is the equivalent +list. The existing list-valued ``pythonversion`` grain is unchanged. diff --git a/salt/grains/core.py b/salt/grains/core.py index a729322305e5..64f83b562fd7 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -3193,7 +3193,19 @@ def pythonversion(): """ # Provides: # pythonversion - return {"pythonversion": list(sys.version_info)} + # pythonrelease + # pythonrelease_info + # + # ``pythonversion`` is a list rather than a dotted string, which is + # inconsistent with the ``release`` / ``release_info`` pair used + # by the other version grains (e.g. ``osrelease`` / ``osrelease_info``). + # ``pythonrelease`` and ``pythonrelease_info`` follow that convention; + # ``pythonversion`` is kept unchanged for backwards compatibility. + return { + "pythonversion": list(sys.version_info), + "pythonrelease": platform.python_version(), + "pythonrelease_info": list(sys.version_info), + } def pythonpath(): diff --git a/tests/pytests/unit/grains/test_core.py b/tests/pytests/unit/grains/test_core.py index e57c05b96b78..2a3727fdca79 100644 --- a/tests/pytests/unit/grains/test_core.py +++ b/tests/pytests/unit/grains/test_core.py @@ -4504,6 +4504,27 @@ def test_pythonversion(): assert ret["pythonversion"] == python_version +def test_pythonrelease(): + """ + test pythonrelease and pythonrelease_info + + These follow the ``release`` / ``release_info`` convention used + by the other version grains, unlike the older list-valued + ``pythonversion`` grain which is retained for backwards compatibility. + """ + ret = core.pythonversion() + + assert "pythonrelease" in ret + assert ret["pythonrelease"] == platform.python_version() + # dotted major.minor.micro, matching the shape of e.g. osrelease + assert ret["pythonrelease"] == "{}.{}.{}".format(*sys.version_info[:3]) + + assert "pythonrelease_info" in ret + assert ret["pythonrelease_info"] == [*sys.version_info] + # the pre-existing grain keeps working and stays in sync + assert ret["pythonrelease_info"] == ret["pythonversion"] + + @pytest.mark.skip_unless_on_linux def test_get_machine_id(): """