config: fix class hierarchy (#45044)

1. Avoid that `self.path` is of type `Optional[str]`
2. Simplify immutable config with a property.
This commit is contained in:
Harmen Stoppels 2024-07-05 12:41:13 +02:00 committed by GitHub
parent 95cf341b50
commit 1d8bdcfc04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 128 additions and 124 deletions

View File

@ -129,10 +129,10 @@ def _bootstrap_config_scopes() -> Sequence["spack.config.ConfigScope"]:
configuration_paths = (spack.config.CONFIGURATION_DEFAULTS_PATH, ("bootstrap", _config_path())) configuration_paths = (spack.config.CONFIGURATION_DEFAULTS_PATH, ("bootstrap", _config_path()))
for name, path in configuration_paths: for name, path in configuration_paths:
platform = spack.platforms.host().name platform = spack.platforms.host().name
platform_scope = spack.config.ConfigScope( platform_scope = spack.config.DirectoryConfigScope(
"/".join([name, platform]), os.path.join(path, platform) f"{name}/{platform}", os.path.join(path, platform)
) )
generic_scope = spack.config.ConfigScope(name, path) generic_scope = spack.config.DirectoryConfigScope(name, path)
config_scopes.extend([generic_scope, platform_scope]) config_scopes.extend([generic_scope, platform_scope])
msg = "[BOOTSTRAP CONFIG SCOPE] name={0}, path={1}" msg = "[BOOTSTRAP CONFIG SCOPE] name={0}, path={1}"
tty.debug(msg.format(generic_scope.name, generic_scope.path)) tty.debug(msg.format(generic_scope.name, generic_scope.path))

View File

@ -809,7 +809,8 @@ def ensure_expected_target_path(path):
cli_scopes = [ cli_scopes = [
os.path.relpath(s.path, concrete_env_dir) os.path.relpath(s.path, concrete_env_dir)
for s in cfg.scopes().values() for s in cfg.scopes().values()
if isinstance(s, cfg.ImmutableConfigScope) if not s.writable
and isinstance(s, (cfg.DirectoryConfigScope))
and s.path not in env_includes and s.path not in env_includes
and os.path.exists(s.path) and os.path.exists(s.path)
] ]

View File

@ -165,7 +165,7 @@ def _reset(args):
if not ok_to_continue: if not ok_to_continue:
raise RuntimeError("Aborting") raise RuntimeError("Aborting")
for scope in spack.config.CONFIG.file_scopes: for scope in spack.config.CONFIG.writable_scopes:
# The default scope should stay untouched # The default scope should stay untouched
if scope.name == "defaults": if scope.name == "defaults":
continue continue

View File

@ -264,7 +264,9 @@ def config_remove(args):
def _can_update_config_file(scope: spack.config.ConfigScope, cfg_file): def _can_update_config_file(scope: spack.config.ConfigScope, cfg_file):
if isinstance(scope, spack.config.SingleFileScope): if isinstance(scope, spack.config.SingleFileScope):
return fs.can_access(cfg_file) return fs.can_access(cfg_file)
elif isinstance(scope, spack.config.DirectoryConfigScope):
return fs.can_write_to_dir(scope.path) and fs.can_access(cfg_file) return fs.can_write_to_dir(scope.path) and fs.can_access(cfg_file)
return False
def _config_change_requires_scope(path, spec, scope, match_spec=None): def _config_change_requires_scope(path, spec, scope, match_spec=None):
@ -362,14 +364,11 @@ def config_change(args):
def config_update(args): def config_update(args):
# Read the configuration files # Read the configuration files
spack.config.CONFIG.get_config(args.section, scope=args.scope) spack.config.CONFIG.get_config(args.section, scope=args.scope)
updates: List[spack.config.ConfigScope] = list( updates: List[spack.config.ConfigScope] = [
filter( x
lambda s: not isinstance( for x in spack.config.CONFIG.format_updates[args.section]
s, (spack.config.InternalConfigScope, spack.config.ImmutableConfigScope) if not isinstance(x, spack.config.InternalConfigScope) and x.writable
), ]
spack.config.CONFIG.format_updates[args.section],
)
)
cannot_overwrite, skip_system_scope = [], False cannot_overwrite, skip_system_scope = [], False
for scope in updates: for scope in updates:
@ -447,7 +446,7 @@ def _can_revert_update(scope_dir, cfg_file, bkp_file):
def config_revert(args): def config_revert(args):
scopes = [args.scope] if args.scope else [x.name for x in spack.config.CONFIG.file_scopes] scopes = [args.scope] if args.scope else [x.name for x in spack.config.CONFIG.writable_scopes]
# Search for backup files in the configuration scopes # Search for backup files in the configuration scopes
Entry = collections.namedtuple("Entry", ["scope", "cfg", "bkp"]) Entry = collections.namedtuple("Entry", ["scope", "cfg", "bkp"])

View File

@ -260,7 +260,7 @@ def _init_compiler_config(
def compiler_config_files(): def compiler_config_files():
config_files = list() config_files = list()
config = spack.config.CONFIG config = spack.config.CONFIG
for scope in config.file_scopes: for scope in config.writable_scopes:
name = scope.name name = scope.name
compiler_config = config.get("compilers", scope=name) compiler_config = config.get("compilers", scope=name)
if compiler_config: if compiler_config:

View File

@ -35,7 +35,7 @@
import os import os
import re import re
import sys import sys
from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, Type, Union from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, Union
from llnl.util import filesystem, lang, tty from llnl.util import filesystem, lang, tty
@ -117,21 +117,39 @@
class ConfigScope: class ConfigScope:
"""This class represents a configuration scope. def __init__(self, name: str) -> None:
self.name = name
self.writable = False
self.sections = syaml.syaml_dict()
A scope is one directory containing named configuration files. def get_section_filename(self, section: str) -> str:
Each file is a config "section" (e.g., mirrors, compilers, etc.). raise NotImplementedError
"""
def __init__(self, name, path) -> None: def get_section(self, section: str) -> Optional[YamlConfigDict]:
self.name = name # scope name. raise NotImplementedError
self.path = path # path to directory containing configs.
self.sections = syaml.syaml_dict() # sections read from config files. def _write_section(self, section: str) -> None:
raise NotImplementedError
@property @property
def is_platform_dependent(self) -> bool: def is_platform_dependent(self) -> bool:
"""Returns true if the scope name is platform specific""" return False
return os.sep in self.name
def clear(self) -> None:
"""Empty cached config information."""
self.sections = syaml.syaml_dict()
def __repr__(self) -> str:
return f"<ConfigScope: {self.name}>"
class DirectoryConfigScope(ConfigScope):
"""Config scope backed by a directory containing one file per section."""
def __init__(self, name: str, path: str, *, writable: bool = True) -> None:
super().__init__(name)
self.path = path
self.writable = writable
def get_section_filename(self, section: str) -> str: def get_section_filename(self, section: str) -> str:
"""Returns the filename associated with a given section""" """Returns the filename associated with a given section"""
@ -148,6 +166,9 @@ def get_section(self, section: str) -> Optional[YamlConfigDict]:
return self.sections[section] return self.sections[section]
def _write_section(self, section: str) -> None: def _write_section(self, section: str) -> None:
if not self.writable:
raise ConfigError(f"Cannot write to immutable scope {self}")
filename = self.get_section_filename(section) filename = self.get_section_filename(section)
data = self.get_section(section) data = self.get_section(section)
if data is None: if data is None:
@ -164,19 +185,23 @@ def _write_section(self, section: str) -> None:
except (syaml.SpackYAMLError, OSError) as e: except (syaml.SpackYAMLError, OSError) as e:
raise ConfigFileError(f"cannot write to '{filename}'") from e raise ConfigFileError(f"cannot write to '{filename}'") from e
def clear(self) -> None: @property
"""Empty cached config information.""" def is_platform_dependent(self) -> bool:
self.sections = syaml.syaml_dict() """Returns true if the scope name is platform specific"""
return "/" in self.name
def __repr__(self) -> str:
return f"<ConfigScope: {self.name}: {self.path}>"
class SingleFileScope(ConfigScope): class SingleFileScope(ConfigScope):
"""This class represents a configuration scope in a single YAML file.""" """This class represents a configuration scope in a single YAML file."""
def __init__( def __init__(
self, name: str, path: str, schema: YamlConfigDict, yaml_path: Optional[List[str]] = None self,
name: str,
path: str,
schema: YamlConfigDict,
*,
yaml_path: Optional[List[str]] = None,
writable: bool = True,
) -> None: ) -> None:
"""Similar to ``ConfigScope`` but can be embedded in another schema. """Similar to ``ConfigScope`` but can be embedded in another schema.
@ -195,15 +220,13 @@ def __init__(
config: config:
install_tree: $spack/opt/spack install_tree: $spack/opt/spack
""" """
super().__init__(name, path) super().__init__(name)
self._raw_data: Optional[YamlConfigDict] = None self._raw_data: Optional[YamlConfigDict] = None
self.schema = schema self.schema = schema
self.path = path
self.writable = writable
self.yaml_path = yaml_path or [] self.yaml_path = yaml_path or []
@property
def is_platform_dependent(self) -> bool:
return False
def get_section_filename(self, section) -> str: def get_section_filename(self, section) -> str:
return self.path return self.path
@ -257,6 +280,8 @@ def get_section(self, section: str) -> Optional[YamlConfigDict]:
return self.sections.get(section, None) return self.sections.get(section, None)
def _write_section(self, section: str) -> None: def _write_section(self, section: str) -> None:
if not self.writable:
raise ConfigError(f"Cannot write to immutable scope {self}")
data_to_write: Optional[YamlConfigDict] = self._raw_data data_to_write: Optional[YamlConfigDict] = self._raw_data
# If there is no existing data, this section SingleFileScope has never # If there is no existing data, this section SingleFileScope has never
@ -301,19 +326,6 @@ def __repr__(self) -> str:
return f"<SingleFileScope: {self.name}: {self.path}>" return f"<SingleFileScope: {self.name}: {self.path}>"
class ImmutableConfigScope(ConfigScope):
"""A configuration scope that cannot be written to.
This is used for ConfigScopes passed on the command line.
"""
def _write_section(self, section) -> None:
raise ConfigError(f"Cannot write to immutable scope {self}")
def __repr__(self) -> str:
return f"<ImmutableConfigScope: {self.name}: {self.path}>"
class InternalConfigScope(ConfigScope): class InternalConfigScope(ConfigScope):
"""An internal configuration scope that is not persisted to a file. """An internal configuration scope that is not persisted to a file.
@ -323,7 +335,7 @@ class InternalConfigScope(ConfigScope):
""" """
def __init__(self, name: str, data: Optional[YamlConfigDict] = None) -> None: def __init__(self, name: str, data: Optional[YamlConfigDict] = None) -> None:
super().__init__(name, None) super().__init__(name)
self.sections = syaml.syaml_dict() self.sections = syaml.syaml_dict()
if data is not None: if data is not None:
@ -333,9 +345,6 @@ def __init__(self, name: str, data: Optional[YamlConfigDict] = None) -> None:
validate({section: dsec}, SECTION_SCHEMAS[section]) validate({section: dsec}, SECTION_SCHEMAS[section])
self.sections[section] = _mark_internal(syaml.syaml_dict({section: dsec}), name) self.sections[section] = _mark_internal(syaml.syaml_dict({section: dsec}), name)
def get_section_filename(self, section: str) -> str:
raise NotImplementedError("Cannot get filename for InternalConfigScope.")
def get_section(self, section: str) -> Optional[YamlConfigDict]: def get_section(self, section: str) -> Optional[YamlConfigDict]:
"""Just reads from an internal dictionary.""" """Just reads from an internal dictionary."""
if section not in self.sections: if section not in self.sections:
@ -440,27 +449,21 @@ def remove_scope(self, scope_name: str) -> Optional[ConfigScope]:
return scope return scope
@property @property
def file_scopes(self) -> List[ConfigScope]: def writable_scopes(self) -> Generator[ConfigScope, None, None]:
"""List of writable scopes with an associated file.""" """Generator of writable scopes with an associated file."""
return [ return (s for s in self.scopes.values() if s.writable)
s
for s in self.scopes.values()
if (type(s) is ConfigScope or type(s) is SingleFileScope)
]
def highest_precedence_scope(self) -> ConfigScope: def highest_precedence_scope(self) -> ConfigScope:
"""Non-internal scope with highest precedence.""" """Writable scope with highest precedence."""
return next(reversed(self.file_scopes)) return next(s for s in reversed(self.scopes.values()) if s.writable) # type: ignore
def highest_precedence_non_platform_scope(self) -> ConfigScope: def highest_precedence_non_platform_scope(self) -> ConfigScope:
"""Non-internal non-platform scope with highest precedence """Writable non-platform scope with highest precedence"""
return next(
Platform-specific scopes are of the form scope/platform""" s
generator = reversed(self.file_scopes) for s in reversed(self.scopes.values()) # type: ignore
highest = next(generator) if s.writable and not s.is_platform_dependent
while highest and highest.is_platform_dependent: )
highest = next(generator)
return highest
def matching_scopes(self, reg_expr) -> List[ConfigScope]: def matching_scopes(self, reg_expr) -> List[ConfigScope]:
""" """
@ -755,13 +758,14 @@ def override(
def _add_platform_scope( def _add_platform_scope(
cfg: Union[Configuration, lang.Singleton], scope_type: Type[ConfigScope], name: str, path: str cfg: Union[Configuration, lang.Singleton], name: str, path: str, writable: bool = True
) -> None: ) -> None:
"""Add a platform-specific subdirectory for the current platform.""" """Add a platform-specific subdirectory for the current platform."""
platform = spack.platforms.host().name platform = spack.platforms.host().name
plat_name = os.path.join(name, platform) scope = DirectoryConfigScope(
plat_path = os.path.join(path, platform) f"{name}/{platform}", os.path.join(path, platform), writable=writable
cfg.push_scope(scope_type(plat_name, plat_path)) )
cfg.push_scope(scope)
def config_paths_from_entry_points() -> List[Tuple[str, str]]: def config_paths_from_entry_points() -> List[Tuple[str, str]]:
@ -806,8 +810,8 @@ def _add_command_line_scopes(
# name based on order on the command line # name based on order on the command line
name = f"cmd_scope_{i:d}" name = f"cmd_scope_{i:d}"
cfg.push_scope(ImmutableConfigScope(name, path)) cfg.push_scope(DirectoryConfigScope(name, path, writable=False))
_add_platform_scope(cfg, ImmutableConfigScope, name, path) _add_platform_scope(cfg, name, path, writable=False)
def create() -> Configuration: def create() -> Configuration:
@ -851,10 +855,10 @@ def create() -> Configuration:
# add each scope and its platform-specific directory # add each scope and its platform-specific directory
for name, path in configuration_paths: for name, path in configuration_paths:
cfg.push_scope(ConfigScope(name, path)) cfg.push_scope(DirectoryConfigScope(name, path))
# Each scope can have per-platfom overrides in subdirectories # Each scope can have per-platfom overrides in subdirectories
_add_platform_scope(cfg, ConfigScope, name, path) _add_platform_scope(cfg, name, path)
# add command-line scopes # add command-line scopes
_add_command_line_scopes(cfg, COMMAND_LINE_SCOPES) _add_command_line_scopes(cfg, COMMAND_LINE_SCOPES)
@ -969,7 +973,7 @@ def set(path: str, value: Any, scope: Optional[str] = None) -> None:
def add_default_platform_scope(platform: str) -> None: def add_default_platform_scope(platform: str) -> None:
plat_name = os.path.join("defaults", platform) plat_name = os.path.join("defaults", platform)
plat_path = os.path.join(CONFIGURATION_DEFAULTS_PATH[1], platform) plat_path = os.path.join(CONFIGURATION_DEFAULTS_PATH[1], platform)
CONFIG.push_scope(ConfigScope(plat_name, plat_path)) CONFIG.push_scope(DirectoryConfigScope(plat_name, plat_path))
def scopes() -> Dict[str, ConfigScope]: def scopes() -> Dict[str, ConfigScope]:
@ -978,19 +982,10 @@ def scopes() -> Dict[str, ConfigScope]:
def writable_scopes() -> List[ConfigScope]: def writable_scopes() -> List[ConfigScope]:
""" """Return list of writable scopes. Higher-priority scopes come first in the list."""
Return list of writable scopes. Higher-priority scopes come first in the scopes = [x for x in CONFIG.scopes.values() if x.writable]
list. scopes.reverse()
""" return scopes
return list(
reversed(
list(
x
for x in CONFIG.scopes.values()
if not isinstance(x, (InternalConfigScope, ImmutableConfigScope))
)
)
)
def writable_scope_names() -> List[str]: def writable_scope_names() -> List[str]:
@ -1599,7 +1594,7 @@ def _config_from(scopes_or_paths: List[Union[ConfigScope, str]]) -> Configuratio
path = os.path.normpath(scope_or_path) path = os.path.normpath(scope_or_path)
assert os.path.isdir(path), f'"{path}" must be a directory' assert os.path.isdir(path), f'"{path}" must be a directory'
name = os.path.basename(path) name = os.path.basename(path)
scopes.append(ConfigScope(name, path)) scopes.append(DirectoryConfigScope(name, path))
configuration = Configuration(*scopes) configuration = Configuration(*scopes)
return configuration return configuration

View File

@ -3028,7 +3028,7 @@ def included_config_scopes(self) -> List[spack.config.ConfigScope]:
SpackEnvironmentError: if the manifest includes a remote file but SpackEnvironmentError: if the manifest includes a remote file but
no configuration stage directory has been identified no configuration stage directory has been identified
""" """
scopes = [] scopes: List[spack.config.ConfigScope] = []
# load config scopes added via 'include:', in reverse so that # load config scopes added via 'include:', in reverse so that
# highest-precedence scopes are last. # highest-precedence scopes are last.
@ -3097,23 +3097,21 @@ def included_config_scopes(self) -> List[spack.config.ConfigScope]:
if os.path.isdir(config_path): if os.path.isdir(config_path):
# directories are treated as regular ConfigScopes # directories are treated as regular ConfigScopes
config_name = "env:%s:%s" % (env_name, os.path.basename(config_path)) config_name = "env:%s:%s" % (env_name, os.path.basename(config_path))
tty.debug("Creating ConfigScope {0} for '{1}'".format(config_name, config_path)) tty.debug(f"Creating DirectoryConfigScope {config_name} for '{config_path}'")
scope = spack.config.ConfigScope(config_name, config_path) scopes.append(spack.config.DirectoryConfigScope(config_name, config_path))
elif os.path.exists(config_path): elif os.path.exists(config_path):
# files are assumed to be SingleFileScopes # files are assumed to be SingleFileScopes
config_name = "env:%s:%s" % (env_name, config_path) config_name = "env:%s:%s" % (env_name, config_path)
tty.debug( tty.debug(f"Creating SingleFileScope {config_name} for '{config_path}'")
"Creating SingleFileScope {0} for '{1}'".format(config_name, config_path) scopes.append(
) spack.config.SingleFileScope(
scope = spack.config.SingleFileScope(
config_name, config_path, spack.schema.merged.schema config_name, config_path, spack.schema.merged.schema
) )
)
else: else:
missing.append(config_path) missing.append(config_path)
continue continue
scopes.append(scope)
if missing: if missing:
msg = "Detected {0} missing include path(s):".format(len(missing)) msg = "Detected {0} missing include path(s):".format(len(missing))
msg += "\n {0}".format("\n ".join(missing)) msg += "\n {0}".format("\n ".join(missing))
@ -3130,7 +3128,10 @@ def env_config_scopes(self) -> List[spack.config.ConfigScope]:
scopes: List[spack.config.ConfigScope] = [ scopes: List[spack.config.ConfigScope] = [
*self.included_config_scopes, *self.included_config_scopes,
spack.config.SingleFileScope( spack.config.SingleFileScope(
self.scope_name, str(self.manifest_file), spack.schema.env.schema, [TOP_LEVEL_KEY] self.scope_name,
str(self.manifest_file),
spack.schema.env.schema,
yaml_path=[TOP_LEVEL_KEY],
), ),
] ]
ensure_no_disallowed_env_config_mods(scopes) ensure_no_disallowed_env_config_mods(scopes)

View File

@ -115,8 +115,8 @@ def default_config(tmpdir, config_directory, monkeypatch, install_mockery_mutabl
cfg = spack.config.Configuration( cfg = spack.config.Configuration(
*[ *[
spack.config.ConfigScope(name, str(mutable_dir)) spack.config.DirectoryConfigScope(name, str(mutable_dir))
for name in ["site/%s" % platform.system().lower(), "site", "user"] for name in [f"site/{platform.system().lower()}", "site", "user"]
] ]
) )

View File

@ -774,7 +774,7 @@ def test_keys_are_ordered(configuration_dir):
"./", "./",
) )
config_scope = spack.config.ConfigScope("modules", configuration_dir.join("site")) config_scope = spack.config.DirectoryConfigScope("modules", configuration_dir.join("site"))
data = config_scope.get_section("modules") data = config_scope.get_section("modules")
@ -956,7 +956,7 @@ def test_immutable_scope(tmpdir):
root: dummy_tree_value root: dummy_tree_value
""" """
) )
scope = spack.config.ImmutableConfigScope("test", str(tmpdir)) scope = spack.config.DirectoryConfigScope("test", str(tmpdir), writable=False)
data = scope.get_section("config") data = scope.get_section("config")
assert data["config"]["install_tree"] == {"root": "dummy_tree_value"} assert data["config"]["install_tree"] == {"root": "dummy_tree_value"}
@ -966,7 +966,9 @@ def test_immutable_scope(tmpdir):
def test_single_file_scope(config, env_yaml): def test_single_file_scope(config, env_yaml):
scope = spack.config.SingleFileScope("env", env_yaml, spack.schema.env.schema, ["spack"]) scope = spack.config.SingleFileScope(
"env", env_yaml, spack.schema.env.schema, yaml_path=["spack"]
)
with spack.config.override(scope): with spack.config.override(scope):
# from the single-file config # from the single-file config
@ -1002,7 +1004,9 @@ def test_single_file_scope_section_override(tmpdir, config):
""" """
) )
scope = spack.config.SingleFileScope("env", env_yaml, spack.schema.env.schema, ["spack"]) scope = spack.config.SingleFileScope(
"env", env_yaml, spack.schema.env.schema, yaml_path=["spack"]
)
with spack.config.override(scope): with spack.config.override(scope):
# from the single-file config # from the single-file config
@ -1018,7 +1022,7 @@ def test_single_file_scope_section_override(tmpdir, config):
def test_write_empty_single_file_scope(tmpdir): def test_write_empty_single_file_scope(tmpdir):
env_schema = spack.schema.env.schema env_schema = spack.schema.env.schema
scope = spack.config.SingleFileScope( scope = spack.config.SingleFileScope(
"test", str(tmpdir.ensure("config.yaml")), env_schema, ["spack"] "test", str(tmpdir.ensure("config.yaml")), env_schema, yaml_path=["spack"]
) )
scope._write_section("config") scope._write_section("config")
# confirm we can write empty config # confirm we can write empty config
@ -1217,7 +1221,9 @@ def test_license_dir_config(mutable_config, mock_packages):
@pytest.mark.regression("22547") @pytest.mark.regression("22547")
def test_single_file_scope_cache_clearing(env_yaml): def test_single_file_scope_cache_clearing(env_yaml):
scope = spack.config.SingleFileScope("env", env_yaml, spack.schema.env.schema, ["spack"]) scope = spack.config.SingleFileScope(
"env", env_yaml, spack.schema.env.schema, yaml_path=["spack"]
)
# Check that we can retrieve data from the single file scope # Check that we can retrieve data from the single file scope
before = scope.get_section("config") before = scope.get_section("config")
assert before assert before

