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
This commit is contained in:
Adam J. Stewart
2017-03-31 15:39:07 -05:00
committed by Todd Gamblin
parent 3ade829566
commit bc404532ea
6 changed files with 167 additions and 7 deletions

View File

@@ -24,6 +24,7 @@
##############################################################################
import inspect
import os
from spack.directives import extends
from spack.package import PackageBase, run_after
@@ -91,10 +92,26 @@ def configure(self, spec, prefix):
# 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 @@ def build_directory(self):
"""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 @@ def check_args(self, spec, prefix):
"""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)

View File

@@ -68,7 +68,7 @@ def __call__(self, *args, **kwargs):
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