summaryrefslogtreecommitdiff
path: root/lib/spack/spack/config.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/spack/config.py')
-rw-r--r--lib/spack/spack/config.py65
1 files changed, 36 insertions, 29 deletions
diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py
index 3bfd0b18ed..46cf0232d0 100644
--- a/lib/spack/spack/config.py
+++ b/lib/spack/spack/config.py
@@ -36,7 +36,7 @@ import os
import re
import sys
from contextlib import contextmanager
-from typing import List
+from typing import Dict, List, Optional
import ruamel.yaml as yaml
from ruamel.yaml.error import MarkedYAMLError
@@ -391,41 +391,44 @@ class Configuration(object):
This class makes it easy to add a new scope on top of an existing one.
"""
- def __init__(self, *scopes):
+ # convert to typing.OrderedDict when we drop 3.6, or OrderedDict when we reach 3.9
+ scopes: Dict[str, ConfigScope]
+
+ def __init__(self, *scopes: ConfigScope):
"""Initialize a configuration with an initial list of scopes.
Args:
- scopes (list of ConfigScope): list of scopes to add to this
+ scopes: list of scopes to add to this
Configuration, ordered from lowest to highest precedence
"""
self.scopes = collections.OrderedDict()
for scope in scopes:
self.push_scope(scope)
- self.format_updates = collections.defaultdict(list)
+ self.format_updates: Dict[str, List[str]] = collections.defaultdict(list)
@_config_mutator
- def push_scope(self, scope):
+ def push_scope(self, scope: ConfigScope):
"""Add a higher precedence scope to the Configuration."""
tty.debug("[CONFIGURATION: PUSH SCOPE]: {}".format(str(scope)), level=2)
self.scopes[scope.name] = scope
@_config_mutator
- def pop_scope(self):
+ def pop_scope(self) -> ConfigScope:
"""Remove the highest precedence scope and return it."""
- name, scope = self.scopes.popitem(last=True)
+ name, scope = self.scopes.popitem(last=True) # type: ignore[call-arg]
tty.debug("[CONFIGURATION: POP SCOPE]: {}".format(str(scope)), level=2)
return scope
@_config_mutator
- def remove_scope(self, scope_name):
+ def remove_scope(self, scope_name: str) -> Optional[ConfigScope]:
"""Remove scope by name; has no effect when ``scope_name`` does not exist"""
scope = self.scopes.pop(scope_name, None)
tty.debug("[CONFIGURATION: POP SCOPE]: {}".format(str(scope)), level=2)
return scope
@property
- def file_scopes(self):
+ def file_scopes(self) -> List[ConfigScope]:
"""List of writable scopes with an associated file."""
return [
s
@@ -433,21 +436,21 @@ class Configuration(object):
if (type(s) == ConfigScope or type(s) == SingleFileScope)
]
- def highest_precedence_scope(self):
+ def highest_precedence_scope(self) -> ConfigScope:
"""Non-internal scope with highest precedence."""
- return next(reversed(self.file_scopes), None)
+ return next(reversed(self.file_scopes))
- def highest_precedence_non_platform_scope(self):
+ def highest_precedence_non_platform_scope(self) -> ConfigScope:
"""Non-internal non-platform scope with highest precedence
Platform-specific scopes are of the form scope/platform"""
generator = reversed(self.file_scopes)
- highest = next(generator, None)
+ highest = next(generator)
while highest and highest.is_platform_dependent:
- highest = next(generator, None)
+ highest = next(generator)
return highest
- def matching_scopes(self, reg_expr):
+ def matching_scopes(self, reg_expr) -> List[ConfigScope]:
"""
List of all scopes whose names match the provided regular expression.
@@ -456,7 +459,7 @@ class Configuration(object):
"""
return [s for s in self.scopes.values() if re.search(reg_expr, s.name)]
- def _validate_scope(self, scope):
+ def _validate_scope(self, scope: Optional[str]) -> ConfigScope:
"""Ensure that scope is valid in this configuration.
This should be used by routines in ``config.py`` to validate
@@ -481,7 +484,7 @@ class Configuration(object):
"Invalid config scope: '%s'. Must be one of %s" % (scope, self.scopes.keys())
)
- def get_config_filename(self, scope, section):
+ def get_config_filename(self, scope, section) -> str:
"""For some scope and section, get the name of the configuration file."""
scope = self._validate_scope(scope)
return scope.get_section_filename(section)
@@ -495,7 +498,9 @@ class Configuration(object):
scope.clear()
@_config_mutator
- def update_config(self, section, update_data, scope=None, force=False):
+ def update_config(
+ self, section: str, update_data: Dict, scope: Optional[str] = None, force: bool = False
+ ):
"""Update the configuration file for a particular scope.
Overwrites contents of a section in a scope with update_data,
@@ -1315,14 +1320,15 @@ def raw_github_gitlab_url(url):
return url
-def collect_urls(base_url):
+def collect_urls(base_url: str) -> list:
"""Return a list of configuration URLs.
Arguments:
- base_url (str): URL for a configuration (yaml) file or a directory
+ base_url: URL for a configuration (yaml) file or a directory
containing yaml file(s)
- Returns: (list) list of configuration file(s) or empty list if none
+ Returns:
+ List of configuration file(s) or empty list if none
"""
if not base_url:
return []
@@ -1337,20 +1343,21 @@ def collect_urls(base_url):
return [link for link in links if link.endswith(extension)]
-def fetch_remote_configs(url, dest_dir, skip_existing=True):
+def fetch_remote_configs(url: str, dest_dir: str, skip_existing: bool = True) -> str:
"""Retrieve configuration file(s) at the specified URL.
Arguments:
- url (str): URL for a configuration (yaml) file or a directory containing
+ url: URL for a configuration (yaml) file or a directory containing
yaml file(s)
- dest_dir (str): destination directory
- skip_existing (bool): Skip files that already exist in dest_dir if
+ dest_dir: destination directory
+ skip_existing: Skip files that already exist in dest_dir if
``True``; otherwise, replace those files
- Returns: (str) path to the corresponding file if URL is or contains a
- single file and it is the only file in the destination directory or
- the root (dest_dir) directory if multiple configuration files exist
- or are retrieved.
+ Returns:
+ Path to the corresponding file if URL is or contains a
+ single file and it is the only file in the destination directory or
+ the root (dest_dir) directory if multiple configuration files exist
+ or are retrieved.
"""
def _fetch_file(url):