(
version, # type: str
python_version=None, # type: Optional[str]
allow_adhoc_version=False, # type: bool
)
| 726 | |
| 727 | |
| 728 | def ensure_python_distribution( |
| 729 | version, # type: str |
| 730 | python_version=None, # type: Optional[str] |
| 731 | allow_adhoc_version=False, # type: bool |
| 732 | ): |
| 733 | # type: (...) -> PyenvPythonDistribution |
| 734 | if not allow_adhoc_version and version not in ALL_PY_VERSIONS: |
| 735 | raise ValueError("Please constrain version to one of {}".format(ALL_PY_VERSIONS)) |
| 736 | |
| 737 | if WINDOWS and _ALL_PY_VERSIONS_TO_VERSION_INFO[version][:2] < (3, 8): |
| 738 | pytest.skip( |
| 739 | "Test uses pyenv {version} interpreter which is not supported on Windows.".format( |
| 740 | version=version |
| 741 | ) |
| 742 | ) |
| 743 | |
| 744 | clone_dir = os.path.abspath( |
| 745 | os.path.join(PEX_TEST_DEV_ROOT, "pyenv-win" if WINDOWS else "pyenv") |
| 746 | ) |
| 747 | with atomic_directory(target_dir=clone_dir) as pyenv_root_atomic_dir: |
| 748 | if not pyenv_root_atomic_dir.is_finalized(): |
| 749 | bootstrap_python_installer(pyenv_root_atomic_dir.work_dir) |
| 750 | |
| 751 | pyenv_root = os.path.join(clone_dir, "pyenv-win") if WINDOWS else clone_dir |
| 752 | pyenv = os.path.join(pyenv_root, "bin", "pyenv.bat" if WINDOWS else "pyenv") |
| 753 | |
| 754 | interpreter_location = os.path.join(pyenv_root, "versions", version) |
| 755 | pip = os.path.join(interpreter_location, SCRIPT_DIR, script_name("pip")) |
| 756 | |
| 757 | if WINDOWS: |
| 758 | python = os.path.join(interpreter_location, "python.exe") |
| 759 | else: |
| 760 | major, minor = (python_version or version).split(".")[:2] |
| 761 | python = os.path.join( |
| 762 | interpreter_location, "bin", "python{major}.{minor}".format(major=major, minor=minor) |
| 763 | ) |
| 764 | |
| 765 | with atomic_directory(target_dir=interpreter_location) as interpreter_target_dir: |
| 766 | if not interpreter_target_dir.is_finalized(): |
| 767 | with pyenv_root_atomic_dir.locked(): |
| 768 | subprocess.check_call(args=["git", "pull", "--ff-only"], cwd=pyenv_root) |
| 769 | |
| 770 | env = os.environ.copy() |
| 771 | env["PYENV_ROOT"] = pyenv_root |
| 772 | env["CFLAGS"] = "-std=c11" |
| 773 | if sys.platform.lower().startswith("linux"): |
| 774 | env["CONFIGURE_OPTS"] = "--enable-shared" |
| 775 | # The pyenv builder detects `--enable-shared` and sets up `RPATH` via |
| 776 | # `LDFLAGS=-Wl,-rpath=... $LDFLAGS` to ensure the built python binary links the |
| 777 | # correct libpython shared lib. Some versions of compiler set the `RUNPATH` instead |
| 778 | # though which is searched _after_ the `LD_LIBRARY_PATH` environment variable. To |
| 779 | # ensure an inopportune `LD_LIBRARY_PATH` doesn't fool the pyenv python binary into |
| 780 | # linking the wrong libpython, force `RPATH`, which is searched 1st by the linker, |
| 781 | # with `--disable-new-dtags`. |
| 782 | env["LDFLAGS"] = "-Wl,--disable-new-dtags" |
| 783 | subprocess.check_call([pyenv, "install", version], env=env) |
| 784 | subprocess.check_call([python, "-m", "pip", "install", "-U", "pip<22.1"]) |
| 785 |
searching dependent graphs…