Last active
October 13, 2021 05:30
-
-
Save ankona/38a83f48050a40d7eaddceb61e46e57b to your computer and use it in GitHub Desktop.
simple cfg
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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