-
-
Notifications
You must be signed in to change notification settings - Fork 635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove direct pex imports from the codebase #21515
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
Comment on lines
+228
to
+261
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This involves reading the pexrc file, which kind of explains why we were directly importing from pex before. I'm not sure if it's worth keeping a hard dependency just for this, but maybe it is in case that logic changes in the future. |
||
|
||
|
||
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") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (I didn't know |
||
if ppp: | ||
return ppp.split(os.pathsep) | ||
else: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note - this does subtly change because we are no longer using Pex to hard-pin the patch version of Python in this constraint; we only pin the minor version. That could potentially be a problem if this behavior is particularly material to the test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Subtly changing the behavior of the test, no the plugin resovler itself. Correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct, behavior of the test. Before, the interpreter constraints for the test would be targeting a specific patch version (inferred from the environment) rather than a minor version. |
||
) | ||
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: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not as part of this PR, but after seeing the errors, thoughts on the LoE to remove the test dependency? Eventually I think we will want to consider using the scie Pex distributions instead of the PyPI wheels.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the main thing that is required to get these tests working without the dependency is finding a way to get pex inside the sandbox without explicitly requiring it. We may be able to potentially find another way to do that, but that's the crux issue for why these tests fail.
I'm not opposed to doing it as part of this PR, I just need to figure out HOW to do it.