Source code for pyfileconf.opts

"""
Options system for pyfileconf

To add a new option, the attribute and type hint to PyfileconfOptions,
add it to PyfileconfOptions.option_attrs,
add it to init and initialize it with the default,
and add a param docstring for it to PyfileconfOptionsManager.

Optionally, functions can be registered in PyfileconfOptions.option_callbacks
to perform an action upon setting or resetting the option. The callbacks
should accept the name of the option as the first argument and the value
being set as the second argument.
"""

from typing import Any, Tuple, Dict, Type, Iterable, List, Optional, Callable

from pyfileconf.logger.logger import logger
from pyfileconf.opts.filelog import add_file_handler_if_log_folder_exists_else_remove_handler


[docs]class PyfileconfOptions: log_stdout: bool log_folder: Optional[str] log_file_rollover_freq: str log_file_num_keep: int option_attrs: Tuple[str, ...] = ( 'log_stdout', 'log_folder', 'log_file_rollover_freq', 'log_file_num_keep', ) option_callbacks: Dict[str, Callable[[str, Any], None]] = { 'log_folder': add_file_handler_if_log_folder_exists_else_remove_handler }
[docs] def __init__(self, log_stdout: bool = False, log_folder: Optional[str] = None, log_file_rollover_freq: str = 'D', log_file_num_keep: int = 0): self.log_stdout = log_stdout self.log_folder = log_folder self.log_file_rollover_freq = log_file_rollover_freq self.log_file_num_keep = log_file_num_keep
[docs] def update(self, opts: 'PyfileconfOptions'): for attr in self.option_attrs: new_value = getattr(opts, attr) setattr(self, attr, new_value)
DEFAULT_OPTIONS = PyfileconfOptions() options = PyfileconfOptions()
[docs]class PyfileconfOption:
[docs] def __init__(self, name: str, callback: Optional[Callable[[str, Any], None]] = None): if callback is None: try: callback = PyfileconfOptions.option_callbacks[name] except KeyError: pass self.name = name self.callback = callback
@property def value(self) -> Any: return getattr(options, self.name) @value.setter def value(self, val: Any): orig_value = getattr(options, self.name) setattr(options, self.name, val) if self.callback is not None and orig_value != val: self.callback(self.name, val) @property def default_value(self) -> Any: return getattr(DEFAULT_OPTIONS, self.name)
[docs] def reset(self): logger.debug(f"Resetting option {self.name}") self.value = self.default_value
def __repr__(self): return f'<PyfileconfOption(name={self.name}, value={self.value}, ' \ f'default_value={self.default_value})>'
[docs]class PyfileconfOptionsManager: """ Allows setting options for the pyfileconf library :Usage: >>> import pyfileconf Use as a context manager with a single change: >>> with pyfileconf.options.set_option('log_stdout', True): >>> # Do something >>> # Now options have been reset Use as a context manager with multiple individual changes: >>> with pyfileconf.options: >>> # Change using set_option and the attribute name >>> pyfileconf.options.set_option('log_stdout', True) >>> # Change using option value attribute >>> pyfileconf.options.log_stdout = True >>> # More options changes, then desired operations >>> # Now options have been reset Use as a context manager with multiple changes at once: >>> with pyfileconf.options.set_options([('log_stdout', True), ('log_folder', 'MyLogs')]): >>> # Operations needing options >>> # Now options have been reset Usage without context manager. The following three are equivalent to set options: >>> pyfileconf.options.set_option("log_stdout", True) >>> pyfileconf.options.set_options([("log_stdout", True)]) >>> pyfileconf.options.log_stdout.value = True When using without the context manager, options will last until they are reset. Options can be reset individually, as a group, or all at once. >>> pyfileconf.options.log_stdout.reset() # reset only the log_stdout option >>> pyfileconf.options.reset_option('log_stdout') # reset only the log_stdout option # reset only the log_stdout option, but other options could be included >>> pyfileconf.options.reset_options(['log_stdout']) >>> pyfileconf.options.reset() # reset all the options :Available Options: :param log_stdout: Whether to capture stdout and log it in the pyfileconf logger :type log_stdout: bool :param log_folder: The folder in which logs should be stored :type log_folder: Optional[str] :param log_file_rollover_freq: How often to roll over to a new log file, see :py:class:`logging.handlers.TimedRotatingFileHandler` when option :param log_file_num_keep: Number of log files to keep, see :py:class:`logging.handlers.TimedRotatingFileHandler` backupCount option """
[docs] def __init__(self): self._options: List[PyfileconfOption] = [] for attr in options.option_attrs: opt = PyfileconfOption(attr) setattr(self, attr, opt) self._options.append(opt)
def __repr__(self): opts_str = '\t' + '\n\t'.join(repr(opt) for opt in self._options) + '\n' return f'<PyfileconfOptionsManager(options=[\n{opts_str}])>' def __dir__(self) -> Iterable[str]: orig_items = super().__dir__() return list(orig_items) + list(options.option_attrs)
[docs] def reset(self): """ Undo all changes made through the options interface :return: """ logger.debug(f"Resetting pyfileconf options") for attr in options.option_attrs: opt = getattr(self, attr) opt.reset()
[docs] def set_option(self, attr: str, value: Any): """ Set a particular option by its name :param attr: Option name :param value: New option value :return: """ logger.debug(f"Setting option {attr} to {value}") opt: PyfileconfOption = getattr(self, attr) opt.value = value return self
[docs] def set_options(self, updates: Iterable[Tuple[str, Any]]): """ Set multiple options at once by their name :param updates: Multiple option updates :return: :Examples: >>> import pyfileconf >>> pyfileconf.options.set_options([('log_stdout', True), ('log_folder', 'MyLogs')]) """ for attr, value in updates: logger.debug(f"Setting option {attr} to {value}") opt: PyfileconfOption = getattr(self, attr) opt.value = value return self
[docs] def reset_option(self, attr: str): """ Reset a particular option by name :param attr: Name of option :return: """ logger.debug(f'Resetting option {attr}') opt: PyfileconfOption = getattr(self, attr) opt.reset()
[docs] def reset_options(self, attrs: Iterable[str]): """ Reset multiple options at once by their names :param attrs: Option names :return: """ for attr in attrs: self.reset_option(attr)
def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.reset()
options_interface = PyfileconfOptionsManager()