Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/cardinal_pythonlib/configfiles.py : 58%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/env python
2# cardinal_pythonlib/configfiles.py
4"""
5===============================================================================
7 Original code copyright (C) 2009-2021 Rudolf Cardinal (rudolf@pobox.com).
9 This file is part of cardinal_pythonlib.
11 Licensed under the Apache License, Version 2.0 (the "License");
12 you may not use this file except in compliance with the License.
13 You may obtain a copy of the License at
15 https://www.apache.org/licenses/LICENSE-2.0
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
23===============================================================================
25**Support functions for config (.INI) file reading.**
27"""
29from configparser import ConfigParser, NoOptionError
30import logging
31from typing import Any, Callable, Iterable, List
33from cardinal_pythonlib.logs import get_brace_style_log_with_null_handler
35log = get_brace_style_log_with_null_handler(__name__)
38# =============================================================================
39# Style 1
40# =============================================================================
42def get_config_string_option(parser: ConfigParser,
43 section: str,
44 option: str,
45 default: str = None) -> str:
46 """
47 Retrieves a string value from a parser.
49 Args:
50 parser: instance of :class:`ConfigParser`
51 section: section name within config file
52 option: option (variable) name within that section
53 default: value to return if option is absent
55 Returns:
56 string value
58 Raises:
59 ValueError: if the section is absent
61 """
62 if not parser.has_section(section):
63 raise ValueError("config missing section: " + section)
64 return parser.get(section, option, fallback=default)
67def read_config_string_options(obj: Any,
68 parser: ConfigParser,
69 section: str,
70 options: Iterable[str],
71 default: str = None) -> None:
72 """
73 Reads config options and writes them as attributes of ``obj``, with
74 attribute names as per ``options``.
76 Args:
77 obj: the object to modify
78 parser: instance of :class:`ConfigParser`
79 section: section name within config file
80 options: option (variable) names within that section
81 default: value to use for any missing options
83 Returns:
85 """
86 # enforce_str removed; ConfigParser always returns strings unless asked
87 # specifically
88 for o in options:
89 setattr(obj, o, get_config_string_option(parser, section, o,
90 default=default))
93def get_config_multiline_option(parser: ConfigParser,
94 section: str,
95 option: str,
96 default: List[str] = None) -> List[str]:
97 """
98 Retrieves a multi-line string value from a parser as a list of strings
99 (one per line, ignoring blank lines).
101 Args:
102 parser: instance of :class:`ConfigParser`
103 section: section name within config file
104 option: option (variable) name within that section
105 default: value to return if option is absent (``None`` is mapped to
106 ``[]``)
108 Returns:
109 list of strings
111 Raises:
112 ValueError: if the section is absent
114 """
115 default = default or []
116 if not parser.has_section(section):
117 raise ValueError("config missing section: " + section)
118 try:
119 multiline = parser.get(section, option)
120 values = [x.strip() for x in multiline.splitlines() if x.strip()]
121 return values
122 except NoOptionError:
123 return default
126def read_config_multiline_options(obj: Any,
127 parser: ConfigParser,
128 section: str,
129 options: Iterable[str]) -> None:
130 """
131 This is to :func:`read_config_string_options` as
132 :func:`get_config_multiline_option` is to :func:`get_config_string_option`.
133 """
134 for o in options:
135 setattr(obj, o, get_config_multiline_option(parser, section, o))
138def get_config_bool_option(parser: ConfigParser,
139 section: str,
140 option: str,
141 default: bool = None) -> bool:
142 """
143 Retrieves a boolean value from a parser.
145 Args:
146 parser: instance of :class:`ConfigParser`
147 section: section name within config file
148 option: option (variable) name within that section
149 default: value to return if option is absent
151 Returns:
152 Boolean value
154 Raises:
155 ValueError: if the section is absent
157 """
158 if not parser.has_section(section):
159 raise ValueError("config missing section: " + section)
160 return parser.getboolean(section, option, fallback=default)
163# =============================================================================
164# Style 2
165# =============================================================================
167# =============================================================================
168# Reading config files: style 2
169# =============================================================================
171def get_config_parameter(config: ConfigParser,
172 section: str,
173 param: str,
174 fn: Callable[[Any], Any],
175 default: Any = None,
176 loglevel: int = logging.DEBUG) -> Any:
177 """
178 Fetch parameter from ``configparser`` ``.INI`` file.
180 Args:
181 config: :class:`ConfigParser` object
182 section: section name within config file
183 param: name of parameter within section
184 fn: function to apply to string parameter (e.g. ``int``)
185 default: default value
186 loglevel: log level if default is needed
188 Returns:
189 parameter value, or ``None`` if ``default is None``, or ``fn(default)``
190 """
191 try:
192 value = fn(config.get(section, param))
193 except (TypeError, ValueError, NoOptionError):
194 log.log(
195 level=loglevel,
196 msg=f"Configuration variable {param} not found or improper in "
197 f"section [{section}]; using default of {default!r}")
198 if default is None:
199 value = default
200 else:
201 value = fn(default)
202 return value
205def get_config_parameter_boolean(config: ConfigParser,
206 section: str,
207 param: str,
208 default: bool,
209 loglevel: int = logging.DEBUG) -> bool:
210 """
211 Get Boolean parameter from ``configparser`` ``.INI`` file.
213 Args:
214 config: :class:`ConfigParser` object
215 section: section name within config file
216 param: name of parameter within section
217 default: default value
218 loglevel: log level if default is needed
219 Returns:
220 parameter value, or default
221 """
222 try:
223 value = config.getboolean(section, param)
224 except (TypeError, ValueError, NoOptionError):
225 log.log(
226 level=loglevel,
227 msg=f"Configuration variable {param} not found or improper in "
228 f"section [{section}]; using default of {default!r}")
229 value = default
230 return value
233def get_config_parameter_loglevel(config: ConfigParser,
234 section: str,
235 param: str,
236 default: int,
237 loglevel: int = logging.DEBUG) -> int:
238 """
239 Get ``loglevel`` parameter from ``configparser`` ``.INI`` file, e.g.
240 mapping ``'debug'`` to ``logging.DEBUG``.
242 Args:
243 config: :class:`ConfigParser` object
244 section: section name within config file
245 param: name of parameter within section
246 default: default value
247 loglevel: log level if default is needed
248 Returns:
249 parameter value, or default
250 """
251 try:
252 value = config.get(section, param).lower()
253 if value == "debug":
254 return logging.DEBUG # 10
255 elif value == "info":
256 return logging.INFO
257 elif value in ["warn", "warning"]:
258 return logging.WARN
259 elif value == "error":
260 return logging.ERROR
261 elif value in ["critical", "fatal"]:
262 return logging.CRITICAL # 50
263 else:
264 raise ValueError
265 except (TypeError, ValueError, NoOptionError, AttributeError):
266 log.log(
267 level=loglevel,
268 msg=f"Configuration variable {param} not found or improper in "
269 f"section [{section}]; using default of {default!r}")
270 return default
273def get_config_parameter_multiline(config: ConfigParser,
274 section: str,
275 param: str,
276 default: List[str],
277 loglevel: int = logging.DEBUG) -> List[str]:
278 """
279 Get multi-line string parameter from ``configparser`` ``.INI`` file,
280 as a list of strings (one per line, ignoring blank lines).
282 Args:
283 config: :class:`ConfigParser` object
284 section: section name within config file
285 param: name of parameter within section
286 default: default value
287 loglevel: log level if default is needed
288 Returns:
289 parameter value, or default
290 """
291 try:
292 multiline = config.get(section, param)
293 lines = [x.strip() for x in multiline.splitlines()]
294 return [line for line in lines if line]
295 except (TypeError, ValueError, NoOptionError):
296 log.log(
297 level=loglevel,
298 msg=f"Configuration variable {param} not found or improper in "
299 f"section [{section}]; using default of {default!r}")
300 return default