Major LINT fixes/refactor for the Config class

This commit is contained in:
Fabio Manganiello 2023-02-04 17:35:48 +01:00
parent db5846d296
commit b96838a856
Signed by: blacklight
GPG key ID: D90FBA7F76362774

View file

@ -11,7 +11,7 @@ import shutil
import socket import socket
import sys import sys
from urllib.parse import quote from urllib.parse import quote
from typing import Optional from typing import Optional, Set
import yaml import yaml
@ -22,9 +22,6 @@ from platypush.utils import (
is_functional_cron, is_functional_cron,
) )
""" Config singleton instance """
_default_config_instance = None
class Config: class Config:
""" """
@ -38,16 +35,17 @@ class Config:
Config.get('foo') Config.get('foo')
""" """
""" # Default config file locations:
Default config file locations: # - $HOME/.config/platypush/config.yaml
- $HOME/.config/platypush/config.yaml # - /etc/platypush/config.yaml
- /etc/platypush/config.yaml
"""
_cfgfile_locations = [ _cfgfile_locations = [
os.path.join(os.path.expanduser('~'), '.config', 'platypush', 'config.yaml'), os.path.join(os.path.expanduser('~'), '.config', 'platypush', 'config.yaml'),
os.path.join(os.sep, 'etc', 'platypush', 'config.yaml'), os.path.join(os.sep, 'etc', 'platypush', 'config.yaml'),
] ]
# Config singleton instance
_instance = None
_default_constants = { _default_constants = {
'today': datetime.date.today, 'today': datetime.date.today,
'now': datetime.datetime.now, 'now': datetime.datetime.now,
@ -56,7 +54,7 @@ class Config:
_workdir_location = os.path.join( _workdir_location = os.path.join(
os.path.expanduser('~'), '.local', 'share', 'platypush' os.path.expanduser('~'), '.local', 'share', 'platypush'
) )
_included_files = set() _included_files: Set[str] = set()
def __init__(self, cfgfile=None): def __init__(self, cfgfile=None):
""" """
@ -118,9 +116,8 @@ class Config:
} }
else: else:
db_engine = { db_engine = {
'engine': 'sqlite:///' + os.path.join( 'engine': 'sqlite:///'
quote(self._config['workdir']), 'main.db' + os.path.join(quote(self._config['workdir']), 'main.db')
)
} }
self._config['db'] = db_engine self._config['db'] = db_engine
@ -139,11 +136,7 @@ class Config:
try: try:
os.makedirs(logdir, exist_ok=True) os.makedirs(logdir, exist_ok=True)
except Exception as e: except Exception as e:
print( print(f'Unable to create logs directory {logdir}: {e}')
'Unable to create logs directory {}: {}'.format(
logdir, str(e)
)
)
v = logfile v = logfile
del logging_config['stream'] del logging_config['stream']
@ -214,11 +207,9 @@ class Config:
continue continue
if not os.path.isabs(include_file): if not os.path.isabs(include_file):
include_file = os.path.join(cfgfile_dir, include_file) include_file = os.path.join(cfgfile_dir, include_file)
self._included_files.add(include_file)
included_config = self._read_config_file(include_file) self._included_files.add(include_file)
for incl_section in included_config.keys(): config.update(self._read_config_file(include_file))
config[incl_section] = included_config[incl_section]
elif section == 'scripts_dir': elif section == 'scripts_dir':
assert isinstance(file_config[section], str) assert isinstance(file_config[section], str)
config['scripts_dir'] = os.path.abspath( config['scripts_dir'] = os.path.abspath(
@ -237,11 +228,7 @@ class Config:
try: try:
module = importlib.import_module(modname) module = importlib.import_module(modname)
except Exception as e: except Exception as e:
print( print(f'Unhandled exception while importing module {modname}: {e}')
'Unhandled exception while importing module {}: {}'.format(
modname, str(e)
)
)
return return
prefix = modname + '.' if prefix is None else prefix prefix = modname + '.' if prefix is None else prefix
@ -284,19 +271,19 @@ class Config:
sys.path = sys_path sys.path = sys_path
def _init_components(self): def _init_components(self):
for key in self._config.keys(): for key, component in self._config.items():
if ( if (
key.startswith('backend.') key.startswith('backend.')
and '.'.join(key.split('.')[1:]) in self._backend_manifests and '.'.join(key.split('.')[1:]) in self._backend_manifests
): ):
backend_name = '.'.join(key.split('.')[1:]) backend_name = '.'.join(key.split('.')[1:])
self.backends[backend_name] = self._config[key] self.backends[backend_name] = component
elif key.startswith('event.hook.'): elif key.startswith('event.hook.'):
hook_name = '.'.join(key.split('.')[2:]) hook_name = '.'.join(key.split('.')[2:])
self.event_hooks[hook_name] = self._config[key] self.event_hooks[hook_name] = component
elif key.startswith('cron.'): elif key.startswith('cron.'):
cron_name = '.'.join(key.split('.')[1:]) cron_name = '.'.join(key.split('.')[1:])
self.cronjobs[cron_name] = self._config[key] self.cronjobs[cron_name] = component
elif key.startswith('procedure.'): elif key.startswith('procedure.'):
tokens = key.split('.') tokens = key.split('.')
_async = bool(len(tokens) > 2 and tokens[1] == 'async') _async = bool(len(tokens) > 2 and tokens[1] == 'async')
@ -314,11 +301,11 @@ class Config:
self.procedures[procedure_name] = { self.procedures[procedure_name] = {
'_async': _async, '_async': _async,
'actions': self._config[key], 'actions': component,
'args': args, 'args': args,
} }
elif key in self._plugin_manifests: elif key in self._plugin_manifests:
self.plugins[key] = self._config[key] self.plugins[key] = component
def _init_manifests(self, base_dir: Optional[str] = None): def _init_manifests(self, base_dir: Optional[str] = None):
if not base_dir: if not base_dir:
@ -353,7 +340,7 @@ class Config:
assert dashboards_dir assert dashboards_dir
abspath = os.path.join(dashboards_dir, name + '.xml') abspath = os.path.join(dashboards_dir, name + '.xml')
if not os.path.isfile(abspath): if not os.path.isfile(abspath):
return return None
with open(abspath, 'r') as fp: with open(abspath, 'r') as fp:
return fp.read() return fp.read()
@ -373,111 +360,94 @@ class Config:
return dashboards return dashboards
@staticmethod @classmethod
def get_dashboard(name: str, dashboards_dir: Optional[str] = None) -> Optional[str]: def _get_instance(
global _default_config_instance cls, cfgfile: Optional[str] = None, force_reload: bool = False
if _default_config_instance is None: ) -> "Config":
_default_config_instance = Config() """
return _default_config_instance._get_dashboard(name, dashboards_dir) Lazy getter/setter for the default configuration instance.
"""
if force_reload or cls._instance is None:
cfg_args = [cfgfile] if cfgfile else []
cls._instance = Config(*cfg_args)
return cls._instance
@classmethod
def get_dashboard(
cls, name: str, dashboards_dir: Optional[str] = None
) -> Optional[str]:
# pylint: disable=protected-access
return cls._get_instance()._get_dashboard(name, dashboards_dir)
@classmethod @classmethod
def get_dashboards(cls, dashboards_dir: Optional[str] = None) -> dict: def get_dashboards(cls, dashboards_dir: Optional[str] = None) -> dict:
global _default_config_instance # pylint: disable=protected-access
if _default_config_instance is None: return cls._get_instance()._get_dashboards(dashboards_dir)
_default_config_instance = Config()
return _default_config_instance._get_dashboards(dashboards_dir)
def _init_dashboards(self, dashboards_dir: str): def _init_dashboards(self, dashboards_dir: str):
self.dashboards = self._get_dashboards(dashboards_dir) self.dashboards = self._get_dashboards(dashboards_dir)
@staticmethod @classmethod
def get_backends(): def get_backends(cls):
global _default_config_instance return cls._get_instance().backends
if _default_config_instance is None:
_default_config_instance = Config()
return _default_config_instance.backends
@staticmethod
def get_plugins():
global _default_config_instance
if _default_config_instance is None:
_default_config_instance = Config()
return _default_config_instance.plugins
@staticmethod
def get_event_hooks():
global _default_config_instance
if _default_config_instance is None:
_default_config_instance = Config()
return _default_config_instance.event_hooks
@staticmethod
def get_procedures():
global _default_config_instance
if _default_config_instance is None:
_default_config_instance = Config()
return _default_config_instance.procedures
@staticmethod
def get_constants():
global _default_config_instance
if _default_config_instance is None:
_default_config_instance = Config()
constants = {}
for name in _default_config_instance.constants.keys():
constants[name] = Config.get_constant(name)
return constants
@staticmethod
def get_constant(name):
global _default_config_instance
if _default_config_instance is None:
_default_config_instance = Config()
if name not in _default_config_instance.constants:
return None
value = _default_config_instance.constants[name]
return value() if callable(value) else value
@staticmethod
def get_cronjobs():
global _default_config_instance
if _default_config_instance is None:
_default_config_instance = Config()
return _default_config_instance.cronjobs
@classmethod @classmethod
def _get_default_cfgfile(cls): def get_plugins(cls):
return cls._get_instance().plugins
@classmethod
def get_event_hooks(cls):
return cls._get_instance().event_hooks
@classmethod
def get_procedures(cls):
return cls._get_instance().procedures
@classmethod
def get_constants(cls):
return {
name: Config.get_constant(name) for name in cls._get_instance().constants
}
@classmethod
def get_constant(cls, name):
value = cls._get_instance().constants.get(name)
if value is None:
return None
return value() if callable(value) else value
@classmethod
def get_cronjobs(cls):
return cls._get_instance().cronjobs
@classmethod
def _get_default_cfgfile(cls) -> Optional[str]:
for location in cls._cfgfile_locations: for location in cls._cfgfile_locations:
if os.path.isfile(location): if os.path.isfile(location):
return location return location
return None
@staticmethod @classmethod
def init(cfgfile=None): def init(cls, cfgfile: Optional[str] = None):
""" """
Initializes the config object singleton Initializes the config object singleton
Params: Params:
cfgfile -- path to the config file - default: _cfgfile_locations cfgfile -- path to the config file - default: _cfgfile_locations
""" """
global _default_config_instance return cls._get_instance(cfgfile, force_reload=True)
_default_config_instance = Config(cfgfile)
@staticmethod @classmethod
def get(key: Optional[str] = None): def get(cls, key: Optional[str] = None):
""" """
Get a config value or the whole configuration object. Get a config value or the whole configuration object.
:param key: Configuration entry to get (default: all entries). :param key: Configuration entry to get (default: all entries).
""" """
global _default_config_instance # pylint: disable=protected-access
if _default_config_instance is None: config = cls._get_instance()._config.copy()
_default_config_instance = Config()
if key: if key:
return _default_config_instance._config.get(key) return config.get(key)
return config
return _default_config_instance._config
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et: