Skip to content

Instantly share code, notes, and snippets.

@ankona
Last active October 13, 2021 05:30
Show Gist options
  • Save ankona/38a83f48050a40d7eaddceb61e46e57b to your computer and use it in GitHub Desktop.
Save ankona/38a83f48050a40d7eaddceb61e46e57b to your computer and use it in GitHub Desktop.
simple cfg
import os
from typing import Tuple, Dict
class TypeConverter(object):
def as_boolean(self, value: str) -> object:
bool_strings = ['true', 'on', 'yes', 'false', 'off', 'no']
if value.lower() in bool_strings[:len(bool_strings)//2]:
return True
if value.lower() in bool_strings[len(bool_strings)//2:]:
return False
return None
def convert_cfg_type(self, value: str) -> object:
"""
Attempt some type conversions and return best choice.
"""
if not value:
return value
try:
output = int(value)
return output
except Exception:
pass
try:
output = float(value)
return output
except Exception:
pass
b = self.as_boolean(value)
if b is not None:
return b
return value
class KeyValueFileReader(object):
def __init__(self, path: str, converter: object=None, verbose=False):
self._path = path
self._converter = converter if converter else TypeConverter()
self._verbose = verbose
def __log_formatting_error(self, line: str, idx: int) -> None:
if self._verbose:
self._logger.warning(f'malformed config @ line {idx}: {line}')
def __load_entry(self, line: str, line_num: int) -> Tuple[str, str]:
if self.__is_comment(line):
return None, None
parts = [p.strip() for p in line.split('=')]
if len(parts) == 2:
return parts[0], parts[1]
self.__log_formatting_error(line, line_num)
return None, None
def __is_comment(self, line: str) -> bool:
return line.startswith('#')
def __iter__(self) -> Tuple[str, object]:
if not os.path.exists(self._path):
raise FileNotFoundError(f'Path not found: {self._path}')
line_num = 1
with open(self._path, 'r') as fp:
entry = fp.readline()
while entry:
entry = entry
k, v = self.__load_entry(entry, line_num)
if k and v:
o = self._converter.convert_cfg_type(v)
yield k, o
entry = fp.readline()
line_num += 1
class SimpleCfgLoader(object):
def __init__(self, path: str="config.txt", verbose: bool=False, reader=None) -> None:
self._d: Dict = {}
self._reader = reader if reader else KeyValueFileReader(path)
self.__load_file()
def __getitem__(self, key: str) -> object:
if key in self._d:
return self._d[key]
return None
def __load_file(self):
for k, v in self._reader:
self[k] = v
if __name__ == "__main__":
cfg = SimpleCfgLoader('config.txt')
all_keys = ['abc', 'host', 'server_id', 'server_load_alarm', 'user', \
'verbose', 'test_mode', 'debug_mode', 'log_file_path', \
'send_notifications']
for key in all_keys:
v = cfg[key]
print(f'{key},', type(v))
try:
other_key = cfg['missingkey']
except KeyError:
print('no key error occurred')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment