Complete refactor of script to make it more pythonic
This commit is contained in:
parent
f6b1b2d5ee
commit
f239b4fb23
|
@ -1,3 +1,4 @@
|
||||||
|
from pathlib import Path
|
||||||
from icalendar import Calendar, Event
|
from icalendar import Calendar, Event
|
||||||
import toml, argparse, os, sys, hashlib, json, pytz, glob, os, time
|
import toml, argparse, os, sys, hashlib, json, pytz, glob, os, time
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
|
@ -9,39 +10,35 @@ from watchdog.events import FileSystemEventHandler
|
||||||
import email_alert, xmpp_alert
|
import email_alert, xmpp_alert
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
import humanfriendly
|
import humanfriendly
|
||||||
|
from pathlib import Path
|
||||||
|
import argparse
|
||||||
|
import textwrap
|
||||||
|
|
||||||
# Parse args
|
def parse_args():
|
||||||
|
"""Parse command line arguments."""
|
||||||
parser = argparse.ArgumentParser(description="A simple calendar alerting daemon written in Python")
|
parser = argparse.ArgumentParser(description="A simple calendar alerting daemon written in Python")
|
||||||
parser.add_argument('--config', type=str, help='Path to config file. Must be .toml')
|
parser.add_argument('--config', type=str, help='Path to config file. Must be .toml')
|
||||||
|
parser.add_argument('--loglevel', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], default='INFO', help='Set the logging level')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
if args.config is None:
|
||||||
|
raise ValueError("No config file provided")
|
||||||
|
return args
|
||||||
|
|
||||||
if not args.config:
|
def read_file(filename):
|
||||||
print("Error: No config file provided.")
|
|
||||||
sys.exit(1) # Exit with error code
|
|
||||||
elif not os.path.isfile(args.config):
|
|
||||||
print("Error: The specified config file does not exist.")
|
|
||||||
sys.exit(1) # Exit with error code
|
|
||||||
else:
|
|
||||||
print("Config file path: ", args.config)
|
|
||||||
|
|
||||||
# Get config
|
|
||||||
try:
|
try:
|
||||||
with open(args.config, 'r') as f:
|
return Path(filename).read_text()
|
||||||
config = toml.load(f)
|
except FileNotFoundError as e:
|
||||||
|
print(f"Error: The specified file does not exist. {e}")
|
||||||
|
sys.exit(1) # Exit with error code
|
||||||
|
|
||||||
|
def parse_toml(content):
|
||||||
|
try:
|
||||||
|
return toml.loads(content)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Error: Failed to parse TOML file.")
|
print("Error: Failed to parse TOML file.")
|
||||||
print(e)
|
print(e)
|
||||||
sys.exit(1) # Exit with error code
|
sys.exit(1) # Exit with error code
|
||||||
|
|
||||||
cal_dir = config["app"]["calendar_dir"]
|
|
||||||
# Check if the path is a directory
|
|
||||||
if not os.path.isdir(cal_dir):
|
|
||||||
print("The provided path to .ics files does not exist: '{}'".format(cal_dir))
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# Get all .ics files from your directory
|
|
||||||
files = glob.glob(os.path.join(cal_dir, '*.ics'))
|
|
||||||
|
|
||||||
class DateTimeEncoder(json.JSONEncoder):
|
class DateTimeEncoder(json.JSONEncoder):
|
||||||
def default(self, o):
|
def default(self, o):
|
||||||
if isinstance(o, (dt.datetime, dt.timedelta)):
|
if isinstance(o, (dt.datetime, dt.timedelta)):
|
||||||
|
@ -316,7 +313,7 @@ def get_next_alert(event, current_time):
|
||||||
next_alert = min(next_alert_list)
|
next_alert = min(next_alert_list)
|
||||||
return next_alert - dt.timedelta(seconds=5), next_event
|
return next_alert - dt.timedelta(seconds=5), next_event
|
||||||
|
|
||||||
def process_alert(current_time, next_alert, event):
|
def process_alert(current_time, next_alert, next_event, event, config):
|
||||||
if current_time >= next_alert and next_alert < next_alert + dt.timedelta(seconds=15):
|
if current_time >= next_alert and next_alert < next_alert + dt.timedelta(seconds=15):
|
||||||
if len(event["alert_history"]) == 0:
|
if len(event["alert_history"]) == 0:
|
||||||
print("First alert for '{}' detected".format(event["summary"]))
|
print("First alert for '{}' detected".format(event["summary"]))
|
||||||
|
@ -333,18 +330,24 @@ def process_alert(current_time, next_alert, event):
|
||||||
f.write(str(event)) # write expects a str not dict
|
f.write(str(event)) # write expects a str not dict
|
||||||
return
|
return
|
||||||
|
|
||||||
# Create initial event_list using calendar_parser
|
def create_event_list(files):
|
||||||
event_list = [] # List to hold dictionaries for each event
|
event_list = [] # List to hold dictionaries for each event
|
||||||
for file in files:
|
for file in files:
|
||||||
with open(file, 'r') as f:
|
with open(file, 'r') as f:
|
||||||
cal_str = f.read()
|
cal_str = f.read()
|
||||||
event_dict = calendar_parser(cal_str)
|
event_dict = calendar_parser(cal_str)
|
||||||
event_list.append(event_dict)
|
event_list.append(event_dict)
|
||||||
|
return event_list
|
||||||
|
|
||||||
|
def start_observer(cal_dir):
|
||||||
observer = Observer()
|
observer = Observer()
|
||||||
handler = FileChangeHandler()
|
handler = FileChangeHandler()
|
||||||
observer.schedule(handler, cal_dir, recursive=True)
|
observer.schedule(handler, cal_dir, recursive=True)
|
||||||
observer.start()
|
observer.start()
|
||||||
|
return observer
|
||||||
|
|
||||||
|
def main_loop(event_list, config, cal_dir):
|
||||||
|
observer = start_observer(cal_dir)
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
with open("status", 'w') as f:
|
with open("status", 'w') as f:
|
||||||
|
@ -358,13 +361,40 @@ try:
|
||||||
event_delta = next_alert-current_time
|
event_delta = next_alert-current_time
|
||||||
total_seconds = event_delta.total_seconds()
|
total_seconds = event_delta.total_seconds()
|
||||||
human_readable_time = humanfriendly.format_timespan(total_seconds)
|
human_readable_time = humanfriendly.format_timespan(total_seconds)
|
||||||
monitor_status = "Current time: {}\nMonitoring: {}\nEvent date: {}\nRecur Dates: {}\nNext alert on: {} in {}\nRecur info: {}\nAlert history: {}\n".format(current_time, event["summary"], next_event, [str(i) for i in event["event_dates"]], next_alert, human_readable_time, event["recur_info"], event["alert_history"])
|
monitor_status = f"""\
|
||||||
|
Current time: {current_time}
|
||||||
|
Monitoring: {event["summary"]}
|
||||||
|
Event date: {next_event}
|
||||||
|
Recur Dates: {[str(i) for i in event["event_dates"]]}
|
||||||
|
Next alert on: {next_alert} in {human_readable_time}
|
||||||
|
Recur info: {event["recur_info"]}
|
||||||
|
Alert history: {event["alert_history"]}\n"""
|
||||||
|
monitor_status = textwrap.dedent(monitor_status)
|
||||||
with open("status", 'a') as f:
|
with open("status", 'a') as f:
|
||||||
# Write the output to the file
|
# Write the output to the file
|
||||||
f.write(monitor_status)
|
f.write(monitor_status)
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
process_alert(current_time, next_alert, event)
|
process_alert(current_time, next_alert, next_event, event, config)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
observer.stop()
|
observer.stop()
|
||||||
observer.join()
|
observer.join()
|
||||||
|
|
||||||
|
# Main script execution starts here
|
||||||
|
def main():
|
||||||
|
args = parse_args()
|
||||||
|
print(args)
|
||||||
|
content = read_file(args.config)
|
||||||
|
config = parse_toml(content)
|
||||||
|
|
||||||
|
cal_dir = Path(config["app"]["calendar_dir"])
|
||||||
|
if not cal_dir.is_dir():
|
||||||
|
print(f"The provided path to .ics files does not exist: '{cal_dir}'")
|
||||||
|
sys.exit(1) # Exit with error code
|
||||||
|
|
||||||
|
files = list(cal_dir.glob('*.ics'))
|
||||||
|
event_list = create_event_list(files)
|
||||||
|
main_loop(event_list, config, cal_dir)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
Loading…
Reference in New Issue