diff options
author | Adam J. Stewart <ajstewart426@gmail.com> | 2017-03-31 15:39:07 -0500 |
---|---|---|
committer | Todd Gamblin <tgamblin@llnl.gov> | 2017-03-31 13:39:07 -0700 |
commit | bc404532ea875ecc6982d049dc7c7f041aa74443 (patch) | |
tree | d3fc3694c24c7cf2a7d259481291482030bd5a89 /lib | |
parent | 3ade829566a00e6bcb542c5af27f107a6e45d50e (diff) | |
download | spack-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.py | 80 | ||||
-rw-r--r-- | lib/spack/spack/util/executable.py | 2 |
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 |