From f8b14d0e5dda302ad305cbead941cfb3ea031189 Mon Sep 17 00:00:00 2001 From: Andy Freeland Date: Tue, 5 Jul 2016 20:12:48 -0700 Subject: [PATCH 1/3] Failing test for #137 --- tests/test_integration.py | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index f68159711..898561b28 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -3,13 +3,15 @@ import os import sys +from textwrap import dedent import pytest from twitter.common.contextutil import environment_as, temporary_dir from pex.compatibility import WINDOWS -from pex.testing import run_pex_command, run_simple_pex_test -from pex.util import named_temporary_file +from pex.installer import EggInstaller +from pex.testing import run_pex_command, run_simple_pex_test, temporary_content +from pex.util import DistributionHelper, named_temporary_file def test_pex_execute(): @@ -88,3 +90,31 @@ def test_pex_python_symlink(): body = "print('Hello')" _, rc = run_simple_pex_test(body, coverage=True) assert rc == 0 + + +def test_entry_point_exit_code(): + setup_py = dedent(""" + from setuptools import setup + + setup( + name='my_app', + version='0.0.0', + zip_safe=True, + packages=[''], + entry_points={'console_scripts': ['my_app = my_app:do_something']}, + ) + """) + + error_msg = 'setuptools expects this to exit non-zero' + + my_app = dedent(""" + def do_something(): + return '%s' + """ % error_msg) + + with temporary_content({'setup.py': setup_py, 'my_app.py': my_app}) as project_dir: + installer = EggInstaller(project_dir) + dist = DistributionHelper.distribution_from_path(installer.bdist()) + so, rc = run_simple_pex_test('', env={'PEX_SCRIPT': 'my_app'}, dists=[dist]) + assert so.decode('utf-8').strip() == error_msg + assert rc == 1 From 4134578fb04c8d4f28f7e75d0a7b7d2c3c3b5d23 Mon Sep 17 00:00:00 2001 From: Andy Freeland Date: Tue, 5 Jul 2016 19:20:48 -0700 Subject: [PATCH 2/3] Don't ignore exit codes when using setuptools entry points Setuptools does not require `console_scripts` entry points to call `sys.exit()` (or similar) to exit non-zero: The functions you specify are called with no arguments, and their return value is passed to `sys.exit()`, so you can return an errorlevel or message to print to stderr This patch updates pex to follow the same behavior. Fixes #137. --- pex/pex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pex/pex.py b/pex/pex.py index 0d5f10876..c37168656 100644 --- a/pex/pex.py +++ b/pex/pex.py @@ -444,7 +444,7 @@ def execute_pkg_resources(spec): else: # setuptools < 11.3 runner = entry.load(require=False) - runner() + sys.exit(runner()) def cmdline(self, args=()): """The commandline to run this environment. From 9fb166669f334430cd1f730ef65484a099d6fe2a Mon Sep 17 00:00:00 2001 From: Andy Freeland Date: Wed, 6 Jul 2016 19:45:08 -0700 Subject: [PATCH 3/3] Exit from PEX.execute_script() --- pex/pex.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pex/pex.py b/pex/pex.py index c37168656..f5cf0bd24 100644 --- a/pex/pex.py +++ b/pex/pex.py @@ -391,7 +391,7 @@ def execute_script(self, script_name): entry_point = get_entry_point_from_console_script(script_name, dists) if entry_point: - return self.execute_entry(entry_point) + sys.exit(self.execute_entry(entry_point)) dist, script_path, script_content = get_script_from_distributions(script_name, dists) if not dist: @@ -426,7 +426,7 @@ def execute_content(cls, name, content, argv0=None): @classmethod def execute_entry(cls, entry_point): runner = cls.execute_pkg_resources if ':' in entry_point else cls.execute_module - runner(entry_point) + return runner(entry_point) @staticmethod def execute_module(module_name): @@ -444,7 +444,7 @@ def execute_pkg_resources(spec): else: # setuptools < 11.3 runner = entry.load(require=False) - sys.exit(runner()) + return runner() def cmdline(self, args=()): """The commandline to run this environment.