summaryrefslogtreecommitdiff
path: root/src/home/config/config.py
diff options
context:
space:
mode:
authorEvgeny Zinoviev <me@ch1p.io>2023-09-27 00:54:57 +0300
committerEvgeny Zinoviev <me@ch1p.io>2023-09-27 00:54:57 +0300
commitd3a295872c49defb55fc8e4e43e55550991e0927 (patch)
treeb9dca15454f9027d5a9dad0d4443a20de04dbc5d /src/home/config/config.py
parentb7cbc2571c1870b4582ead45277d0aa7f961bec8 (diff)
parentbdbb296697f55f4c3a07af43c9aaf7a9ea86f3d0 (diff)
Merge branch 'master' of ch1p.io:homekit
Diffstat (limited to 'src/home/config/config.py')
-rw-r--r--src/home/config/config.py204
1 files changed, 0 insertions, 204 deletions
diff --git a/src/home/config/config.py b/src/home/config/config.py
deleted file mode 100644
index 4681685..0000000
--- a/src/home/config/config.py
+++ /dev/null
@@ -1,204 +0,0 @@
-import toml
-import yaml
-import logging
-import os
-
-from os.path import join, isdir, isfile
-from typing import Optional, Any, MutableMapping
-from argparse import ArgumentParser
-from ..util import parse_addr
-
-
-def _get_config_path(name: str) -> str:
- formats = ['toml', 'yaml']
-
- dirname = join(os.environ['HOME'], '.config', name)
-
- if isdir(dirname):
- for fmt in formats:
- filename = join(dirname, f'config.{fmt}')
- if isfile(filename):
- return filename
-
- raise IOError(f'config not found in {dirname}')
-
- else:
- filenames = [join(os.environ['HOME'], '.config', f'{name}.{format}') for format in formats]
- for file in filenames:
- if isfile(file):
- return file
-
- raise IOError(f'config not found')
-
-
-class ConfigStore:
- data: MutableMapping[str, Any]
- app_name: Optional[str]
-
- def __init__(self):
- self.data = {}
- self.app_name = None
-
- def load(self, name: Optional[str] = None,
- use_cli=True,
- parser: ArgumentParser = None):
- self.app_name = name
-
- if (name is None) and (not use_cli):
- raise RuntimeError('either config name must be none or use_cli must be True')
-
- log_default_fmt = False
- log_file = None
- log_verbose = False
- no_config = name is False
-
- path = None
- if use_cli:
- if parser is None:
- parser = ArgumentParser()
- if not no_config:
- parser.add_argument('-c', '--config', type=str, required=name is None,
- help='Path to the config in TOML or YAML format')
- parser.add_argument('-V', '--verbose', action='store_true')
- parser.add_argument('--log-file', type=str)
- parser.add_argument('--log-default-fmt', action='store_true')
- args = parser.parse_args()
-
- if not no_config and args.config:
- path = args.config
-
- if args.verbose:
- log_verbose = True
- if args.log_file:
- log_file = args.log_file
- if args.log_default_fmt:
- log_default_fmt = args.log_default_fmt
-
- if not no_config and path is None:
- path = _get_config_path(name)
-
- if no_config:
- self.data = {}
- else:
- if path.endswith('.toml'):
- self.data = toml.load(path)
- elif path.endswith('.yaml'):
- with open(path, 'r') as fd:
- self.data = yaml.safe_load(fd)
-
- if 'logging' in self:
- if not log_file and 'file' in self['logging']:
- log_file = self['logging']['file']
- if log_default_fmt and 'default_fmt' in self['logging']:
- log_default_fmt = self['logging']['default_fmt']
-
- setup_logging(log_verbose, log_file, log_default_fmt)
-
- if use_cli:
- return args
-
- def __getitem__(self, key):
- return self.data[key]
-
- def __setitem__(self, key, value):
- raise NotImplementedError('overwriting config values is prohibited')
-
- def __contains__(self, key):
- return key in self.data
-
- def get(self, key: str, default=None):
- cur = self.data
- pts = key.split('.')
- for i in range(len(pts)):
- k = pts[i]
- if i < len(pts)-1:
- if k not in cur:
- raise KeyError(f'key {k} not found')
- else:
- return cur[k] if k in cur else default
- cur = self.data[k]
- raise KeyError(f'option {key} not found')
-
- def get_addr(self, key: str):
- return parse_addr(self.get(key))
-
- def items(self):
- return self.data.items()
-
-
-config = ConfigStore()
-
-
-def is_development_mode() -> bool:
- if 'HK_MODE' in os.environ and os.environ['HK_MODE'] == 'dev':
- return True
-
- return ('logging' in config) and ('verbose' in config['logging']) and (config['logging']['verbose'] is True)
-
-
-def setup_logging(verbose=False, log_file=None, default_fmt=False):
- logging_level = logging.INFO
- if is_development_mode() or verbose:
- logging_level = logging.DEBUG
- _add_logging_level('TRACE', logging.DEBUG-5)
-
- log_config = {'level': logging_level}
- if not default_fmt:
- log_config['format'] = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
-
- if log_file is not None:
- log_config['filename'] = log_file
- log_config['encoding'] = 'utf-8'
-
- logging.basicConfig(**log_config)
-
-
-# https://stackoverflow.com/questions/2183233/how-to-add-a-custom-loglevel-to-pythons-logging-facility/35804945#35804945
-def _add_logging_level(levelName, levelNum, methodName=None):
- """
- Comprehensively adds a new logging level to the `logging` module and the
- currently configured logging class.
-
- `levelName` becomes an attribute of the `logging` module with the value
- `levelNum`. `methodName` becomes a convenience method for both `logging`
- itself and the class returned by `logging.getLoggerClass()` (usually just
- `logging.Logger`). If `methodName` is not specified, `levelName.lower()` is
- used.
-
- To avoid accidental clobberings of existing attributes, this method will
- raise an `AttributeError` if the level name is already an attribute of the
- `logging` module or if the method name is already present
-
- Example
- -------
- >>> addLoggingLevel('TRACE', logging.DEBUG - 5)
- >>> logging.getLogger(__name__).setLevel("TRACE")
- >>> logging.getLogger(__name__).trace('that worked')
- >>> logging.trace('so did this')
- >>> logging.TRACE
- 5
-
- """
- if not methodName:
- methodName = levelName.lower()
-
- if hasattr(logging, levelName):
- raise AttributeError('{} already defined in logging module'.format(levelName))
- if hasattr(logging, methodName):
- raise AttributeError('{} already defined in logging module'.format(methodName))
- if hasattr(logging.getLoggerClass(), methodName):
- raise AttributeError('{} already defined in logger class'.format(methodName))
-
- # This method was inspired by the answers to Stack Overflow post
- # http://stackoverflow.com/q/2183233/2988730, especially
- # http://stackoverflow.com/a/13638084/2988730
- def logForLevel(self, message, *args, **kwargs):
- if self.isEnabledFor(levelNum):
- self._log(levelNum, message, args, **kwargs)
- def logToRoot(message, *args, **kwargs):
- logging.log(levelNum, message, *args, **kwargs)
-
- logging.addLevelName(levelNum, levelName)
- setattr(logging, levelName, levelNum)
- setattr(logging.getLoggerClass(), methodName, logForLevel)
- setattr(logging, methodName, logToRoot) \ No newline at end of file