Coverage for yasmon/processor.py: 100%
124 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-28 10:57 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-28 10:57 +0000
1from yasmon.callbacks import AbstractCallback
2from yasmon.callbacks import CallbackDict
3from yasmon.callbacks import ShellCallback, LoggerCallback, MailCallback
4from yasmon.callbacks import CallbackSyntaxError
5from yasmon.callbacks import CallbackNotImplementedError
6from yasmon.tasks import TaskList, WatchfilesTask, TaskNotImplementedError
7from yasmon.loggers import LoggerSyntaxError, AbstractLogger
8from yasmon.loggers import StdErrLogger, FileLogger, JournalLogger
10from loguru import logger
11import yaml
14class YAMLSyntaxError(Exception):
15 """
16 Raised when on general YAML syntax errors.
17 """
19 def __init__(self, message="yaml syntax error"):
20 self.message = message
21 super().__init__(self.message)
24class YAMLProcessor:
25 def __init__(self):
26 self.data = None
28 def load_file(self, filename: str):
29 try:
30 fh = open(filename, "r")
31 logger.info(f'using config file {filename}')
32 except FileNotFoundError as err:
33 logger.error(f"YAML file {filename} not found")
34 raise err
35 except PermissionError as err:
36 logger.error(
37 f"{err.__class__.__name__} while opening {filename} {err}")
38 raise err
39 except OSError as err:
40 logger.error(
41 f"{err.__class__.__name__} while opening {filename} {err}")
42 raise err
43 except Exception as err:
44 logger.error(
45 f"{err.__class__.__name__} while opening {filename} {err}")
46 raise err
47 else:
48 try:
49 self.data = yaml.safe_load(fh)
50 except yaml.YAMLError as err:
51 raise YAMLSyntaxError(err)
52 finally:
53 fh.close()
55 if self.data is None:
56 raise YAMLSyntaxError('config file is empty')
58 def add_loggers(self) -> list[AbstractLogger]:
59 """
60 Add defined loggers.
62 :return: list of added loggers or empty list
63 :rtype: list[AbstractLogger]
64 """
65 logger.info('processing loggers...')
66 loggers: list[AbstractLogger] = []
68 for key in self.data:
69 data = self.data[key]
70 yaml_data = yaml.dump(data)
71 try:
72 match key:
73 case 'log_stderr':
74 instance = StdErrLogger.from_yaml(yaml_data)
75 loggers.append(instance)
76 case 'log_file':
77 instance = FileLogger.from_yaml(yaml_data)
78 loggers.append(instance)
79 case 'log_journal':
80 instance = JournalLogger.from_yaml(yaml_data)
81 loggers.append(instance)
82 except LoggerSyntaxError:
83 raise
85 return loggers
87 def load_document(self, document: str):
88 try:
89 self.data = yaml.safe_load(document)
90 logger.info(f'config:\n{document}')
91 except yaml.YAMLError as err:
92 raise YAMLSyntaxError(err)
94 if self.data is None:
95 raise YAMLSyntaxError('config document is empty')
97 def get_tasks(self, callbacks: CallbackDict):
98 logger.debug('processing tasks...')
99 if 'tasks' not in self.data:
100 raise YAMLSyntaxError('tasks not defined')
102 if not self.data['tasks']:
103 logger.warning('no tasks defined')
104 return TaskList()
106 tasks = self.data['tasks']
108 if type(tasks) is not dict:
109 raise YAMLSyntaxError('tasks must be a dictionary')
111 taskslist = TaskList()
112 for task in tasks:
113 taskdata = tasks[task]
114 if type(taskdata) is not dict:
115 raise YAMLSyntaxError(f'{task} task data must be a dictionary')
117 taskdata_yaml = yaml.dump(taskdata)
119 if 'callbacks' not in taskdata:
120 raise YAMLSyntaxError(f'{task} task data must include'
121 ' callbacks list')
123 task_callbacks: list[AbstractCallback] = [
124 callbacks[c] for c in taskdata["callbacks"]
125 if c in taskdata["callbacks"]
126 ]
128 match taskdata['type']:
129 case 'watchfiles':
130 taskslist.append(WatchfilesTask.from_yaml(task,
131 taskdata_yaml,
132 task_callbacks))
133 case _:
134 raise TaskNotImplementedError(
135 f'task type {taskdata["type"]}'
136 ' not implement')
138 logger.debug('done processing tasks')
139 return taskslist
141 def get_callbacks(self):
142 logger.debug('processing callbacks...')
143 if 'callbacks' not in self.data:
144 raise YAMLSyntaxError('callbacks not defined')
146 if not self.data['callbacks']:
147 logger.warning('no callbacks defined')
148 return
150 callbacks = self.data['callbacks']
152 if type(self.data['callbacks']) is not dict:
153 raise YAMLSyntaxError('callbacks must be a dictionary')
155 callbacksdict = CallbackDict()
156 for callback in callbacks:
157 callbackdata = self.data['callbacks'].get(callback)
158 if type(callbackdata) is not dict:
159 raise YAMLSyntaxError(f'{callback} callback data must'
160 ' be a dictionary')
162 try:
163 match callbackdata['type']:
164 case 'shell':
165 callbacksdict[callback] = ShellCallback.from_yaml(
166 callback, yaml.dump(callbackdata))
167 case 'logger':
168 callbacksdict[callback] = LoggerCallback.from_yaml(
169 callback, yaml.dump(callbackdata))
170 case 'mail':
171 callbacksdict[callback] = MailCallback.from_yaml(
172 callback, yaml.dump(callbackdata))
173 case _:
174 raise CallbackNotImplementedError(
175 f'callback type {callbackdata["type"]} '
176 'not implement')
177 except CallbackSyntaxError as err:
178 logger.error(f'error while processing callbacks: {err}. '
179 'Exiting!')
180 raise err
182 logger.debug('done processing callbacks')
183 return callbacksdict