added parameter sweeps back in

This commit is contained in:
PatchOfScotland
2023-01-10 16:44:33 +01:00
parent 5dded8fc96
commit e9519d718f
9 changed files with 828 additions and 45 deletions

View File

@ -1,5 +1,6 @@
import threading
import sys
import os
from fnmatch import translate
@ -7,39 +8,38 @@ from re import match
from time import time, sleep
from typing import Any
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler, FileCreatedEvent, \
FileModifiedEvent, FileMovedEvent, FileClosedEvent, FileDeletedEvent, \
DirCreatedEvent, DirDeletedEvent, DirModifiedEvent, DirMovedEvent
from watchdog.events import PatternMatchingEventHandler
from core.correctness.validation import check_type, valid_string, \
valid_dict, valid_list, valid_path
valid_dict, valid_list, valid_path, valid_existing_dir_path, \
setup_debugging
from core.correctness.vars import VALID_RECIPE_NAME_CHARS, \
VALID_VARIABLE_NAME_CHARS, FILE_EVENTS, FILE_CREATE_EVENT, \
FILE_MODIFY_EVENT, FILE_MOVED_EVENT, FILE_CLOSED_EVENT, \
FILE_DELETED_EVENT, DIR_CREATE_EVENT, DIR_DELETED_EVENT, \
DIR_MODIFY_EVENT, DIR_MOVED_EVENT, VALID_CHANNELS
FILE_MODIFY_EVENT, FILE_MOVED_EVENT, VALID_CHANNELS, DEBUG_INFO, \
DEBUG_ERROR, DEBUG_WARNING
from core.functionality import print_debug
from core.meow import BasePattern, BaseMonitor, BaseRule
_EVENT_TRANSLATIONS = {
FileCreatedEvent: FILE_CREATE_EVENT,
FileModifiedEvent: FILE_MODIFY_EVENT,
FileMovedEvent: FILE_MOVED_EVENT,
FileClosedEvent: FILE_CLOSED_EVENT,
FileDeletedEvent: FILE_DELETED_EVENT,
DirCreatedEvent: DIR_CREATE_EVENT,
DirDeletedEvent: DIR_DELETED_EVENT,
DirModifiedEvent: DIR_MODIFY_EVENT,
DirMovedEvent: DIR_MOVED_EVENT
}
_DEFAULT_MASK = [
FILE_CREATE_EVENT,
FILE_MODIFY_EVENT,
FILE_MOVED_EVENT
]
SWEEP_START = "start"
SWEEP_STOP = "stop"
SWEEP_JUMP = "jump"
class FileEventPattern(BasePattern):
triggering_path:str
triggering_file:str
event_mask:list[str]
sweep:dict[str,Any]
def __init__(self, name:str, triggering_path:str, recipe:str,
triggering_file:str, event_mask:list[str]=FILE_EVENTS,
parameters:dict[str,Any]={}, outputs:dict[str,Any]={}):
triggering_file:str, event_mask:list[str]=_DEFAULT_MASK,
parameters:dict[str,Any]={}, outputs:dict[str,Any]={},
sweep:dict[str,Any]={}):
super().__init__(name, recipe, parameters, outputs)
self._is_valid_triggering_path(triggering_path)
self.triggering_path = triggering_path
@ -47,6 +47,8 @@ class FileEventPattern(BasePattern):
self.triggering_file = triggering_file
self._is_valid_event_mask(event_mask)
self.event_mask = event_mask
self._is_valid_sweep(sweep)
self.sweep = sweep
def _is_valid_recipe(self, recipe:str)->None:
valid_string(recipe, VALID_RECIPE_NAME_CHARS)
@ -79,20 +81,57 @@ class FileEventPattern(BasePattern):
raise ValueError(f"Invalid event mask '{mask}'. Valid are: "
f"{FILE_EVENTS}")
def _is_valid_sweep(self, sweep)->None:
check_type(sweep, dict)
if not sweep:
return
for k, v in sweep.items():
valid_dict(
v, str, Any, [
SWEEP_START, SWEEP_STOP, SWEEP_JUMP
], strict=True)
check_type(
v[SWEEP_START], expected_type=int, alt_types=[float, complex])
check_type(
v[SWEEP_STOP], expected_type=int, alt_types=[float, complex])
check_type(
v[SWEEP_JUMP], expected_type=int, alt_types=[float, complex])
# Try to check that this loop is not infinite
if v[SWEEP_JUMP] == 0:
raise ValueError(
f"Cannot create sweep with a '{SWEEP_JUMP}' value of zero"
)
elif v[SWEEP_JUMP] > 0:
if not v[SWEEP_STOP] > v[SWEEP_START]:
raise ValueError(
"Cannot create sweep with a positive '{SWEEP_JUMP}' "
"value where the end point is smaller than the start."
)
elif v[SWEEP_JUMP] < 0:
if not v[SWEEP_STOP] < v[SWEEP_START]:
raise ValueError(
"Cannot create sweep with a negative '{SWEEP_JUMP}' "
"value where the end point is smaller than the start."
)
class WatchdogMonitor(BaseMonitor):
event_handler:PatternMatchingEventHandler
monitor:Observer
base_dir:str
debug_level:int
_print_target:Any
_rules_lock:threading.Lock
def __init__(self, base_dir:str, rules:dict[str, BaseRule],
report:VALID_CHANNELS, autostart=False,
settletime:int=1)->None:
settletime:int=1, print:Any=sys.stdout, logging:int=0)->None:
super().__init__(rules, report)
self._is_valid_base_dir(base_dir)
self.base_dir = base_dir
check_type(settletime, int)
self._print_target, self.debug_level = setup_debugging(print, logging)
self._rules_lock = threading.Lock()
self.event_handler = WatchdogEventHandler(self, settletime=settletime)
self.monitor = Observer()
@ -101,14 +140,20 @@ class WatchdogMonitor(BaseMonitor):
self.base_dir,
recursive=True
)
print_debug(self._print_target, self.debug_level,
"Created new WatchdogMonitor instance", DEBUG_INFO)
if autostart:
self.start()
def start(self)->None:
print_debug(self._print_target, self.debug_level,
"Starting WatchdogMonitor", DEBUG_INFO)
self.monitor.start()
def stop(self)->None:
print_debug(self._print_target, self.debug_level,
"Stopping WatchdogMonitor", DEBUG_INFO)
self.monitor.stop()
def match(self, event)->None:
@ -134,6 +179,10 @@ class WatchdogMonitor(BaseMonitor):
direct_hit = match(direct_regexp, handle_path)
if direct_hit or recursive_hit:
print_debug(self._print_target, self.debug_level,
f"Event at {src_path} of type {event_type} hit rule "
f"{rule.name}", DEBUG_INFO)
event.monitor_base = self.base_dir
self.report.send((event, rule))
except Exception as e:
@ -144,7 +193,7 @@ class WatchdogMonitor(BaseMonitor):
def _is_valid_base_dir(self, base_dir:str)->None:
valid_path(base_dir)
valid_existing_dir_path(base_dir)
def _is_valid_report(self, report:VALID_CHANNELS)->None:
check_type(report, VALID_CHANNELS)
@ -205,7 +254,7 @@ class WatchdogEventHandler(PatternMatchingEventHandler):
def on_created(self, event):
self.handle_event(event)
def on_modified(self, event):
self.handle_event(event)