Skip to content

Commit

Permalink
Fixup PEX.demote_bootstrap: fully unimport. (#554)
Browse files Browse the repository at this point in the history
Previously only root 3rdparty packages copied into the bootstrap were
unimported leaving subpackages in-place. This could lead to a mismatch
in 3rdparty package API expectations when a re-imported 3rdparty root
package from the user PEX sys.path was from a different version of the
3rdparty package.

Fixes #550
  • Loading branch information
jsirois authored Sep 25, 2018
1 parent 64d2cd3 commit 479bd5f
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 2 deletions.
3 changes: 3 additions & 0 deletions pex/pex.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,9 @@ def demote_bootstrap(cls):
TRACER.log('Un-importing third party bootstrap dependency %s from %s'
% (mod, bootstrap_path))
sys.modules.pop(mod)
submod_prefix = mod + '.'
for submod in [m for m in sys.modules.keys() if m.startswith(submod_prefix)]:
sys.modules.pop(submod)
sys.path.pop(bootstrap_path_index)
sys.path.append(bootstrap_path)

Expand Down
7 changes: 5 additions & 2 deletions pex/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def make_bdist(name='my_project', version='0.0.0', installer_impl=EggInstaller,
"""


def write_simple_pex(td, exe_contents, dists=None, sources=None, coverage=False):
def write_simple_pex(td, exe_contents, dists=None, sources=None, coverage=False, interpreter=None):
"""Write a pex file that contains an executable entry point
:param td: temporary directory path
Expand All @@ -189,6 +189,7 @@ def write_simple_pex(td, exe_contents, dists=None, sources=None, coverage=False)
:param dists: distributions to include, typically sdists or bdists
:param sources: sources to include, as a list of pairs (env_filename, contents)
:param coverage: include coverage header
:param interpreter: a custom interpreter to use to build the pex
"""
dists = dists or []
sources = sources or []
Expand All @@ -198,7 +199,9 @@ def write_simple_pex(td, exe_contents, dists=None, sources=None, coverage=False)
with open(os.path.join(td, 'exe.py'), 'w') as fp:
fp.write(exe_contents)

pb = PEXBuilder(path=td, preamble=COVERAGE_PREAMBLE if coverage else None)
pb = PEXBuilder(path=td,
preamble=COVERAGE_PREAMBLE if coverage else None,
interpreter=interpreter)

for dist in dists:
pb.add_dist_location(dist.location)
Expand Down
27 changes: 27 additions & 0 deletions tests/test_pex.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from pex.bin.pex import get_interpreter
from pex.compatibility import PY2, WINDOWS, nested, to_bytes
from pex.installer import EggInstaller, WheelInstaller
from pex.interpreter import PythonInterpreter
from pex.pex import PEX
from pex.pex_builder import PEXBuilder
from pex.pex_info import PexInfo
Expand Down Expand Up @@ -373,3 +374,29 @@ def test_pex_run_custom_setuptools_useable():
)
rc = PEX(pex.path()).run()
assert rc == 0


def test_pex_run_conflicting_custom_setuptools_useable():
# Here we use an older setuptools to build the pex which has a newer setuptools requirement.
# These setuptools dists have different pkg_resources APIs:
# $ diff \
# <(zipinfo -1 setuptools-20.3.1-py2.py3-none-any.whl | grep pkg_resources/ | sort) \
# <(zipinfo -1 setuptools-40.4.3-py2.py3-none-any.whl | grep pkg_resources/ | sort)
# 2a3,4
# > pkg_resources/py31compat.py
# > pkg_resources/_vendor/appdirs.py
with temporary_dir() as resolve_cache:
dists = resolve(['setuptools==20.3.1'], cache=resolve_cache)
interpreter = PythonInterpreter.from_binary(sys.executable,
path_extras=[dist.location for dist in dists],
include_site_extras=False)
dists = resolve(['setuptools==40.4.3'], cache=resolve_cache)
with temporary_dir() as temp_dir:
pex = write_simple_pex(
temp_dir,
'from pkg_resources import appdirs, py31compat',
dists=dists,
interpreter=interpreter
)
rc = PEX(pex.path()).run()
assert rc == 0

0 comments on commit 479bd5f

Please sign in to comment.