diff options
-rw-r--r-- | lib/spack/spack/build_systems/python.py | 80 | ||||
-rw-r--r-- | lib/spack/spack/util/executable.py | 2 | ||||
-rw-r--r-- | var/spack/repos/builtin/packages/py-nose/package.py | 4 | ||||
-rw-r--r-- | var/spack/repos/builtin/packages/py-numpy/package.py | 35 | ||||
-rw-r--r-- | var/spack/repos/builtin/packages/py-scipy/package.py | 39 | ||||
-rw-r--r-- | var/spack/repos/builtin/packages/py-setuptools/package.py | 14 |
6 files changed, 167 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 diff --git a/var/spack/repos/builtin/packages/py-nose/package.py b/var/spack/repos/builtin/packages/py-nose/package.py index c78c52647a..2b27ed4f1d 100644 --- a/var/spack/repos/builtin/packages/py-nose/package.py +++ b/var/spack/repos/builtin/packages/py-nose/package.py @@ -34,6 +34,10 @@ class PyNose(PythonPackage): list_url = "https://pypi.python.org/pypi/nose/" list_depth = 2 + import_modules = [ + 'nose', 'nose.ext', 'nose.plugins', 'nose.sphinx', 'nose.tools' + ] + version('1.3.7', '4d3ad0ff07b61373d2cefc89c5d0b20b') version('1.3.6', '0ca546d81ca8309080fc80cb389e7a16') version('1.3.4', '6ed7169887580ddc9a8e16048d38274d') diff --git a/var/spack/repos/builtin/packages/py-numpy/package.py b/var/spack/repos/builtin/packages/py-numpy/package.py index 3ed0d0bdb5..3b590fbd24 100644 --- a/var/spack/repos/builtin/packages/py-numpy/package.py +++ b/var/spack/repos/builtin/packages/py-numpy/package.py @@ -36,6 +36,18 @@ class PyNumpy(PythonPackage): homepage = "http://www.numpy.org/" url = "https://pypi.io/packages/source/n/numpy/numpy-1.9.1.tar.gz" + install_time_test_callbacks = ['install_test', 'import_module_test'] + + import_modules = [ + 'numpy', 'numpy.compat', 'numpy.core', 'numpy.distutils', 'numpy.doc', + 'numpy.f2py', 'numpy.fft', 'numpy.lib', 'numpy.linalg', 'numpy.ma', + 'numpy.matrixlib', 'numpy.polynomial', 'numpy.random', 'numpy.testing', + 'numpy.distutils.command', 'numpy.distutils.fcompiler' + ] + + # FIXME: numpy._build_utils and numpy.core.code_generators failed to import + # FIXME: Is this expected? + version('1.12.0', '33e5a84579f31829bbbba084fe0a4300', url="https://pypi.io/packages/source/n/numpy/numpy-1.12.0.zip") version('1.11.2', '03bd7927c314c43780271bf1ab795ebc') @@ -53,6 +65,10 @@ class PyNumpy(PythonPackage): depends_on('blas', when='+blas') depends_on('lapack', when='+lapack') + # Tests require: + # TODO: Add a 'test' deptype + # depends_on('py-nose@1.0.0:', type='test') + def setup_dependent_package(self, module, dependent_spec): python_version = self.spec['python'].version.up_to(2) arch = '{0}-{1}'.format(platform.system().lower(), platform.machine()) @@ -132,3 +148,22 @@ class PyNumpy(PythonPackage): args = ['-j', str(make_jobs)] return args + + def test(self): + # `setup.py test` is not supported. Use one of the following + # instead: + # + # - `python runtests.py` (to build and test) + # - `python runtests.py --no-build` (to test installed numpy) + # - `>>> numpy.test()` (run tests for installed numpy + # from within an interpreter) + pass + + def install_test(self): + # Change directories due to the following error: + # + # ImportError: Error importing numpy: you should not try to import + # numpy from its source directory; please exit the numpy + # source tree, and relaunch your python interpreter from there. + with working_dir('..'): + python('-c', 'import numpy; numpy.test("full", verbose=2)') diff --git a/var/spack/repos/builtin/packages/py-scipy/package.py b/var/spack/repos/builtin/packages/py-scipy/package.py index c506d4747d..c3ca24291f 100644 --- a/var/spack/repos/builtin/packages/py-scipy/package.py +++ b/var/spack/repos/builtin/packages/py-scipy/package.py @@ -33,6 +33,22 @@ class PyScipy(PythonPackage): homepage = "http://www.scipy.org/" url = "https://pypi.io/packages/source/s/scipy/scipy-0.18.1.tar.gz" + install_time_test_callbacks = ['install_test', 'import_module_test'] + + import_modules = [ + 'scipy', 'scipy._build_utils', 'scipy._lib', 'scipy.cluster', + 'scipy.constants', 'scipy.fftpack', 'scipy.integrate', + 'scipy.interpolate', 'scipy.io', 'scipy.linalg', 'scipy.misc', + 'scipy.ndimage', 'scipy.odr', 'scipy.optimize', 'scipy.signal', + 'scipy.sparse', 'scipy.spatial', 'scipy.special', 'scipy.stats', + 'scipy.weave', 'scipy.io.arff', 'scipy.io.harwell_boeing', + 'scipy.io.matlab', 'scipy.optimize._lsq', 'scipy.sparse.csgraph', + 'scipy.sparse.linalg', 'scipy.sparse.linalg.dsolve', + 'scipy.sparse.linalg.eigen', 'scipy.sparse.linalg.isolve', + 'scipy.sparse.linalg.eigen.arpack', 'scipy.sparse.linalg.eigen.lobpcg', + 'scipy.special._precompute' + ] + version('0.19.0', '91b8396231eec780222a57703d3ec550', url="https://pypi.io/packages/source/s/scipy/scipy-0.19.0.zip") version('0.18.1', '5fb5fb7ccb113ab3a039702b6c2f3327') @@ -49,6 +65,10 @@ class PyScipy(PythonPackage): depends_on('blas') depends_on('lapack') + # Tests require: + # TODO: Add a 'test' deptype + # depends_on('py-nose', type='test') + def build_args(self, spec, prefix): args = [] @@ -59,3 +79,22 @@ class PyScipy(PythonPackage): args.extend(['-j', str(make_jobs)]) return args + + def test(self): + # `setup.py test` is not supported. Use one of the following + # instead: + # + # - `python runtests.py` (to build and test) + # - `python runtests.py --no-build` (to test installed scipy) + # - `>>> scipy.test()` (run tests for installed scipy + # from within an interpreter) + pass + + def install_test(self): + # Change directories due to the following error: + # + # ImportError: Error importing scipy: you should not try to import + # scipy from its source directory; please exit the scipy + # source tree, and relaunch your python interpreter from there. + with working_dir('..'): + python('-c', 'import scipy; scipy.test("full", verbose=2)') diff --git a/var/spack/repos/builtin/packages/py-setuptools/package.py b/var/spack/repos/builtin/packages/py-setuptools/package.py index af1ea9bf06..94ee8a7fc4 100644 --- a/var/spack/repos/builtin/packages/py-setuptools/package.py +++ b/var/spack/repos/builtin/packages/py-setuptools/package.py @@ -32,6 +32,12 @@ class PySetuptools(PythonPackage): homepage = "https://pypi.python.org/pypi/setuptools" url = "https://pypi.io/packages/source/s/setuptools/setuptools-25.2.0.tar.gz" + import_modules = [ + 'pkg_resources', 'setuptools', 'pkg_resources.extern', + 'pkg_resources._vendor', 'pkg_resources._vendor.packaging', + 'setuptools.extern', 'setuptools.command' + ] + version('34.2.0', '41b630da4ea6cfa5894d9eb3142922be', url="https://pypi.io/packages/source/s/setuptools/setuptools-34.2.0.zip") version('25.2.0', 'a0dbb65889c46214c691f6c516cf959c') @@ -53,3 +59,11 @@ class PySetuptools(PythonPackage): depends_on('py-packaging@16.8:', when='@34.0.0:', type=('build', 'run')) depends_on('py-six@1.6.0:', when='@34.0.0:', type=('build', 'run')) depends_on('py-appdirs@1.4.0:', when='@34.0.0:', type=('build', 'run')) + + # Tests require: + # TODO: Add a 'test' deptype + # FIXME: All of these depend on setuptools, creating a dependency loop + # FIXME: Is there any way around this problem? + # depends_on('py-pytest-flake8', type='test') + # depends_on('pytest@2.8:', type='test') + # depends_on('py-mock', when='^python@:3.2', type='test') |