|
2 | 2 | import subprocess |
3 | 3 | import sys |
4 | 4 | import unittest |
5 | | - |
| 5 | +import tempfile |
| 6 | +import os.path |
6 | 7 |
|
7 | 8 | class LocalToolchainTest(unittest.TestCase): |
8 | 9 | maxDiff = None |
9 | 10 |
|
10 | 11 | def test_python_from_path_used(self): |
| 12 | + # NOTE: This is a bit brittle. It assumes the environment during the |
| 13 | + # repo-phase and when the test is run are roughly the same. It's |
| 14 | + # easy to violate this condition if there are shell-local changes |
| 15 | + # that wouldn't be reflected when sub-shells are run later. |
11 | 16 | shell_path = shutil.which("python3") |
12 | 17 |
|
13 | 18 | # We call the interpreter and print its executable because of |
14 | 19 | # things like pyenv: they install a shim that re-execs python. |
15 | 20 | # The shim is e.g. /home/user/.pyenv/shims/python3, which then |
16 | 21 | # runs e.g. /usr/bin/python3 |
17 | | - expected = subprocess.check_output( |
18 | | - [shell_path, "-c", "import os, sys; print(sys._base_executable)"], |
19 | | - text=True, |
20 | | - ) |
21 | | - expected = expected.strip().lower() |
| 22 | + with tempfile.NamedTemporaryFile(suffix="_info.py", mode="w+") as f: |
| 23 | + f.write(""" |
| 24 | +import sys |
| 25 | +print(sys.executable) |
| 26 | +print(sys._base_executable) |
| 27 | +""" |
| 28 | + ) |
| 29 | + f.flush() |
| 30 | + output_lines = subprocess.check_output( |
| 31 | + [shell_path, f.name], |
| 32 | + text=True, |
| 33 | + ).strip().splitlines() |
| 34 | + shell_exe, shell_base_exe = output_lines |
| 35 | + |
| 36 | + # Call realpath() to help normalize away differences from symlinks. |
| 37 | + # Use base executable to ignore a venv the test may be running within. |
| 38 | + expected = os.path.realpath(shell_base_exe.strip().lower()) |
| 39 | + actual = os.path.realpath(sys._base_executable.lower()) |
| 40 | + |
| 41 | + msg = f""" |
| 42 | +details of executables: |
| 43 | +test's runtime: |
| 44 | +{sys.executable=} |
| 45 | +{sys._base_executable=} |
| 46 | +realpath exe : {os.path.realpath(sys.executable)} |
| 47 | +realpath base_exe: {os.path.realpath(sys._base_executable)} |
| 48 | +
|
| 49 | +from shell resolution: |
| 50 | +{shell_exe=} |
| 51 | +{shell_base_exe=} |
| 52 | +realpath exe : {os.path.realpath(shell_exe)} |
| 53 | +realpath base_exe: {os.path.realpath(shell_base_exe)} |
| 54 | +""".strip() |
22 | 55 |
|
23 | 56 | # Normalize case: Windows may have case differences |
24 | | - self.assertEqual(expected.lower(), sys._base_executable.lower()) |
| 57 | + self.assertEqual(expected.lower(), actual.lower(), msg=msg) |
25 | 58 |
|
26 | 59 |
|
27 | 60 | if __name__ == "__main__": |
|
0 commit comments