Check whether a Python binary exists for the given py_version and has support. This respects your PATH. For Windows, it will first try to use the py launcher specified in PEP 397. Otherwise (and for all other platforms), it will attempt to check for python .<py_version[
(py_version)
| 48 | return proto |
| 49 | |
| 50 | def have_python_version(py_version): |
| 51 | """Check whether a Python binary exists for the given py_version and has |
| 52 | support. This respects your PATH. |
| 53 | For Windows, it will first try to use the py launcher specified in PEP 397. |
| 54 | Otherwise (and for all other platforms), it will attempt to check for |
| 55 | python<py_version[0]>.<py_version[1]>. |
| 56 | |
| 57 | Eg. given a *py_version* of (3, 7), the function will attempt to try |
| 58 | 'py -3.7' (for Windows) first, then 'python3.7', and return |
| 59 | ['py', '-3.7'] (on Windows) or ['python3.7'] on other platforms. |
| 60 | |
| 61 | Args: |
| 62 | py_version: a 2-tuple of the major, minor version. Eg. python 3.7 would |
| 63 | be (3, 7) |
| 64 | Returns: |
| 65 | List/Tuple containing the Python binary name and its required arguments, |
| 66 | or None if no valid binary names found. |
| 67 | """ |
| 68 | python_str = ".".join(map(str, py_version)) |
| 69 | targets = [('py', f'-{python_str}'), (f'python{python_str}',)] |
| 70 | if py_version not in py_executable_map: |
| 71 | for target in targets[0 if is_windows else 1:]: |
| 72 | try: |
| 73 | worker = subprocess.Popen([*target, '-c', 'pass'], |
| 74 | stdout=subprocess.DEVNULL, |
| 75 | stderr=subprocess.DEVNULL, |
| 76 | shell=is_windows) |
| 77 | worker.communicate() |
| 78 | if worker.returncode == 0: |
| 79 | py_executable_map[py_version] = target |
| 80 | break |
| 81 | except FileNotFoundError: |
| 82 | pass |
| 83 | |
| 84 | return py_executable_map.get(py_version, None) |
| 85 | |
| 86 | |
| 87 | def read_exact(f, n): |
no test coverage detected
searching dependent graphs…