added parameter sweeps back in
This commit is contained in:
@ -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)
|
||||
|
||||
|
Reference in New Issue
Block a user