Repository: pex-tool/pex

Issue:
PEX fails to pass a custom `interpreter` down to `PEXEnvironments` it `_activates`
2 spots:
https://github.com/pantsbuild/pex/blob/master/pex/pex.py#L73
https://github.com/pantsbuild/pex/blob/master/pex/pex.py#L83

The fallout can be incorrect selection of valid platform tags here: https://github.com/pantsbuild/pex/blob/master/pex/environment.py#L127-L129


Discussion:
Found in https://github.com/pantsbuild/pants/pull/6104

Resolving patch:
diff --git a/pex/pex.py b/pex/pex.py
--- a/pex/pex.py
+++ b/pex/pex.py
@@ -73,7 +73,7 @@ def _activate(self):
       pex_info = self._pex_info.copy()
       pex_info.update(self._pex_info_overrides)
       pex_info.merge_pex_path(self._vars.PEX_PATH)
-      self._envs.append(PEXEnvironment(self._pex, pex_info))
+      self._envs.append(PEXEnvironment(self._pex, pex_info, interpreter=self._interpreter))
       # N.B. by this point, `pex_info.pex_path` will contain a single pex path
       # merged from pex_path in `PEX-INFO` and `PEX_PATH` set in the environment.
       # `PEX_PATH` entries written into `PEX-INFO` take precedence over those set
@@ -83,7 +83,7 @@ def _activate(self):
         for pex_path in filter(None, pex_info.pex_path.split(os.pathsep)):
           pex_info = PexInfo.from_pex(pex_path)
           pex_info.update(self._pex_info_overrides)
-          self._envs.append(PEXEnvironment(pex_path, pex_info))
+          self._envs.append(PEXEnvironment(pex_path, pex_info, interpreter=self._interpreter))
 
       # activate all of them
       for env in self._envs:


Test patch:
diff --git a/pex/testing.py b/pex/testing.py
--- a/pex/testing.py
+++ b/pex/testing.py
@@ -153,11 +153,12 @@ def make_sdist(name='my_project', version='0.0.0', zip_safe=True, install_reqs=N
 
 @contextlib.contextmanager
 def make_bdist(name='my_project', version='0.0.0', installer_impl=EggInstaller, zipped=False,
-               zip_safe=True):
+               zip_safe=True, **kwargs):
   with make_installer(name=name,
                       version=version,
                       installer_impl=installer_impl,
-                      zip_safe=zip_safe) as installer:
+                      zip_safe=zip_safe,
+                      **kwargs) as installer:
     dist_location = installer.bdist()
     if zipped:
       yield DistributionHelper.distribution_from_path(dist_location)
diff --git a/tests/test_pex.py b/tests/test_pex.py
--- a/tests/test_pex.py
+++ b/tests/test_pex.py
@@ -10,11 +10,16 @@
 import pytest
 from twitter.common.contextutil import temporary_file
 
-from pex.compatibility import WINDOWS, nested, to_bytes
+from pex.bin.pex import get_interpreter
+from pex.compatibility import PY2, WINDOWS, nested, to_bytes
 from pex.installer import EggInstaller, WheelInstaller
 from pex.pex import PEX
 from pex.pex_builder import PEXBuilder
+from pex.pex_info import PexInfo
 from pex.testing import (
+    IS_PYPY,
+    ensure_python_interpreter,
+    make_bdist,
     make_installer,
     named_temporary_file,
     run_simple_pex_test,
@@ -309,3 +314,31 @@ def test_pex_verify_entry_point_module_should_fail():
       PEX(pex_builder.path(),
           interpreter=pex_builder.interpreter,
           verify_entry_point=True)
+
+
+@pytest.mark.skipif(IS_PYPY)
+def test_activate_interpreter_different_from_current():
+  with temporary_dir() as pex_root:
+    interp_version = '3.6.3' if PY2 else '2.7.10'
+    custom_interpreter = get_interpreter(
+      python_interpreter=ensure_python_interpreter(interp_version),
+      interpreter_cache_dir=os.path.join(pex_root, 'interpreters'),
+      repos=None,  # Default to PyPI.
+      use_wheel=True
+    )
+    pex_info = PexInfo.default(custom_interpreter)
+    pex_info.pex_root = pex_root
+    with temporary_dir() as pex_chroot:
+      pex_builder = PEXBuilder(path=pex_chroot,
+                               interpreter=custom_interpreter,
+                               pex_info=pex_info)
+      with make_bdist(installer_impl=WheelInstaller, interpreter=custom_interpreter) as bdist:
+        pex_builder.add_distribution(bdist)
+        pex_builder.set_entry_point('sys:exit')
+        pex_builder.freeze()
+
+        pex = PEX(pex_builder.path(), interpreter=custom_interpreter)
+        try:
+          pex._activate()
+        except SystemExit as e:
+          pytest.fail('PEX activation of %s failed with %s' % (pex, e))