Skip to content

Commit 983589a

Browse files
authored
Support -c for plat spec dists in multiplat pexes. (#545)
* Support -c for plat spec dists in multiplat pexes. Fixes #537
1 parent 927433a commit 983589a

File tree

6 files changed

+70
-14
lines changed

6 files changed

+70
-14
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ matrix:
6161
env: TOXENV=pypy-integration
6262

6363
install:
64-
- pip install -U tox "setuptools<34"
64+
- pip install -U tox "setuptools>=36"
6565

6666
script:
6767
- ./scripts/ci.sh

pex/finders.py

+14-9
Original file line numberDiff line numberDiff line change
@@ -293,17 +293,22 @@ def get_script_from_distributions(name, dists):
293293

294294

295295
def get_entry_point_from_console_script(script, dists):
296-
# check all distributions for the console_script "script"
297-
entries = frozenset(filter(None, (
298-
dist.get_entry_map().get('console_scripts', {}).get(script) for dist in dists)))
296+
# Check all distributions for the console_script "script". De-dup by dist key to allow for a
297+
# duplicate console script IFF the distribution is platform-specific and this is a multi-platform
298+
# pex.
299+
def get_entrypoint(dist):
300+
script_entry = dist.get_entry_map().get('console_scripts', {}).get(script)
301+
if script_entry is not None:
302+
# Entry points are of the form 'foo = bar', we just want the 'bar' part.
303+
return dist.key, str(script_entry).split('=')[1].strip()
304+
305+
entries = frozenset(filter(None, (get_entrypoint(dist) for dist in dists)))
299306

300-
# if multiple matches, freak out
301307
if len(entries) > 1:
302308
raise RuntimeError(
303-
'Ambiguous script specification %s matches multiple entry points:%s' % (
304-
script, ' '.join(map(str, entries))))
309+
'Ambiguous script specification %s matches multiple entry points:\n\t%s' % (
310+
script, '\n\t'.join('%s from %s' % (entry_point, key) for key, entry_point in entries)))
305311

306312
if entries:
307-
entry_point = next(iter(entries))
308-
# entry points are of the form 'foo = bar', we just want the 'bar' part:
309-
return str(entry_point).split('=')[1].strip()
313+
_, entry_point = next(iter(entries))
314+
return entry_point

pex/testing.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,9 @@ def ensure_python_distribution(version):
330330
bootstrap_python_installer(pyenv_root)
331331

332332
if not os.path.exists(interpreter_location):
333-
os.environ['PYENV_ROOT'] = pyenv_root
334-
subprocess.check_call([pyenv, 'install', '--keep', version])
333+
env = {'PYENV_ROOT': pyenv_root,
334+
'CONFIGURE_OPTS': '--enable-shared'}
335+
subprocess.check_call([pyenv, 'install', '--keep', version], env=env)
335336
subprocess.check_call([pip, 'install', '-U', 'pip'])
336337
subprocess.check_call([pip, 'install', SETUPTOOLS_REQUIREMENT])
337338

tests/test_finders.py

+31-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
import zipimport
55

66
import pkg_resources
7+
import pytest
78

89
from pex.finders import ChainedFinder
910
from pex.finders import _add_finder as add_finder
1011
from pex.finders import _remove_finder as remove_finder
11-
from pex.finders import find_eggs_in_zip, get_script_from_egg
12+
from pex.finders import find_eggs_in_zip, get_entry_point_from_console_script, get_script_from_egg
1213

1314
try:
1415
import mock
@@ -118,3 +119,32 @@ def test_get_script_from_egg():
118119

119120
assert location is None
120121
assert content is None
122+
123+
124+
class FakeDist(object):
125+
def __init__(self, key, console_script_entry):
126+
self.key = key
127+
script = console_script_entry.split('=')[0].strip()
128+
self._entry_map = {'console_scripts': {script: console_script_entry}}
129+
130+
def get_entry_map(self):
131+
return self._entry_map
132+
133+
134+
def test_get_entry_point_from_console_script():
135+
dists = [FakeDist(key='fake', console_script_entry='bob= bob.main:run'),
136+
FakeDist(key='fake', console_script_entry='bob =bob.main:run')]
137+
assert 'bob.main:run' == get_entry_point_from_console_script('bob', dists)
138+
139+
140+
def test_get_entry_point_from_console_script_conflict():
141+
dists = [FakeDist(key='bob', console_script_entry='bob= bob.main:run'),
142+
FakeDist(key='fake', console_script_entry='bob =bob.main:run')]
143+
with pytest.raises(RuntimeError):
144+
get_entry_point_from_console_script('bob', dists)
145+
146+
147+
def test_get_entry_point_from_console_script_dne():
148+
dists = [FakeDist(key='bob', console_script_entry='bob= bob.main:run'),
149+
FakeDist(key='fake', console_script_entry='bob =bob.main:run')]
150+
assert None is get_entry_point_from_console_script('jane', dists)

tests/test_integration.py

+20
Original file line numberDiff line numberDiff line change
@@ -981,3 +981,23 @@ def test_invalid_entry_point_verification_3rdparty():
981981
'-o', pex_out_path,
982982
'--validate-entry-point'])
983983
res.assert_failure()
984+
985+
986+
@pytest.mark.skipif(IS_PYPY)
987+
def test_multiplatform_entrypoint():
988+
with temporary_dir() as td:
989+
pex_out_path = os.path.join(td, 'p537.pex')
990+
interpreter = ensure_python_interpreter('3.6.3')
991+
res = run_pex_command(['p537==1.0.3',
992+
'--no-build',
993+
'--python={}'.format(interpreter),
994+
'--python-shebang=#!{}'.format(interpreter),
995+
'--platform=linux-x86_64',
996+
'--platform=macosx-10.13-x86_64',
997+
'-c', 'p537',
998+
'-o', pex_out_path,
999+
'--validate-entry-point'])
1000+
res.assert_success()
1001+
1002+
greeting = subprocess.check_output([pex_out_path])
1003+
assert b'Hello World!' == greeting.strip()

tox.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ commands =
1111
# Ensure pex's main entrypoint can be run externally.
1212
pex --cache-dir {envtmpdir}/buildcache wheel requests . -e pex.bin.pex:main --version
1313
deps =
14-
pytest==3.6.0
14+
pytest==3.7.2
1515
twitter.common.contextutil>=0.3.1,<0.4.0
1616
twitter.common.dirutil>=0.3.1,<0.4.0
1717
twitter.common.lang>=0.3.1,<0.4.0

0 commit comments

Comments
 (0)