Skip to content

Commit

Permalink
Fix installers to be insensitive to extras iteration order. (#532)
Browse files Browse the repository at this point in the history
Fixes #158
  • Loading branch information
jsirois authored Jul 28, 2018
1 parent d1f946c commit 685757e
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 5 deletions.
13 changes: 10 additions & 3 deletions pex/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def function_wrapper(self, *args, **kw):

class InstallerBase(object):
SETUP_BOOTSTRAP_HEADER = "import sys"
SETUP_BOOTSTRAP_MODULE = "sys.path.insert(0, %(path)r); import %(module)s"
SETUP_BOOTSTRAP_PYPATH = "sys.path.insert(0, %(path)r)"
SETUP_BOOTSTRAP_MODULE = "import %(module)s"
SETUP_BOOTSTRAP_FOOTER = """
__file__ = 'setup.py'
sys.argv[0] = 'setup.py'
Expand Down Expand Up @@ -85,15 +86,21 @@ def capability(self):

@property
def bootstrap_script(self):
bootstrap_sys_paths = []
bootstrap_modules = []
for module, requirement in self.mixins().items():
path = self._interpreter.get_location(requirement)
if not path:
assert not self._strict # This should be caught by validation
continue
bootstrap_modules.append(self.SETUP_BOOTSTRAP_MODULE % {'path': path, 'module': module})
bootstrap_sys_paths.append(self.SETUP_BOOTSTRAP_PYPATH % {'path': path})
bootstrap_modules.append(self.SETUP_BOOTSTRAP_MODULE % {'module': module})
return '\n'.join(
[self.SETUP_BOOTSTRAP_HEADER] + bootstrap_modules + [self.SETUP_BOOTSTRAP_FOOTER])
[self.SETUP_BOOTSTRAP_HEADER] +
bootstrap_sys_paths +
bootstrap_modules +
[self.SETUP_BOOTSTRAP_FOOTER]
)

def run(self):
if self._installed is not None:
Expand Down
4 changes: 2 additions & 2 deletions pex/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ def write_zipfile(directory, dest, reverse=False):

@contextlib.contextmanager
def make_installer(name='my_project', version='0.0.0', installer_impl=EggInstaller, zip_safe=True,
install_reqs=None):
install_reqs=None, **kwargs):
interp = {'project_name': name,
'version': version,
'zip_safe': zip_safe,
'install_requires': install_reqs or []}
with temporary_content(PROJECT_CONTENT, interp=interp) as td:
yield installer_impl(td)
yield installer_impl(td, **kwargs)


@contextlib.contextmanager
Expand Down
60 changes: 60 additions & 0 deletions tests/test_installer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright 2018 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
import contextlib
from collections import OrderedDict

import pytest

from pex.bin.pex import get_interpreter
from pex.installer import WheelInstaller
from pex.testing import ensure_python_interpreter, make_installer, temporary_dir
from pex.version import SETUPTOOLS_REQUIREMENT, WHEEL_REQUIREMENT


class OrderableInstaller(WheelInstaller):
def __init__(self, source_dir, strict=True, interpreter=None, install_dir=None, mixins=None):
self._mixins = mixins
super(OrderableInstaller, self).__init__(source_dir, strict, interpreter, install_dir)

def mixins(self):
return self._mixins


@contextlib.contextmanager
def bare_interpreter():
with temporary_dir() as interpreter_cache:
yield get_interpreter(
python_interpreter=ensure_python_interpreter('3.6.3'),
interpreter_cache_dir=interpreter_cache,
repos=None,
use_wheel=True
)


@contextlib.contextmanager
def wheel_installer(*mixins):
with bare_interpreter() as interpreter:
with make_installer(installer_impl=OrderableInstaller,
interpreter=interpreter,
mixins=OrderedDict(mixins)) as installer:
yield installer


WHEEL_EXTRA = ('wheel', WHEEL_REQUIREMENT)
SETUPTOOLS_EXTRA = ('setuptools', SETUPTOOLS_REQUIREMENT)


def test_wheel_before_setuptools():
with wheel_installer(WHEEL_EXTRA, SETUPTOOLS_EXTRA) as installer:
installer.bdist()


def test_setuptools_before_wheel():
with wheel_installer(SETUPTOOLS_EXTRA, WHEEL_EXTRA) as installer:
installer.bdist()


def test_no_wheel():
with wheel_installer(SETUPTOOLS_EXTRA) as installer:
with pytest.raises(installer.InstallFailure):
installer.bdist()

0 comments on commit 685757e

Please sign in to comment.