comparison configmix/__init__.py @ 293:6f0bf673d4ff

Provide an optional "strict" flag to the top-level loader to pass it to low-level loaders that understand it. Currently only the YAML loader understands this flag.
author Franz Glasner <f.glasner@feldmann-mg.com>
date Wed, 10 Feb 2021 15:25:55 +0100
parents aec97edf7945
children eed16a1ec8f3
comparison
equal deleted inserted replaced
292:6a044778371a 293:6f0bf673d4ff
73 last 73 last
74 74
75 Use this for example to overwrite configuration file 75 Use this for example to overwrite configuration file
76 settings from commandline arguments. 76 settings from commandline arguments.
77 :type extras: dict-alike or None 77 :type extras: dict-alike or None
78 :keyword strict: enable strict parsing mode for parsers that support it
79 (e.g. to prevent duplicate keys)
80 :type strict: bool
78 :returns: the configuration 81 :returns: the configuration
79 :rtype: ~configmix.config.Configuration 82 :rtype: ~configmix.config.Configuration
80 83
81 """ 84 """
82 defaults = kwargs.get("defaults") 85 defaults = kwargs.get("defaults")
83 extras = kwargs.get("extras") 86 extras = kwargs.get("extras")
87 strict = kwargs.get("strict", False)
84 if defaults is None: 88 if defaults is None:
85 ex = Configuration() 89 ex = Configuration()
86 else: 90 else:
87 ex = merge(None, Configuration(defaults)) 91 ex = merge(None, Configuration(defaults))
88 for f in files: 92 for f in files:
89 if f.startswith(DIR_PREFIX): 93 if f.startswith(DIR_PREFIX):
90 for f2 in _get_configuration_files_from_dir(f[5:]): 94 for f2 in _get_configuration_files_from_dir(f[5:]):
91 nx = _load_cfg_from_file(f2, ignore_unknown=True) 95 nx = _load_cfg_from_file(f2, ignore_unknown=True, strict=strict)
92 if nx is not None: 96 if nx is not None:
93 ex = merge(nx, ex) 97 ex = merge(nx, ex)
94 else: 98 else:
95 nx = _load_cfg_from_file(f) 99 nx = _load_cfg_from_file(f, strict=strict)
96 if nx is not None: 100 if nx is not None:
97 ex = merge(nx, ex) 101 ex = merge(nx, ex)
98 if extras: 102 if extras:
99 ex = merge(Configuration(extras), ex) 103 ex = merge(Configuration(extras), ex)
100 return Configuration(ex) 104 return Configuration(ex)
105 instead of :func:`.merge` 109 instead of :func:`.merge`
106 110
107 """ 111 """
108 defaults = kwargs.get("defaults") 112 defaults = kwargs.get("defaults")
109 extras = kwargs.get("extras") 113 extras = kwargs.get("extras")
114 strict = kwargs.get("strict", False)
110 if defaults is None: 115 if defaults is None:
111 ex = Configuration() 116 ex = Configuration()
112 else: 117 else:
113 ex = safe_merge(None, Configuration(defaults)) 118 ex = safe_merge(None, Configuration(defaults))
114 for f in files: 119 for f in files:
115 if f.startswith(DIR_PREFIX): 120 if f.startswith(DIR_PREFIX):
116 for f2 in _get_configuration_files_from_dir(f[5:]): 121 for f2 in _get_configuration_files_from_dir(f[5:]):
117 nx = _load_cfg_from_file(f2, ignore_unknown=True) 122 nx = _load_cfg_from_file(f2, ignore_unknown=True, strict=strict)
118 if nx is not None: 123 if nx is not None:
119 ex = safe_merge(nx, ex) 124 ex = safe_merge(nx, ex)
120 else: 125 else:
121 nx = _load_cfg_from_file(f) 126 nx = _load_cfg_from_file(f, strict=strict)
122 if nx is not None: 127 if nx is not None:
123 ex = safe_merge(nx, ex) 128 ex = safe_merge(nx, ex)
124 if extras: 129 if extras:
125 ex = safe_merge(Configuration(extras), ex) 130 ex = safe_merge(Configuration(extras), ex)
126 return Configuration(ex) 131 return Configuration(ex)
144 continue 149 continue
145 files.append(path) 150 files.append(path)
146 return files 151 return files
147 152
148 153
149 def _load_yaml(filename): 154 def _load_yaml(filename, strict=False):
150 from . import yaml 155 from . import yaml
151 with open(u2fs(filename), "rb") as yf: 156 with open(u2fs(filename), "rb") as yf:
152 return yaml.safe_load(yf) 157 return yaml.safe_load(yf, strict=strict)
153 158
154 159
155 def _load_json(filename): 160 def _load_json(filename, strict=False):
156 from . import json 161 from . import json
157 return json.load(filename) 162 return json.load(filename)
158 163
159 164
160 def _load_py(filename): 165 def _load_py(filename, strict=False):
161 from . import py 166 from . import py
162 return py.load(filename) 167 return py.load(filename)
163 168
164 169
165 def _load_ini(filename): 170 def _load_ini(filename, strict=False):
166 from . import ini 171 from . import ini
167 return ini.load(filename) 172 return ini.load(filename)
168 173
169 174
170 def _load_toml(filename): 175 def _load_toml(filename, strict=False):
171 from . import toml 176 from . import toml
172 return toml.load(filename) 177 return toml.load(filename)
173 178
174 179
175 def _load_ignore(filename): 180 def _load_ignore(filename, strict=False):
176 """A loader that returns `None` just to ignore `filename`""" 181 """A loader that returns `None` just to ignore `filename`"""
177 return None 182 return None
178 183
179 184
180 EMACS_MODELINE = re.compile(r"-\*-(.*?)-\*-") 185 EMACS_MODELINE = re.compile(r"-\*-(.*?)-\*-")
357 break # restart 362 break # restart
358 else: 363 else:
359 return # nothing deleted -> done 364 return # nothing deleted -> done
360 365
361 366
362 def _load_cfg_from_file(filename, ignore_unknown=False): 367 def _load_cfg_from_file(filename, ignore_unknown=False, strict=False):
363 """Determine the loader for file `filename` and return the loaded 368 """Determine the loader for file `filename` and return the loaded
364 configuration dict. 369 configuration dict.
365 370
366 If `ignore_unknown` is `True` then unknown extensions are ignored. 371 If `ignore_unknown` is `True` then unknown extensions are ignored.
367 Otherwise a :exc:`ValueError` exception is raised. 372 Otherwise a :exc:`ValueError` exception is raised.
373 if fnmatch.fnmatch(filename, p): 378 if fnmatch.fnmatch(filename, p):
374 if callable(m): 379 if callable(m):
375 m = m(filename) 380 m = m(filename)
376 if m is None: 381 if m is None:
377 continue 382 continue
378 return mode_loaders[m](filename) 383 return mode_loaders[m](filename, strict=strict)
379 else: 384 else:
380 if ignore_unknown: 385 if ignore_unknown:
381 return None 386 return None
382 else: 387 else:
383 raise ValueError("Unknown configuration file type for filename " 388 raise ValueError("Unknown configuration file type for filename "