-
Notifications
You must be signed in to change notification settings - Fork 0
/
config_manager.py
245 lines (207 loc) · 9.18 KB
/
config_manager.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#
# Author : Manuel Bernal Llinares
# Project : cloud-web-frontend
# Timestamp : 19-03-2018 16:26
# ---
# © 2017 Manuel Bernal Llinares <mbdebian@gmail.com>
# All rights reserved.
#
"""
This module implements configuration management for the application
"""
import os
import sys
import uuid
import time
import logging
import platform
import importlib
# App imports
from toolbox import general
from exceptions import AppConfigException, ConfigManagerException
# Defaults
__DEFAULT_CONFIG_FILE = "config_default.json"
# Application defaults - NORMAL OPERATION MODE
_folder_bin = os.path.abspath('bin')
_folder_config = os.path.abspath('config')
_folder_docs = os.path.abspath('docs')
_folder_logs = os.path.abspath('logs')
_folder_resources = os.path.abspath('resources')
_folder_run = os.path.abspath('run')
# Configuration file name
__configuration_file_name = __DEFAULT_CONFIG_FILE
# Configuration Singleton
__app_config_manager = None
# Flags
__show_logs_on_console = True
# Logging defaults
_logger_formatters = {
"DEBUG": "%(asctime)s [%(levelname)7s][%(name)18s][%(module)18s, %(lineno)4s] %(message)s",
"INFO": "%(asctime)s [%(levelname)7s][%(name)18s] %(message)s"
}
_log_level = 'DEBUG'
_console_log_level = 'DEBUG'
def set_application_config_file(configuration_file):
"""
This method sets the application wide configuration file that will be used
:param configuration_file: config file name if the file is in the default configuration path or path to the
configuration file if it is not.
:return: no return value
:exception: ConfigException is raised if there already is a configuration file set
"""
global __configuration_file_name
if __configuration_file_name is not None:
raise AppConfigException(
"Configuration file can't be changed once an initial configuartion file has been provided")
__configuration_file_name = configuration_file
def is_show_logs_on_console():
global __show_logs_on_console
return __show_logs_on_console
def get_app_config_manager():
"""
Singleton implementation of the Application Config Manager
:return: the Application Configuration Manager
"""
global __app_config_manager
if __app_config_manager is None:
__app_config_manager = AppConfigManager(read_config_from_file(__configuration_file_name),
__configuration_file_name)
return __app_config_manager
def read_config_from_file(configuration_file):
"""
Given a file name or absolute path, read its configuration information in json format and return its object
representation
:param configuration_file: file name or absolute path for the file that contains the configuration information
:return: an object representation of the json formatted configuration information read from the file
"""
if configuration_file is None:
# If there is no configuration file, we return an empty configuration object
return {}
config_file_path = configuration_file
if not os.path.isabs(config_file_path):
config_file_path = os.path.join(_folder_config, configuration_file)
try:
return general.read_json(config_file_path)
except Exception as e:
msg = "Config file {} could not be read, because {}".format(config_file_path, str(e))
raise AppConfigException(msg)
class ConfigurationManager:
"""
This class is a helper class for those submodules having to manage configuration files themselves, that are specific
to them
"""
def __init__(self, configuration_object, configuration_file):
self.__configuration_object = configuration_object
self.__configuration_file = configuration_file
def _get_value_for_key(self, key):
if key in self.__configuration_object:
return self.__configuration_object[key]
else:
msg = "MISSING configuration key '{}' in configuration file '{}'".format(key, self.__configuration_file)
raise ConfigManagerException(msg)
def _get_value_for_key_with_default(self, key, default):
if key in self.__configuration_object:
return self.__configuration_object[key]
else:
return default
def _get_configuration_object(self):
return self.__configuration_object
def _get_configuration_file(self):
return self.__configuration_file
class AppConfigManager(ConfigurationManager):
"""
Application wide Configuration Manager
"""
def __init__(self, configuration_object, configuration_file):
super().__init__(configuration_object, configuration_file)
global _log_level
global _logger_formatters
# Session ID
self.__session_id = time.strftime('%Y.%m.%d_%H.%M') \
+ "-{}".format(str(uuid.uuid4())) \
+ "-session"
# TODO config, folder_run, etc.
self.__session_working_dir = os.path.abspath(os.path.join(self.get_folder_run(), self.get_session_id()))
# TODO check and create folders (if needed)
folders_to_check = [self.get_folder_bin(),
self.get_folder_logs(),
self.get_folder_resources(),
self.get_folder_run(),
self.get_session_working_dir(),
]
general.check_create_folders(folders_to_check)
# Prepare Logging subsystem
if "loglevel" in configuration_object["logger"]:
_log_level = configuration_object["logger"]["loglevel"]
if "formatters" in configuration_object["logger"]["formatters"]:
_logger_formatters = configuration_object["logger"]["formatters"]
self.__log_handlers = []
log_handlers_prefix = self.get_session_id() + '-'
log_handlers_extension = '.log'
self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
self._logger.setLevel(getattr(logging, _log_level))
# TODO fix this code
# for llevel, lformat in _logger_formatters.items():
# logfile = os.path.join(self.get_folder_logs(),
# log_handlers_prefix + llevel.lower() + log_handlers_extension)
# lformatter = logging.Formatter(lformat)
# lhandler = logging.FileHandler(logfile, mode='w')
# lhandler.setLevel(getattr(logging, llevel))
# lhandler.setFormatter(lformatter)
# self.__log_handlers.append(lhandler)
# # Add the handlers to my own logger
# self._logger.addHandler(lhandler)
if is_show_logs_on_console():
lhandler = logging.StreamHandler(stream=sys.stdout)
lhandler.setLevel(getattr(logging, _console_log_level))
lformatter = logging.Formatter(_logger_formatters[_console_log_level])
lhandler.setFormatter(lformatter)
self.__log_handlers.append(lhandler)
# Add the handlers to my own logger
self._logger.addHandler(lhandler)
self._logger.debug("Logging system initialized")
# TODO to be completed
def _get_log_handlers(self):
return self.__log_handlers
def get_folder_bin(self):
# 'Bin' folder cannot be changed in this version of the template
return os.path.abspath(_folder_bin)
def get_folder_config(self):
# Configuration folder cannot be changed in this version of the template
return os.path.abspath(_folder_config)
def get_folder_logs(self):
# Configuration for logging folder cannot be changed in this version of the template
return os.path.abspath(_folder_logs)
def get_folder_resources(self):
# Configuration for resources folder cannot be changed in this version of the template
return os.path.abspath(_folder_resources)
def get_folder_run(self):
# Configuration for 'run' folder cannot be changed in this version of the template
return os.path.abspath(_folder_run)
def get_session_working_dir(self):
return self.__session_working_dir
def get_logger_for(self, name):
"""
Create a logger on demand
:param name: name to be used in the logger
:return: a new logger on that name
"""
self._logger.debug("Creating logger with name {}".format(name))
lg = logging.getLogger(name)
for handler in self._get_log_handlers():
lg.addHandler(handler)
lg.setLevel(_log_level)
return lg
def get_session_id(self):
return self.__session_id
def get_path_chrome_driver(self):
# TODO - Selenium path could be externalized later down the road, if it makes sense
path_selenium_binaries = os.path.join(self.get_folder_bin(), 'selenium')
if platform.system() == 'Darwin':
return os.path.join(path_selenium_binaries, "chromedriver-mac")
elif platform.system() == 'Linux':
return os.path.join(path_selenium_binaries, "chromedriver-linux")
else:
return os.path.join(path_selenium_binaries, "chromedriver.exe")
if __name__ == '__main__':
print("ERROR: This script is part of a application and it is not meant to be run in stand alone mode")