1
|
|
|
""" |
2
|
|
|
groundwork module provides mainly the App class, which is a container for all functions and |
3
|
|
|
data related to plugins and their patterns. |
4
|
|
|
""" |
5
|
|
|
import logging |
6
|
|
|
import logging.config |
7
|
|
|
import sys |
8
|
|
|
import os |
9
|
|
|
|
10
|
|
|
from groundwork.configuration import ConfigManager |
11
|
|
|
from groundwork.pluginmanager import PluginManager |
12
|
|
|
from groundwork.signals import SignalsApplication |
13
|
|
|
|
14
|
|
|
|
15
|
|
|
class App(object): |
16
|
|
|
""" |
17
|
|
|
Application object for a groundwork app. |
18
|
|
|
Loads configurations, configures logs, initialises and activates plugins and provides managers. |
19
|
|
|
|
20
|
|
|
Performed steps during start up: |
21
|
|
|
1. load configuration |
22
|
|
|
2. configure logs |
23
|
|
|
3. get valid groundwork plugins |
24
|
|
|
4. activate configured plugins |
25
|
|
|
|
26
|
|
|
:param config_files: List of config files, which shall be loaded |
27
|
|
|
:type config_files: list of str |
28
|
|
|
:param plugins: List of plugins, which shall be registered |
29
|
|
|
:type plugins: Plugin-Classes, based on :class:`~groundwork.patterns.gw_base_pattern.GwBasePattern` |
30
|
|
|
:param strict: If true, Exceptions are thrown, if a plugin can not be initialised or activated. |
31
|
|
|
""" |
32
|
|
|
def __init__(self, config_files=None, plugins=None, strict=False): |
33
|
|
|
if config_files is None: |
34
|
|
|
config_files = [] |
35
|
|
|
|
36
|
|
|
self.strict = strict |
37
|
|
|
|
38
|
|
|
#: logging object for sending log messages. Example:: |
39
|
|
|
#: |
40
|
|
|
#: from groundwork import App |
41
|
|
|
#: my_app = App() |
42
|
|
|
#: my_app.log.debug("Send debug message") |
43
|
|
|
#: my_app.log.error("Send error....") |
44
|
|
|
self.log = logging.getLogger("groundwork") |
45
|
|
|
|
46
|
|
|
self._configure_logging() |
47
|
|
|
self.log.info("Initializing groundwork") |
48
|
|
|
self.log.info("Reading configuration") |
49
|
|
|
|
50
|
|
|
#: Instance of :class:`~groundwork.configuration.configmanager.ConfigManager`. |
51
|
|
|
#: Used to load different configuration files and create a common configuration object. |
52
|
|
|
self.config = ConfigManager().load(config_files) |
53
|
|
|
|
54
|
|
|
self._configure_logging(self.config.get("GROUNDWORK_LOGGING")) |
55
|
|
|
|
56
|
|
|
#: Name of the application. Is configurable by parameter "APP_NAME" of a configuration file. |
57
|
|
|
self.name = self.config.get("APP_NAME", None) or "NoName App" |
58
|
|
|
|
59
|
|
|
#: Absolute application path. Is configurable by parameter "APP_PATH" of a configuration file. |
60
|
|
|
#: If not given, the current working directory is taken. |
61
|
|
|
#: The path is used to calculate absolute paths for tests, documentation and much more. |
62
|
|
|
self.path = os.path.abspath(self.config.get("APP_PATH", None) or os.getcwd()) |
63
|
|
|
|
64
|
|
|
#: Instance of :class:`~groundwork.signals.SignalsApplication`. Provides functions to register and fire |
65
|
|
|
# signals or receivers on application level. |
66
|
|
|
self.signals = SignalsApplication(app=self) |
67
|
|
|
|
68
|
|
|
self.signals.register("plugin_activate_pre", self, |
69
|
|
|
"Gets send right before activation routine of a plugins will be executed") |
70
|
|
|
self.signals.register("plugin_activate_post", self, |
71
|
|
|
"Gets send right after activation routine of a plugins was executed") |
72
|
|
|
self.signals.register("plugin_deactivate_pre", self, |
73
|
|
|
"Gets send right before deactivation routine of a plugins will be executed") |
74
|
|
|
self.signals.register("plugin_deactivate_post", self, |
75
|
|
|
"Gets send right after deactivation routine of a plugins was executed") |
76
|
|
|
|
77
|
|
|
#: Instance of :class:`~groundwork.pluginmanager.PluginManager`- Provides functions to load, activate and |
78
|
|
|
# deactivate plugins. |
79
|
|
|
self.plugins = PluginManager(app=self) |
80
|
|
|
|
81
|
|
|
if plugins is not None: |
82
|
|
|
self.plugins.classes.register(plugins) |
83
|
|
|
|
84
|
|
|
def _configure_logging(self, logger_dict=None): |
85
|
|
|
""" |
86
|
|
|
Configures the logging module with a given dictionary, which in most cases was loaded from a configuration |
87
|
|
|
file. |
88
|
|
|
|
89
|
|
|
If no dictionary is provided, it falls back to a default configuration. |
90
|
|
|
|
91
|
|
|
See `Python docs |
92
|
|
|
<https://docs.python.org/3.5/library/logging.config.html#logging.config.dictConfig>`_ for more information. |
93
|
|
|
|
94
|
|
|
:param logger_dict: dictionary for logger. |
95
|
|
|
""" |
96
|
|
|
self.log.debug("Configure logging") |
97
|
|
|
|
98
|
|
|
# Let's be sure, that for our log no handlers are registered anymore |
99
|
|
|
if self.log.hasHandlers(): |
100
|
|
|
for handler in self.log.handlers: |
101
|
|
|
self.log.removeHandler(handler) |
102
|
|
|
if logger_dict is None: |
103
|
|
|
self.log.debug("No logger dictionary defined. Doing default logger configuration") |
104
|
|
|
formatter = logging.Formatter("%(name)s - %(asctime)s - [%(levelname)s] - %(module)s - %(message)s") |
105
|
|
|
stream_handler = logging.StreamHandler(sys.stdout) |
106
|
|
|
stream_handler.setLevel(logging.WARNING) |
107
|
|
|
stream_handler.setFormatter(formatter) |
108
|
|
|
self.log.addHandler(stream_handler) |
109
|
|
|
self.log.setLevel(logging.WARNING) |
110
|
|
|
else: |
111
|
|
|
self.log.debug("Logger dictionary defined. Loading dictConfig for logging") |
112
|
|
|
logging.config.dictConfig(logger_dict) |
113
|
|
|
self.log.debug("dictConfig loaded") |
114
|
|
|
|