Use a module-like object to propagate changes in the MRO, when setting build env (#34059)
This fixes an issue introduced in #32340, which changed the semantics of the "module" object passed to the "setup_dependent_package" callback.
This commit is contained in:
parent
e964a396c9
commit
7593b18626
@ -978,22 +978,9 @@ def add_modifications_for_dep(dep):
|
|||||||
if set_package_py_globals:
|
if set_package_py_globals:
|
||||||
set_module_variables_for_package(dpkg)
|
set_module_variables_for_package(dpkg)
|
||||||
|
|
||||||
# Allow dependencies to modify the module
|
current_module = ModuleChangePropagator(spec.package)
|
||||||
# Get list of modules that may need updating
|
dpkg.setup_dependent_package(current_module, spec)
|
||||||
modules = []
|
current_module.propagate_changes_to_mro()
|
||||||
for cls in inspect.getmro(type(spec.package)):
|
|
||||||
module = cls.module
|
|
||||||
if module == spack.package_base:
|
|
||||||
break
|
|
||||||
modules.append(module)
|
|
||||||
|
|
||||||
# Execute changes as if on a single module
|
|
||||||
# copy dict to ensure prior changes are available
|
|
||||||
changes = spack.util.pattern.Bunch()
|
|
||||||
dpkg.setup_dependent_package(changes, spec)
|
|
||||||
|
|
||||||
for module in modules:
|
|
||||||
module.__dict__.update(changes.__dict__)
|
|
||||||
|
|
||||||
if context == "build":
|
if context == "build":
|
||||||
builder = spack.builder.create(dpkg)
|
builder = spack.builder.create(dpkg)
|
||||||
@ -1437,3 +1424,51 @@ def write_log_summary(out, log_type, log, last=None):
|
|||||||
# If no errors are found but warnings are, display warnings
|
# If no errors are found but warnings are, display warnings
|
||||||
out.write("\n%s found in %s log:\n" % (plural(nwar, "warning"), log_type))
|
out.write("\n%s found in %s log:\n" % (plural(nwar, "warning"), log_type))
|
||||||
out.write(make_log_context(warnings))
|
out.write(make_log_context(warnings))
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleChangePropagator(object):
|
||||||
|
"""Wrapper class to accept changes to a package.py Python module, and propagate them in the
|
||||||
|
MRO of the package.
|
||||||
|
|
||||||
|
It is mainly used as a substitute of the ``package.py`` module, when calling the
|
||||||
|
"setup_dependent_package" function during build environment setup.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_PROTECTED_NAMES = ("package", "current_module", "modules_in_mro", "_set_attributes")
|
||||||
|
|
||||||
|
def __init__(self, package):
|
||||||
|
self._set_self_attributes("package", package)
|
||||||
|
self._set_self_attributes("current_module", package.module)
|
||||||
|
|
||||||
|
#: Modules for the classes in the MRO up to PackageBase
|
||||||
|
modules_in_mro = []
|
||||||
|
for cls in inspect.getmro(type(package)):
|
||||||
|
module = cls.module
|
||||||
|
|
||||||
|
if module == self.current_module:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if module == spack.package_base:
|
||||||
|
break
|
||||||
|
|
||||||
|
modules_in_mro.append(module)
|
||||||
|
self._set_self_attributes("modules_in_mro", modules_in_mro)
|
||||||
|
self._set_self_attributes("_set_attributes", {})
|
||||||
|
|
||||||
|
def _set_self_attributes(self, key, value):
|
||||||
|
super(ModuleChangePropagator, self).__setattr__(key, value)
|
||||||
|
|
||||||
|
def __getattr__(self, item):
|
||||||
|
return getattr(self.current_module, item)
|
||||||
|
|
||||||
|
def __setattr__(self, key, value):
|
||||||
|
if key in ModuleChangePropagator._PROTECTED_NAMES:
|
||||||
|
msg = 'Cannot set attribute "{}" in ModuleMonkeyPatcher'.format(key)
|
||||||
|
return AttributeError(msg)
|
||||||
|
|
||||||
|
setattr(self.current_module, key, value)
|
||||||
|
self._set_attributes[key] = value
|
||||||
|
|
||||||
|
def propagate_changes_to_mro(self):
|
||||||
|
for module_in_mro in self.modules_in_mro:
|
||||||
|
module_in_mro.__dict__.update(self._set_attributes)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
import inspect
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import posixpath
|
import posixpath
|
||||||
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
import spack.build_environment
|
import spack.build_environment
|
||||||
import spack.config
|
import spack.config
|
||||||
|
import spack.package_base
|
||||||
import spack.spec
|
import spack.spec
|
||||||
import spack.util.spack_yaml as syaml
|
import spack.util.spack_yaml as syaml
|
||||||
from spack.build_environment import (
|
from spack.build_environment import (
|
||||||
@ -521,3 +522,27 @@ def test_dirty_disable_module_unload(config, mock_packages, working_env, mock_mo
|
|||||||
assert mock_module_cmd.calls
|
assert mock_module_cmd.calls
|
||||||
assert any(("unload", "cray-libsci") == item[0] for item in mock_module_cmd.calls)
|
assert any(("unload", "cray-libsci") == item[0] for item in mock_module_cmd.calls)
|
||||||
assert any(("unload", "cray-mpich") == item[0] for item in mock_module_cmd.calls)
|
assert any(("unload", "cray-mpich") == item[0] for item in mock_module_cmd.calls)
|
||||||
|
|
||||||
|
|
||||||
|
class TestModuleMonkeyPatcher:
|
||||||
|
def test_getting_attributes(self, config, mock_packages):
|
||||||
|
s = spack.spec.Spec("libelf").concretized()
|
||||||
|
module_wrapper = spack.build_environment.ModuleChangePropagator(s.package)
|
||||||
|
assert module_wrapper.Libelf == s.package.module.Libelf
|
||||||
|
|
||||||
|
def test_setting_attributes(self, config, mock_packages):
|
||||||
|
s = spack.spec.Spec("libelf").concretized()
|
||||||
|
module = s.package.module
|
||||||
|
module_wrapper = spack.build_environment.ModuleChangePropagator(s.package)
|
||||||
|
|
||||||
|
# Setting an attribute has an immediate effect
|
||||||
|
module_wrapper.SOME_ATTRIBUTE = 1
|
||||||
|
assert module.SOME_ATTRIBUTE == 1
|
||||||
|
|
||||||
|
# We can also propagate the settings to classes in the MRO
|
||||||
|
module_wrapper.propagate_changes_to_mro()
|
||||||
|
for cls in inspect.getmro(type(s.package)):
|
||||||
|
current_module = cls.module
|
||||||
|
if current_module == spack.package_base:
|
||||||
|
break
|
||||||
|
assert current_module.SOME_ATTRIBUTE == 1
|
||||||
|
Loading…
Reference in New Issue
Block a user