Skip to content

Commit

Permalink
Fix multiple binary target case and add integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Livingston committed Jan 30, 2018
1 parent 9e0b2d6 commit e8f6b98
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ def _create_binary(self, binary_tgt, results_dir):
built_dists = self.context.products.get_data(BuildLocalPythonDistributions.PYTHON_DISTS)
if built_dists:
for dist in built_dists:
builder.add_dist_location(dist)
# Ensure only python_dist dependencies of binary_tgt are added to the output pex.
# This protects against the case where a single `./pants binary` command builds two
# binary targets that each have their own unique python_dist depencency.
if any([tgt.id in dist for tgt in binary_tgt.closure(exclude_scopes=Scopes.COMPILE)]):
builder.add_dist_location(dist)

# Build the .pex file.
pex_path = os.path.join(results_dir, '{}.pex'.format(binary_tgt.name))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright 2017 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

# Like Hello world, but built with a python_dist.
# python_dist allows you to use setup.py to depend on C/C++ extensions.

python_dist(
name='superhello',
sources=[
'super_greet.c',
'hello_package/hello.py',
'hello_package/__init__.py',
'setup.py'
]
)

python_binary(
name='bin_with_python_dist',
source='main.py',
dependencies=[
':superhello',
]
)


# The targets below are for testing purposes only.
# Their purpose is to expose an error that arises when a python_dist
# contains a requirement that conflicts with the same requirement of
# a different version in the consuming target. In this case, the pants
# goal will fail and indicate that incomptible requirements exist.

python_dist(
name='superhello_with_conflicting_dep',
sources=[
'super_greet.c',
'hello_package/hello.py',
'hello_package/__init__.py',
'setup.py'
],
dependencies=[
':pex_lib'
]
)

python_binary(
name='main_with_conflicting_dep',
source='main.py',
dependencies=[
':superhello_with_conflicting_dep',
'3rdparty/python:pex'
]
)

python_requirement_library(
name='pex_lib',
requirements=[
python_requirement('pex==1.2.11'),
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# coding=utf-8
# Copyright 2017 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from __future__ import (absolute_import, division, generators, nested_scopes, print_function,
unicode_literals, with_statement)

import super_greet

def hello():
print(super_greet.super_greet())
return super_greet.super_greet()
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# coding=utf-8
# Copyright 2017 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from __future__ import (absolute_import, division, generators, nested_scopes, print_function,
unicode_literals, with_statement)

# hello_package is a python module within the superhello python_distribution
from hello_package import hello


if __name__ == '__main__':
hello.hello()
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# coding=utf-8
# Copyright 2017 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from __future__ import (absolute_import, division, generators, nested_scopes, print_function,
unicode_literals, with_statement)

from setuptools import setup, find_packages
from distutils.core import Extension


c_module = Extension(str('super_greet'), sources=[str('super_greet.c')])

