PYTHONPATH : python patches methods for its extensions

This commit is contained in:
alalazo 2016-03-18 14:40:53 +01:00
parent 82ba0c6c07
commit ec8cc2b528
7 changed files with 53 additions and 27 deletions

View File

@ -282,9 +282,11 @@ def setup_package(pkg):
for mod in modules: for mod in modules:
set_module_variables_for_package(pkg, mod) set_module_variables_for_package(pkg, mod)
# Allow dependencies to set up environment as well. # Allow dependencies to modify the module
for dependency_spec in pkg.spec.traverse(root=False): for dependency_spec in pkg.spec.traverse(root=False):
dependency_spec.package.modify_module(pkg.module, dependency_spec, pkg.spec) dependency_spec.package.modify_module(pkg.module, dependency_spec, pkg.spec)
# Allow dependencies to set up environment as well
for dependency_spec in pkg.spec.traverse(root=False):
dependency_spec.package.setup_dependent_environment(env, pkg.spec) dependency_spec.package.setup_dependent_environment(env, pkg.spec)
# TODO : implement validation # TODO : implement validation
#validate(env) #validate(env)

View File

@ -79,7 +79,7 @@ def uninstall(parser, args):
try: try:
# should work if package is known to spack # should work if package is known to spack
pkgs.append(s.package) pkgs.append(s.package)
except spack.repository.UnknownPackageError, e: except spack.repository.UnknownPackageError as e:
# The package.py file has gone away -- but still # The package.py file has gone away -- but still
# want to uninstall. # want to uninstall.
spack.Package(s).do_uninstall(force=True) spack.Package(s).do_uninstall(force=True)
@ -94,11 +94,11 @@ def num_installed_deps(pkg):
for pkg in pkgs: for pkg in pkgs:
try: try:
pkg.do_uninstall(force=args.force) pkg.do_uninstall(force=args.force)
except PackageStillNeededError, e: except PackageStillNeededError as e:
tty.error("Will not uninstall %s" % e.spec.format("$_$@$%@$#", color=True)) tty.error("Will not uninstall %s" % e.spec.format("$_$@$%@$#", color=True))
print print()
print "The following packages depend on it:" print("The following packages depend on it:")
display_specs(e.dependents, long=True) display_specs(e.dependents, long=True)
print print()
print "You can use spack uninstall -f to force this action." print("You can use spack uninstall -f to force this action.")
sys.exit(1) sys.exit(1)

View File

@ -150,7 +150,7 @@ def remove_install_directory(self, spec):
if os.path.exists(path): if os.path.exists(path):
try: try:
shutil.rmtree(path) shutil.rmtree(path)
except exceptions.OSError, e: except exceptions.OSError as e:
raise RemoveFailedError(spec, path, e) raise RemoveFailedError(spec, path, e)
path = os.path.dirname(path) path = os.path.dirname(path)

View File

@ -119,13 +119,13 @@ def __init__(cls, name, bases, dict):
module_types[cls.name] = cls module_types[cls.name] = cls
def __init__(self, spec=None): def __init__(self, spec=None):
self.spec = spec
self.pkg = spec.package # Just stored for convenience
# category in the modules system # category in the modules system
# TODO: come up with smarter category names. # TODO: come up with smarter category names.
self.category = "spack" self.category = "spack"
self.spec = spec
self.pkg = spec.package # Just stored for convenience
# short description default is just the package + version # short description default is just the package + version
# packages can provide this optional attribute # packages can provide this optional attribute
self.short_description = spec.format("$_ $@") self.short_description = spec.format("$_ $@")
@ -161,6 +161,12 @@ def write(self):
# Environment modifications guessed by inspecting the installation prefix # Environment modifications guessed by inspecting the installation prefix
env = inspect_path(self.spec.prefix) env = inspect_path(self.spec.prefix)
# Let the extendee modify their extensions before asking for package-specific modifications
for extendee in self.pkg.extendees:
extendee_spec = self.spec[extendee]
extendee_spec.package.modify_module(self.pkg, extendee_spec, self.spec)
# Package-specific environment modifications # Package-specific environment modifications
self.spec.package.setup_environment(env) self.spec.package.setup_environment(env)
# TODO : implement site-specific modifications and filters # TODO : implement site-specific modifications and filters