View File

@ -719,9 +719,9 @@ def _create_mock_configuration_scopes(configuration_dir):
"""Create the configuration scopes used in `config` and `mutable_config`.""" """Create the configuration scopes used in `config` and `mutable_config`."""
return [ return [
spack.config.InternalConfigScope("_builtin", spack.config.CONFIG_DEFAULTS), spack.config.InternalConfigScope("_builtin", spack.config.CONFIG_DEFAULTS),
spack.config.ConfigScope("site", str(configuration_dir.join("site"))), spack.config.DirectoryConfigScope("site", str(configuration_dir.join("site"))),
spack.config.ConfigScope("system", str(configuration_dir.join("system"))), spack.config.DirectoryConfigScope("system", str(configuration_dir.join("system"))),
spack.config.ConfigScope("user", str(configuration_dir.join("user"))), spack.config.DirectoryConfigScope("user", str(configuration_dir.join("user"))),
spack.config.InternalConfigScope("command_line"), spack.config.InternalConfigScope("command_line"),
] ]
@ -755,7 +755,7 @@ def mutable_empty_config(tmpdir_factory, configuration_dir):
"""Empty configuration that can be modified by the tests.""" """Empty configuration that can be modified by the tests."""
mutable_dir = tmpdir_factory.mktemp("mutable_config").join("tmp") mutable_dir = tmpdir_factory.mktemp("mutable_config").join("tmp")
scopes = [ scopes = [
spack.config.ConfigScope(name, str(mutable_dir.join(name))) spack.config.DirectoryConfigScope(name, str(mutable_dir.join(name)))
for name in ["site", "system", "user"] for name in ["site", "system", "user"]
] ]
@ -790,7 +790,7 @@ def concretize_scope(mutable_config, tmpdir):
"""Adds a scope for concretization preferences""" """Adds a scope for concretization preferences"""
tmpdir.ensure_dir("concretize") tmpdir.ensure_dir("concretize")
mutable_config.push_scope( mutable_config.push_scope(
spack.config.ConfigScope("concretize", str(tmpdir.join("concretize"))) spack.config.DirectoryConfigScope("concretize", str(tmpdir.join("concretize")))
) )
yield str(tmpdir.join("concretize")) yield str(tmpdir.join("concretize"))
@ -802,10 +802,10 @@ def concretize_scope(mutable_config, tmpdir):
@pytest.fixture @pytest.fixture
def no_compilers_yaml(mutable_config): def no_compilers_yaml(mutable_config):
"""Creates a temporary configuration without compilers.yaml""" """Creates a temporary configuration without compilers.yaml"""
for scope, local_config in mutable_config.scopes.items(): for local_config in mutable_config.scopes.values():
if not local_config.path: # skip internal scopes if not isinstance(local_config, spack.config.DirectoryConfigScope):
continue continue
compilers_yaml = os.path.join(local_config.path, "compilers.yaml") compilers_yaml = local_config.get_section_filename("compilers")
if os.path.exists(compilers_yaml): if os.path.exists(compilers_yaml):
os.remove(compilers_yaml) os.remove(compilers_yaml)
return mutable_config return mutable_config
@ -814,7 +814,9 @@ def no_compilers_yaml(mutable_config):
@pytest.fixture() @pytest.fixture()
def mock_low_high_config(tmpdir): def mock_low_high_config(tmpdir):
"""Mocks two configuration scopes: 'low' and 'high'.""" """Mocks two configuration scopes: 'low' and 'high'."""
scopes = [spack.config.ConfigScope(name, str(tmpdir.join(name))) for name in ["low", "high"]] scopes = [
spack.config.DirectoryConfigScope(name, str(tmpdir.join(name))) for name in ["low", "high"]
]
with spack.config.use_configuration(*scopes) as config: with spack.config.use_configuration(*scopes) as config:
yield config yield config