1"""Configuration management setup
5 As written in config files.
7 Value associated with a name
9 Name combined with it's section (section.name)
11 A single word describing where the configuration key-value pair came from
18from typing
import Any, Dict, Iterable, List, NewType, Optional, Tuple
22 ConfigurationFileCouldNotBeLoaded,
30Kind = NewType(
"Kind", str)
32CONFIG_BASENAME =
"pip.ini" if WINDOWS
else "pip.conf"
33ENV_NAMES_IGNORED =
"version",
"help"
46logger = getLogger(__name__)
51 """Make a name consistent regardless of source (environment or file)"""
61 "Key does not contain dot separated section and key. "
62 "Perhaps you wanted to use 'global.{}' instead?"
69 global_config_files = [
76 "pip" if WINDOWS
else ".pip",
83 kinds.USER: [legacy_config_file, new_config_file],
88 """Handles management of configuration.
90 Provides an interface to accessing and managing configuration files.
92 This class converts provides an API that takes "section.key-name" style
93 keys and stores the value associated with it as "key-name" under the
96 This allows for a clean interface wherein the both the section and the
97 key-name are preserved in an easy to manage form in the configuration files
98 and the data stored is also nice.
101 def __init__(self, isolated: bool, load_only: Optional[Kind] =
None) ->
None:
104 if load_only
is not None and load_only
not in VALID_LOAD_ONLY:
106 "Got invalid value for load_only - should be one of {}".format(
107 ", ".join(map(repr, VALID_LOAD_ONLY))
114 self._parsers: Dict[Kind, List[Tuple[str, RawConfigParser]]] = {
115 variant: []
for variant
in OVERRIDE_ORDER
117 self._config: Dict[Kind, Dict[str, Any]] = {
118 variant: {}
for variant
in OVERRIDE_ORDER
120 self._modified_parsers: List[Tuple[str, RawConfigParser]] = []
122 def load(self) -> None:
123 """Loads configuration from configuration files and environment"""
129 """Returns the file with highest priority in configuration"""
130 assert self.
load_only is not None,
"Need to be specified a file to be editing"
137 def items(self) -> Iterable[Tuple[str, Any]]:
138 """Returns key-value pairs like dict.items() representing the loaded
144 """Get a value from the configuration."""
156 """Modify a value in the configuration."""
163 if parser
is not None:
171 self._config[self.
load_only][key] = value
175 """Unset a value in the configuration."""
181 if key
not in self._config[self.
load_only]:
186 if parser
is not None:
193 "Fatal Internal error [id=1]. Please report as a bug."
204 """Save the current in-memory state."""
207 for fname, parser
in self._modified_parsers:
215 with open(fname,
"w")
as f:
217 except OSError
as error:
219 f
"An error occurred while writing to the configuration file "
234 """A dictionary representing the loaded configuration."""
239 for variant
in OVERRIDE_ORDER:
245 """Loads configuration from configuration files"""
249 "Skipping loading configuration files due to "
250 "environment's PIP_CONFIG_FILE being os.devnull"
259 logger.debug(
"Skipping file '%s' (variant: %s)", fname, variant)
265 self._parsers[variant].append((fname, parser))
267 def _load_file(self, variant: Kind, fname: str) -> RawConfigParser:
268 logger.verbose(
"For variant '%s', will try loading '%s'", variant, fname)
287 except UnicodeDecodeError:
290 reason=f
"contains invalid {locale_encoding} characters",
299 """Loads configuration from environment variables"""
305 self, section: str, items: Iterable[Tuple[str, Any]]
307 """Normalizes items to construct a dictionary with normalized keys.
309 This routine is where the names become keys and are made the same
310 regardless of source - configuration files or environment.
313 for name, val
in items:
315 normalized[key] = val
319 """Returns a generator with all environmental vars with prefix PIP_"""
322 name = key[4:].
lower()
323 if name
not in ENV_NAMES_IGNORED:
328 """Yields variant and configuration files associated with it.
330 This should be treated like items of a dictionary.
336 if config_file
is not None:
347 should_load_user_config =
not self.
isolated and not (
350 if should_load_user_config:
358 """Get values present in a config file"""
359 return self._config[variant]
368 "Fatal Internal error [id=2]. Please report as a bug."
376 file_parser_tuple = (fname, parser)
377 if file_parser_tuple
not in self._modified_parsers:
378 self._modified_parsers.append(file_parser_tuple)
381 return f
"{self.__class__.__name__}({self._dictionary!r})"
Dict[str, Any] _dictionary(self)
None _load_config_files(self)
Iterable[Tuple[str, str]] get_environ_vars(self)
Optional[str] get_file_to_edit(self)
None _mark_as_modified(self, str fname, RawConfigParser parser)
RawConfigParser _load_file(self, Kind variant, str fname)
Tuple[str, RawConfigParser] _get_parser_to_modify(self)
Iterable[Tuple[str, Any]] items(self)
Dict[str, Any] _normalized_keys(self, str section, Iterable[Tuple[str, Any]] items)
Any get_value(self, str key)
None set_value(self, str key, Any value)
Iterable[Tuple[Kind, List[str]]] iter_config_files(self)
None _load_environment_vars(self)
Dict[str, Any] get_values_in_config(self, Kind variant)
None unset_value(self, str key)
RawConfigParser _construct_parser(self, str fname)
None __init__(self, bool isolated, Optional[Kind] load_only=None)
None _ensure_have_load_only(self)
str _normalize_name(str name)
Dict[Kind, List[str]] get_configuration_files()
List[str] _disassemble_key(str name)