diff --git a/src/python/pants/backend/python/util_rules/BUILD b/src/python/pants/backend/python/util_rules/BUILD index 6c2224f9d40..2b49775b0ba 100644 --- a/src/python/pants/backend/python/util_rules/BUILD +++ b/src/python/pants/backend/python/util_rules/BUILD @@ -13,7 +13,7 @@ python_tests( name="tests", overrides={ "local_dists_test.py": {"timeout": 120}, - "pex_from_targets_test.py": {"timeout": 200}, + "pex_from_targets_test.py": {"timeout": 200, "dependencies": ["3rdparty/python#pex"]}, "pex_test.py": {"timeout": 600, "dependencies": [":complete_platform_pex_test"]}, "package_dists_test.py": {"timeout": 150}, "vcs_versioning_test.py": {"timeout": 120}, diff --git a/src/python/pants/core/subsystems/python_bootstrap.py b/src/python/pants/core/subsystems/python_bootstrap.py index 6a4743af0ee..50bf0e77aa7 100644 --- a/src/python/pants/core/subsystems/python_bootstrap.py +++ b/src/python/pants/core/subsystems/python_bootstrap.py @@ -6,10 +6,9 @@ import itertools import logging import os +import sys from dataclasses import dataclass -from typing import Collection - -from pex.variables import Variables +from typing import Collection, Optional from pants.core.util_rules import asdf, search_paths from pants.core.util_rules.asdf import AsdfPathString, AsdfToolPathsResult @@ -226,13 +225,49 @@ async def _expand_interpreter_search_paths( return _SearchPaths(tuple(expanded)) +# This method is copied from the pex package, located at pex.variables.Variables._get_kv(). +# It is copied here to avoid a hard dependency on pex. +def _get_kv(variable: str) -> Optional[list[str]]: + kv = variable.strip().split("=") + if len(list(filter(None, kv))) == 2: + return kv + else: + return None + + +# This method is copied from the pex package, located at pex.variables.Variables.from_rc(). +# It is copied here to avoid a hard dependency on pex. +def _read_pex_rc(rc: Optional[str] = None) -> dict[str, str]: + """Read pex runtime configuration variables from a pexrc file. + + :param rc: an absolute path to a pexrc file. + :return: A dict of key value pairs found in processed pexrc files. + """ + ret_vars = {} + rc_locations = [ + os.path.join(os.sep, "etc", "pexrc"), + os.path.join("~", ".pexrc"), + os.path.join(os.path.dirname(sys.argv[0]), ".pexrc"), + ] + if rc: + rc_locations.append(rc) + for filename in rc_locations: + try: + with open(os.path.expanduser(filename)) as fh: + rc_items = map(_get_kv, fh) + ret_vars.update(dict(filter(None, rc_items))) + except OSError: + continue + return ret_vars + + def _get_pex_python_paths(): """Returns a list of paths to Python interpreters as defined in a pexrc file. These are provided by a PEX_PYTHON_PATH in either of '/etc/pexrc', '~/.pexrc'. PEX_PYTHON_PATH defines a colon-separated list of paths to interpreters that a pex can be built and run against. """ - ppp = Variables.from_rc().get("PEX_PYTHON_PATH") + ppp = _read_pex_rc().get("PEX_PYTHON_PATH") if ppp: return ppp.split(os.pathsep) else: diff --git a/tests/python/pants_test/init/test_plugin_resolver.py b/tests/python/pants_test/init/test_plugin_resolver.py index f0445cf9e98..21e2162296a 100644 --- a/tests/python/pants_test/init/test_plugin_resolver.py +++ b/tests/python/pants_test/init/test_plugin_resolver.py @@ -13,7 +13,6 @@ from typing import Dict, Iterable, Sequence import pytest -from pex.interpreter import PythonInterpreter from pkg_resources import Distribution, Requirement, WorkingSet from pants.backend.python.util_rules import pex @@ -31,7 +30,6 @@ from pants.testutil.python_interpreter_selection import ( PY_38, PY_39, - python_interpreter_path, skip_unless_python38_and_python39_present, ) from pants.testutil.rule_runner import EXECUTOR, QueryRule, RuleRunner @@ -125,7 +123,7 @@ class Plugin: def plugin_resolution( rule_runner: RuleRunner, *, - interpreter: PythonInterpreter | None = None, + python_version: str | None = None, chroot: str | None = None, plugins: Sequence[Plugin] = (), requirements: Iterable[str] = (), @@ -143,7 +141,7 @@ def provide_chroot(existing): # Default to resolving with whatever we're currently running with. interpreter_constraints = ( - InterpreterConstraints([f"=={interpreter.identity.version_str}"]) if interpreter else None + InterpreterConstraints([f"=={python_version}.*"]) if python_version else None ) artifact_interpreter_constraints = interpreter_constraints or InterpreterConstraints( [f"=={'.'.join(map(str, sys.version_info[:3]))}"] @@ -301,12 +299,9 @@ def test_exact_requirements_interpreter_change_bdist(rule_runner: RuleRunner) -> def _do_test_exact_requirements_interpreter_change(rule_runner: RuleRunner, sdist: bool) -> None: - python38 = PythonInterpreter.from_binary(python_interpreter_path(PY_38)) - python39 = PythonInterpreter.from_binary(python_interpreter_path(PY_39)) - with plugin_resolution( rule_runner, - interpreter=python38, + python_version=PY_38, plugins=[Plugin("jake", "1.2.3"), Plugin("jane", "3.4.5")], sdist=sdist, ) as results: @@ -316,7 +311,7 @@ def _do_test_exact_requirements_interpreter_change(rule_runner: RuleRunner, sdis with pytest.raises(ExecutionError): with plugin_resolution( rule_runner, - interpreter=python39, + python_version=PY_39, chroot=chroot, plugins=[Plugin("jake", "1.2.3"), Plugin("jane", "3.4.5")], ): @@ -333,7 +328,7 @@ def _do_test_exact_requirements_interpreter_change(rule_runner: RuleRunner, sdis # directly from the still in-tact cache. with plugin_resolution( rule_runner, - interpreter=python38, + python_version=PY_38, chroot=chroot, plugins=[Plugin("jake", "1.2.3"), Plugin("jane", "3.4.5")], ) as results2: