Repository: ni/measurement-plugin-python (language: python)

Issue:
GitHub workflow caching doesn't take full Python version into account
# Bug Report

Windows Python 3.12 tests have started failing due to a mismatch between the installed Python and the cached venv: https://github.com/ni/measurementlink-python/actions/runs/7215371883/job/19659513972

```
Run actions/setup-python@v5
  with:
    python-version: 3.[1](https://github.com/ni/measurementlink-python/actions/runs/7215371883/job/19659513972#step:3:1)[2](https://github.com/ni/measurementlink-python/actions/runs/7215371883/job/19659513972#step:3:2)
    check-latest: false
    token: ***
    update-environment: true
    allow-prereleases: false
  env:
    POETRY_VERSION: 1.2.2
Installed versions
  Successfully set up CPython ([3](https://github.com/ni/measurementlink-python/actions/runs/7215371883/job/19659513972#step:3:3).12.1)
```

```
Run poetry install -v

  CalledProcessError

  Command 'D:\a\measurementlink-python\measurementlink-python\.venv\Scripts\python.exe -W ignore -' returned non-zero exit status 103.

  at C:\hostedtoolcache\windows\Python\3.[12](https://github.com/ni/measurementlink-python/actions/runs/7215371883/job/19659513972#step:6:13).1\x64\Lib\subprocess.py:571 in run
       567|             # We don't call process.wait() as .__exit__ does that for us.
       568|             raise
       569|         retcode = process.poll()
       570|         if check and retcode:
    >  571|             raise CalledProcessError(retcode, process.args,
       572|                                      output=stdout, stderr=stderr)
       573|     return CompletedProcess(process.args, retcode, stdout, stderr)
       574| 
       575| 

The following error occurred when trying to handle this error:


  EnvCommandError

  Command D:\a\measurementlink-python\measurementlink-python\.venv\Scripts\python.exe -W ignore - errored with the following return code 103, and output: 
  No Python at '"C:\hostedtoolcache\windows\Python\3.12.0\x64\python.exe'

  input was : import sys
  
  if hasattr(sys, "real_prefix"):
      print(sys.real_prefix)
  elif hasattr(sys, "base_prefix"):
      print(sys.base_prefix)
  else:
      print(sys.prefix)
  

  at ~\AppData\Roaming\pypoetry\venv\Lib\site-packages\poetry\utils\env.py:[14](https://github.com/ni/measurementlink-python/actions/runs/7215371883/job/19659513972#step:6:15)76 in _run
      1472|                 output = subprocess.check_output(
      1[47](https://github.com/ni/measurementlink-python/actions/runs/7215371883/job/19659513972#step:6:48)3|                     command, stderr=subprocess.STDOUT, env=env, **kwargs
      1474|                 )
      1475|         except CalledProcessError as e:
    > 1476|             raise EnvCommandError(e, input=input_)
      1477| 
      1478|         return decode(output)
      1479| 
      1[48](https://github.com/ni/measurementlink-python/actions/runs/7215371883/job/19659513972#step:6:49)0|     def execute(self, bin: str, *args: str, **kwargs: Any) -> int:
Error: Process completed with exit code 1.
```

## Repro or Code Sample

Create a PR.

## Expected Behavior

The tests pass.

## Current Behavior

`No Python at '"C:\hostedtoolcache\windows\Python\3.12.0\x64\python.exe'`

## Possible Solution

Use full Python version in the cache key.

## Context

Developing ni-measurementlink-service.

## Your Environment

GitHub

[AB#2605083](https://dev.azure.com/ni/94b22d7b-ad7b-4f5e-88f0-867910f91c94/_workitems/edit/2605083)


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/check_examples.yml b/.github/workflows/check_examples.yml
index 418127345..b80c0e535 100644
--- a/.github/workflows/check_examples.yml
+++ b/.github/workflows/check_examples.yml
@@ -17,6 +17,7 @@ jobs:
         uses: actions/checkout@v4
       - name: Set up Python
         uses: actions/setup-python@v5
+        id: setup-python
         with:
           python-version: ${{ env.PYTHON_VERSION }}
       - name: Set up Poetry
@@ -30,7 +31,7 @@ jobs:
         with:
           path: 'examples/**/poetry.lock'
           # Include the main project's poetry.lock in the hash to detect upstream dependency updates.
-          key: examples-poetry-lock-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('examples/**/pyproject.toml', 'poetry.lock') }}
+          key: examples-poetry-lock-${{ runner.os }}-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('examples/**/pyproject.toml', 'poetry.lock') }}
       - name: Lock examples
         if: steps.cache-poetry-lock.outputs.cache-hit != 'true'
         run: |