setup(
name='superhello',
version='1.0.0',
ext_modules=[c_module],
packages=find_packages(),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <Python.h>

static PyObject * super_greet(PyObject *self, PyObject *args) {
return Py_BuildValue("s", "A different Super hello");
}

static PyMethodDef Methods[] = {
{"super_greet", super_greet, METH_VARARGS, "A super greeting"},
{NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC initsuper_greet(void) {
(void) Py_InitModule("super_greet", Methods);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,69 +17,61 @@ class PythonDistributionIntegrationTest(PantsRunIntegrationTest):
# whl by setup.py) and an associated test to be consumed by the pants goals tested below.
superhello_project = 'examples/src/python/example/python_distribution/hello/superhello'
superhello_tests = 'examples/tests/python/example/python_distribution/hello/test_superhello'
superhello_testprojects_project = 'testprojects/src/python/python_targets/python_distribution/superhello'

def test_pants_binary(self):
self._maybe_test_pants_binary('2.7')
command=['binary', '{}:main'.format(self.superhello_project)]
pants_run_27 = self.run_pants(command=command)
self.assert_success(pants_run_27)
# Check that the pex was built.
pex = os.path.join(get_buildroot(), 'dist', 'main.pex')
self.assertTrue(os.path.isfile(pex))
# Check that the pex runs.
output = subprocess.check_output(pex)
self.assertIn('Super hello', output)
# Cleanup
os.remove(pex)

def test_pants_run(self):
self._maybe_test_pants_binary('2.7')
command=['run', '{}:main'.format(self.superhello_project)]
pants_run_27 = self.run_pants(command=command)
self.assert_success(pants_run_27)
# Check that text was properly printed to stdout.
self.assertIn('Super hello', pants_run_27.stdout_data)

def test_pants_test(self):
self._maybe_test_pants_test('2.7')
command=['test', '{}:superhello'.format(self.superhello_tests)]
pants_run_27 = self.run_pants(command=command)
self.assert_success(pants_run_27)

def test_python_distribution_integration_with_conflicting_deps(self):
self._maybe_test_with_conflicting_deps('2.7')
def test_with_conflicting_deps(self):
command=['run', '{}:main_with_conflicting_dep'.format(self.superhello_project)]
pants_run_27 = self.run_pants(command=command)
self.assert_failure(pants_run_27)
self.assertIn('Exception message: Could not satisfy all requirements', pants_run_27.stderr_data)
command=['binary', '{}:main_with_conflicting_dep'.format(self.superhello_project)]
pants_run_27 = self.run_pants(command=command)
self.assert_failure(pants_run_27)
self.assertIn('Exception message: Could not satisfy all requirements', pants_run_27.stderr_data)

def _maybe_test_pants_binary(self, version):
if self.has_python_version(version):
print('Found python {}. Testing running on it.'.format(version))
command=['binary', '{}:main'.format(self.superhello_project)]
pants_run_27 = self.run_pants(command=command)
self.assert_success(pants_run_27)
# Check that the pex was built.
pex = os.path.join(get_buildroot(), 'dist', 'main.pex')
self.assertTrue(os.path.isfile(pex))
# Check that the pex runs.
output = subprocess.check_output(pex)
self.assertIn('Super hello', output)
else:
print('No python {} found. Skipping.'.format(version))
self.skipTest('No python {} on system'.format(version))

def _maybe_test_pants_run(self, version):
if self.has_python_version(version):
print('Found python {}. Testing running on it.'.format(version))
command=['run', '{}:main'.format(self.superhello_project)]
pants_run_27 = self.run_pants(command=command)
self.assert_success(pants_run_27)
# Check that text was properly printed to stdout.
self.assertIn('Super hello', pants_run_27.stdout_data)
else:
print('No python {} found. Skipping.'.format(version))
self.skipTest('No python {} on system'.format(version))

def _maybe_test_pants_test(self, version):
if self.has_python_version(version):
print('Found python {}. Testing running on it.'.format(version))
command=['test', '{}:superhello'.format(self.superhello_tests)]
pants_run_27 = self.run_pants(command=command)
self.assert_success(pants_run_27)
else:
print('No python {} found. Skipping.'.format(version))
self.skipTest('No python {} on system'.format(version))

def _maybe_test_with_conflicting_deps(self, version):
if self.has_python_version(version):
# Test pants run.
command=['run', '{}:main_with_conflicting_dep'.format(self.superhello_project)]
pants_run_27 = self.run_pants(command=command)
self.assert_failure(pants_run_27)
self.assertIn('Exception message: Could not satisfy all requirements', pants_run_27.stderr_data)
# Test pants binary.
command=['binary', '{}:main_with_conflicting_dep'.format(self.superhello_project)]
pants_run_27 = self.run_pants(command=command)
self.assert_failure(pants_run_27)
self.assertIn('Exception message: Could not satisfy all requirements', pants_run_27.stderr_data)
else:
print('No python {} found. Skipping.'.format(version))
self.skipTest('No python {} on system'.format(version))
def test_pants_binary_with_two_targets(self):
# Test that targets with unique python_dist dependencies only build with their specific
# listed python_dist dependencies (i.e. that built dist products are filtered properly).
command=['binary', '{}:main'.format(self.superhello_project), '{}:bin_with_python_dist'.format(self.superhello_testprojects_project)]
pants_run_27 = self.run_pants(command=command)
self.assert_success(pants_run_27)
# Check that the pex was built.
pex = os.path.join(get_buildroot(), 'dist', 'main.pex')
self.assertTrue(os.path.isfile(pex))
# Check that the pex runs.
output = subprocess.check_output(pex)
self.assertIn('Super hello', output)
# Check that the pex was built.
pex2 = os.path.join(get_buildroot(), 'dist', 'bin_with_python_dist.pex')
self.assertTrue(os.path.isfile(pex2))
# Check that the pex runs.
output = subprocess.check_output(pex2)
self.assertIn('A different Super hello', output)
# Cleanup
os.remove(pex)
os.remove(pex2)

0 comments on commit e8f6b98

Please sign in to comment.