simplify mro stuff

This commit is contained in:
Harmen Stoppels 2024-08-30 15:07:33 +02:00
parent 3d827b0ea5
commit dd9e28a621
3 changed files with 16 additions and 38 deletions

View File

@ -555,7 +555,7 @@ def set_package_py_globals(pkg, context: Context = Context.BUILD):
"""Populate the Python module of a package with some useful global names. """Populate the Python module of a package with some useful global names.
This makes things easier for package writers. This makes things easier for package writers.
""" """
module = ModuleChangePropagator(pkg) module = SetPackageGlobals(pkg)
if context == Context.BUILD: if context == Context.BUILD:
module.std_cmake_args = spack.build_systems.cmake.CMakeBuilder.std_args(pkg) module.std_cmake_args = spack.build_systems.cmake.CMakeBuilder.std_args(pkg)
@ -1016,7 +1016,7 @@ def set_all_package_py_globals(self):
# setting globals for those. # setting globals for those.
if id(spec) not in self.nodes_in_subdag: if id(spec) not in self.nodes_in_subdag:
continue continue
dependent_module = ModuleChangePropagator(spec.package) dependent_module = SetPackageGlobals(spec.package)
pkg.setup_dependent_package(dependent_module, spec) pkg.setup_dependent_package(dependent_module, spec)
dependent_module.propagate_changes_to_mro() dependent_module.propagate_changes_to_mro()
@ -1543,7 +1543,7 @@ def write_log_summary(out, log_type, log, last=None):
out.write(make_log_context(warnings)) out.write(make_log_context(warnings))
class ModuleChangePropagator: class SetPackageGlobals:
"""Wrapper class to accept changes to a package.py Python module, and propagate them in the """Wrapper class to accept changes to a package.py Python module, and propagate them in the
MRO of the package. MRO of the package.
@ -1551,41 +1551,22 @@ class ModuleChangePropagator:
"setup_dependent_package" function during build environment setup. "setup_dependent_package" function during build environment setup.
""" """
_PROTECTED_NAMES = ("package", "current_module", "modules_in_mro", "_set_attributes")
def __init__(self, package: spack.package_base.PackageBase) -> None: def __init__(self, package: spack.package_base.PackageBase) -> None:
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 for the classes in the MRO up to PackageBase
modules_in_mro = [] modules_in_mro = []
for cls in package.__class__.__mro__: for cls in package.__class__.__mro__:
module = getattr(cls, "module", None) module = getattr(cls, "module", None)
if module is None or module is spack.package_base: if module is None or module is spack.package_base:
break break
if module is self.current_module:
continue
modules_in_mro.append(module) 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().__setattr__("modules_in_mro", modules_in_mro)
super().__setattr__(key, value)
def __getattr__(self, item): def __getattr__(self, item):
return getattr(self.current_module, item) return getattr(self.modules_in_mro[0], item)
def __setattr__(self, key, value): def __setattr__(self, key, value):
if key in ModuleChangePropagator._PROTECTED_NAMES: if key == "modules_in_mro":
msg = f'Cannot set attribute "{key}" in ModuleMonkeyPatcher' raise AttributeError(f'Cannot set attribute "{key}" in ModuleMonkeyPatcher')
return AttributeError(msg) for module in self.modules_in_mro:
setattr(module, key, value)
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)

View File

@ -14,6 +14,7 @@
import spack.build_environment import spack.build_environment
import spack.builder import spack.builder
import spack.package_base import spack.package_base
from spack.build_environment import SetPackageGlobals
from spack.directives import build_system, conflicts, depends_on from spack.directives import build_system, conflicts, depends_on
from spack.multimethod import when from spack.multimethod import when
from spack.operating_systems.mac_os import macos_version from spack.operating_systems.mac_os import macos_version
@ -577,9 +578,7 @@ def set_configure_or_die(self):
raise RuntimeError(msg.format(self.configure_directory)) raise RuntimeError(msg.format(self.configure_directory))
# Monkey-patch the configure script in the corresponding module # Monkey-patch the configure script in the corresponding module
globals_for_pkg = spack.build_environment.ModuleChangePropagator(self.pkg) SetPackageGlobals(self.pkg).configure = Executable(self.configure_abs_path)
globals_for_pkg.configure = Executable(self.configure_abs_path)
globals_for_pkg.propagate_changes_to_mro()
def configure_args(self): def configure_args(self):
"""Return the list of all the arguments that must be passed to configure, """Return the list of all the arguments that must be passed to configure,

View File

@ -575,28 +575,26 @@ def test_build_jobs_defaults():
) )
class TestModuleMonkeyPatcher: class TestSetPackageGlobals:
def test_getting_attributes(self, default_mock_concretization): def test_getting_attributes(self, default_mock_concretization):
s = default_mock_concretization("libelf") s = default_mock_concretization("libelf")
module_wrapper = spack.build_environment.ModuleChangePropagator(s.package) module_wrapper = spack.build_environment.SetPackageGlobals(s.package)
assert module_wrapper.Libelf == s.package.module.Libelf assert module_wrapper.Libelf == s.package.module.Libelf
def test_setting_attributes(self, default_mock_concretization): def test_setting_attributes(self, default_mock_concretization):
s = default_mock_concretization("libelf") s = default_mock_concretization("libelf")
module = s.package.module module = s.package.module
module_wrapper = spack.build_environment.ModuleChangePropagator(s.package) module_wrapper = spack.build_environment.SetPackageGlobals(s.package)
# Setting an attribute has an immediate effect # Setting an attribute has an immediate effect
module_wrapper.SOME_ATTRIBUTE = 1 module_wrapper.SOME_ATTRIBUTE = 1
assert module.SOME_ATTRIBUTE == 1 assert module.SOME_ATTRIBUTE == 1
# We can also propagate the settings to classes in the MRO # We can also propagate the settings to classes in the MRO
module_wrapper.propagate_changes_to_mro()
for cls in s.package.__class__.__mro__: for cls in s.package.__class__.__mro__:
current_module = cls.module if cls.module == spack.package_base:
if current_module == spack.package_base:
break break
assert current_module.SOME_ATTRIBUTE == 1 assert cls.module.SOME_ATTRIBUTE == 1
def test_effective_deptype_build_environment(default_mock_concretization): def test_effective_deptype_build_environment(default_mock_concretization):