@@ -46,7 +47,7 @@ jobs:
         id: cache-venv
         with:
           path: 'examples/**/.venv'
-          key: examples-venv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('examples/**/poetry.lock') }}
+          key: examples-venv-${{ runner.os }}-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('examples/**/poetry.lock') }}
       - name: Install examples
         run: |
           for example in examples/*/; do
diff --git a/.github/workflows/check_nimg.yml b/.github/workflows/check_nimg.yml
index 72a5e37a4..ce9309951 100644
--- a/.github/workflows/check_nimg.yml
+++ b/.github/workflows/check_nimg.yml
@@ -21,6 +21,7 @@ jobs:
         uses: actions/checkout@v4
       - name: Set up Python
         uses: actions/setup-python@v5
+        id: setup-python
         with:
           python-version: ${{ env.PYTHON_VERSION }}
       - name: Set up Poetry
@@ -34,7 +35,7 @@ jobs:
         id: cache
         with:
           path: ni_measurementlink_generator/.venv
-          key: ni-measurementlink-generator-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('poetry.lock') }}
+          key: ni-measurementlink-generator-${{ runner.os }}-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
       - name: Install ni-measurementlink-generator
         run: poetry install -v
       - name: Lint ni-measurementlink-generator
diff --git a/.github/workflows/check_nims.yml b/.github/workflows/check_nims.yml
index a64958f73..6ca043cfa 100644
--- a/.github/workflows/check_nims.yml
+++ b/.github/workflows/check_nims.yml
@@ -17,6 +17,7 @@ jobs:
         uses: actions/checkout@v4
       - name: Set up Python
         uses: actions/setup-python@v5
+        id: setup-python
         with:
           python-version: ${{ env.PYTHON_VERSION }}
       - name: Set up Poetry
@@ -32,7 +33,7 @@ jobs:
         id: restore-nims-all-extras
         with:
           path: .venv
-          key: ni-measurementlink-service-all-extras-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('poetry.lock') }}
+          key: ni-measurementlink-service-all-extras-${{ runner.os }}-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
       - name: Install ni-measurementlink-service (all extras)
         run: poetry install -v --all-extras
       - name: Save cached virtualenv (ni-measurementlink-service, all extras)
@@ -58,7 +59,7 @@ jobs:
         id: restore-nims-all-extras-docs
         with:
           path: .venv
-          key: ni-measurementlink-service-all-extras-docs-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('poetry.lock') }}
+          key: ni-measurementlink-service-all-extras-docs-${{ runner.os }}-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
       - name: Install ni-measurementlink-service (all extras, docs)
         run: poetry install -v --all-extras --with docs
       - name: Save cached virtualenv (ni-measurementlink-service, all extras, docs)


Test patch:
diff --git a/.github/workflows/run_unit_tests.yml b/.github/workflows/run_unit_tests.yml
index c798f849f..0a015e3af 100644
--- a/.github/workflows/run_unit_tests.yml
+++ b/.github/workflows/run_unit_tests.yml
@@ -23,6 +23,7 @@ jobs:
         uses: actions/checkout@v4
       - name: Set up Python
         uses: actions/setup-python@v5
+        id: setup-python
         with:
           python-version: ${{ matrix.python-version }}
       - name: Set up Poetry
@@ -36,7 +37,7 @@ jobs:
         id: restore-nims-no-extras
         with:
           path: .venv
-          key: ni-measurementlink-service-no-extras-${{ runner.os }}-py${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
+          key: ni-measurementlink-service-no-extras-${{ runner.os }}-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
       - name: Install ni-measurementlink-service (no extras)
         run: poetry install -v
       - name: Save cached virtualenv (ni-measurementlink-service, no extras)
@@ -54,7 +55,7 @@ jobs:
         id: restore-nims-all-extras
         with:
           path: .venv
-          key: ni-measurementlink-service-all-extras-${{ runner.os }}-py${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
+          key: ni-measurementlink-service-all-extras-${{ runner.os }}-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
       - name: Install ni-measurementlink-service (all extras)
         run: poetry install -v --all-extras
       - name: Save cached ni-measurementlink-service virtualenv (all extras)
@@ -72,7 +73,7 @@ jobs:
         id: restore-nimg
         with:
           path: ni_measurementlink_generator/.venv
-          key: ni-measurementlink-generator-${{ runner.os }}-py${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
+          key: ni-measurementlink-generator-${{ runner.os }}-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
       - name: Install ni-measurementlink-generator
         run: poetry install -v
         working-directory: ./ni_measurementlink_generator