View File

@ -1261,16 +1261,6 @@ def rpath_args(self):
"""Get the rpath args as a string, with -Wl,-rpath, for each element.""" """Get the rpath args as a string, with -Wl,-rpath, for each element."""
return " ".join("-Wl,-rpath,%s" % p for p in self.rpath) return " ".join("-Wl,-rpath,%s" % p for p in self.rpath)
class PythonExtension(Package):
def setup_dependent_environment(self, env, dependent_spec):
pass
def setup_environment(self, env):
site_packages = glob.glob(join_path(self.spec.prefix.lib, "python*/site-packages"))
if site_packages:
env.prepend_path('PYTHONPATH', site_packages[0])
def validate_package_url(url_string): def validate_package_url(url_string):
"""Determine whether spack can handle a particular URL or not.""" """Determine whether spack can handle a particular URL or not."""
url = urlparse(url_string) url = urlparse(url_string)

View File

@ -1,7 +1,7 @@
from spack import * from spack import *
from spack.package import PythonExtension
class PyNose(PythonExtension):
class PyNose(Package):
"""nose extends the test loading and running features of unittest, """nose extends the test loading and running features of unittest,
making it easier to write, find and run tests.""" making it easier to write, find and run tests."""

View File

@ -1,11 +1,14 @@
import functools
import glob
import inspect
import os import os
import re import re
from contextlib import closing from contextlib import closing
from llnl.util.lang import match_predicate
from spack.util.environment import *
from spack import *
import spack import spack
from llnl.util.lang import match_predicate
from spack import *
from spack.util.environment import *
class Python(Package): class Python(Package):
@ -111,6 +114,31 @@ def modify_module(self, module, spec, ext_spec):
else: else:
module.python = Executable(join_path(spec.prefix.bin, 'python')) module.python = Executable(join_path(spec.prefix.bin, 'python'))
# The code below patches the any python extension to have good defaults for `setup_dependent_environment` and
# `setup_environment` only if the extension didn't override any of these functions explicitly.
def _setup_env(self, env):
site_packages = glob.glob(join_path(self.spec.prefix.lib, "python*/site-packages"))
if site_packages:
env.prepend_path('PYTHONPATH', site_packages[0])
def _setup_denv(self, env, extension_spec):
pass
pkg_cls = type(ext_spec.package) # Retrieve the type we may want to patch
if 'python' in pkg_cls.extendees:
# List of overrides we are interested in
interesting_overrides = ['setup_environment', 'setup_dependent_environment']
overrides_found = [
(name, defining_cls) for name, _, defining_cls, _, in inspect.classify_class_attrs(pkg_cls)
if
name in interesting_overrides and # The attribute has the right name
issubclass(defining_cls, Package) and defining_cls is not Package # and is an actual override
]
if not overrides_found:
# If no override were found go on patching
pkg_cls.setup_environment = functools.wraps(Package.setup_environment)(_setup_env)
pkg_cls.setup_dependent_environment = functools.wraps(Package.setup_dependent_environment)(_setup_denv)
# Add variables for lib/pythonX.Y and lib/pythonX.Y/site-packages dirs. # Add variables for lib/pythonX.Y and lib/pythonX.Y/site-packages dirs.
module.python_lib_dir = os.path.join(ext_spec.prefix, self.python_lib_dir) module.python_lib_dir = os.path.join(ext_spec.prefix, self.python_lib_dir)
module.python_include_dir = os.path.join(ext_spec.prefix, self.python_include_dir) module.python_include_dir = os.path.join(ext_spec.prefix, self.python_include_dir)