summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAdam J. Stewart <ajstewart426@gmail.com>2017-03-31 15:39:07 -0500
committerTodd Gamblin <tgamblin@llnl.gov>2017-03-31 13:39:07 -0700
commitbc404532ea875ecc6982d049dc7c7f041aa74443 (patch)
treed3fc3694c24c7cf2a7d259481291482030bd5a89 /lib
parent3ade829566a00e6bcb542c5af27f107a6e45d50e (diff)
downloadspack-bc404532ea875ecc6982d049dc7c7f041aa74443.tar.gz
spack-bc404532ea875ecc6982d049dc7c7f041aa74443.tar.bz2
spack-bc404532ea875ecc6982d049dc7c7f041aa74443.tar.xz
spack-bc404532ea875ecc6982d049dc7c7f041aa74443.zip
PythonPackage: Let There Be Tests! (#2869)
* Run python setup.py test if --run-tests * Attempt to import the Python module after installation * Add testing support to numpy and scipy * Remove duplicated comments * Update to new run-tests callback methodology * Remove unrelated changes for another PR
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/build_systems/python.py80
-rw-r--r--lib/spack/spack/util/executable.py2
2 files changed, 75 insertions, 7 deletions
diff --git a/lib/spack/spack/build_systems/python.py b/lib/spack/spack/build_systems/python.py
index d2ee72925d..2c8ccebae6 100644
--- a/lib/spack/spack/build_systems/python.py
+++ b/lib/spack/spack/build_systems/python.py
@@ -24,6 +24,7 @@
##############################################################################
import inspect
+import os
from spack.directives import extends
from spack.package import PackageBase, run_after
@@ -91,10 +92,26 @@ class PythonPackage(PackageBase):
# Default phases
phases = ['build', 'install']
+ # Name of modules that the Python package provides
+ # This is used to test whether or not the installation succeeded
+ # These names generally come from running:
+ #
+ # >>> import setuptools
+ # >>> setuptools.find_packages()
+ #
+ # in the source tarball directory
+ import_modules = []
+
# To be used in UI queries that require to know which
# build-system class we are using
build_system_class = 'PythonPackage'
+ #: Callback names for build-time test
+ build_time_test_callbacks = ['test']
+
+ #: Callback names for install-time test
+ install_time_test_callbacks = ['import_module_test']
+
extends('python')
def setup_file(self):
@@ -106,19 +123,38 @@ class PythonPackage(PackageBase):
"""The directory containing the ``setup.py`` file."""
return self.stage.source_path
- def python(self, *args):
- inspect.getmodule(self).python(*args)
+ def python(self, *args, **kwargs):
+ inspect.getmodule(self).python(*args, **kwargs)
- def setup_py(self, *args):
+ def setup_py(self, *args, **kwargs):
setup = self.setup_file()
with working_dir(self.build_directory):
- self.python(setup, '--no-user-cfg', *args)
+ self.python(setup, '--no-user-cfg', *args, **kwargs)
+
+ def _setup_command_available(self, command):
+ """Determines whether or not a setup.py command exists.
+
+ :param str command: The command to look for
+ :return: True if the command is found, else False
+ :rtype: bool
+ """
+ kwargs = {
+ 'output': os.devnull,
+ 'error': os.devnull,
+ 'fail_on_error': False
+ }
+
+ python = inspect.getmodule(self).python
+ setup = self.setup_file()
+
+ python(setup, '--no-user-cfg', command, '--help', **kwargs)
+ return python.returncode == 0
# The following phases and their descriptions come from:
# $ python setup.py --help-commands
- # Only standard commands are included here, but some packages
- # define extra commands as well
+
+ # Standard commands
def build(self, spec, prefix):
"""Build everything needed to install."""
@@ -306,5 +342,37 @@ class PythonPackage(PackageBase):
"""Arguments to pass to check."""
return []
+ # Testing
+
+ def test(self):
+ """Run unit tests after in-place build.
+
+ These tests are only run if the package actually has a 'test' command.
+ """
+ if self._setup_command_available('test'):
+ args = self.test_args(self.spec, self.prefix)
+
+ self.setup_py('test', *args)
+
+ def test_args(self, spec, prefix):
+ """Arguments to pass to test."""
+ return []
+
+ run_after('build')(PackageBase._run_default_build_time_test_callbacks)
+
+ def import_module_test(self):
+ """Attempts to import the module that was just installed.
+
+ This test is only run if the package overrides
+ :py:attr:`import_modules` with a list of module names."""
+
+ # Make sure we are importing the installed modules,
+ # not the ones in the current directory
+ with working_dir('..'):
+ for module in self.import_modules:
+ self.python('-c', 'import {0}'.format(module))
+
+ run_after('install')(PackageBase._run_default_install_time_test_callbacks)
+
# Check that self.prefix is there after installation
run_after('install')(PackageBase.sanity_check_prefix)
diff --git a/lib/spack/spack/util/executable.py b/lib/spack/spack/util/executable.py
index 63bbbb7c92..7a960e88cb 100644
--- a/lib/spack/spack/util/executable.py
+++ b/lib/spack/spack/util/executable.py
@@ -68,7 +68,7 @@ class Executable(object):
Raise an exception if the subprocess returns an
error. Default is True. When not set, the return code is
- avaiale as `exe.returncode`.
+ available as `exe.returncode`.
ignore_errors