Load config, harden processing and notifications
- Actually load configs/config.yaml at startup (init_config was commented out) - Add timeouts and error handling to all HTTP calls; run blocking requests in threads; serialize processing with a lock; run initial check in background - URL-encode Telegram messages and HTML-escape scraped data - Fix GPV crash on empty schedule, 00:00 end time, date sorting and fallback format - Parse PO table per row; fix daily reminder check and change detection - Use per-instance timestamps in dataclasses; robust config value parsing - Matrix: use v3 PUT send endpoint; strip secrets from logged errors - Resolve templates/static/test paths relative to the project; use lifespan - Move debug GPV data to test/data_gpv.json; add CLAUDE.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
e3367c6a2e
commit
22fc8b38bf
+27
-31
@@ -1,43 +1,43 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
def read_config(name):
|
||||
if not os.path.isfile(name):
|
||||
raise Exception(f"File {name} doesn't exists")
|
||||
filename, ext = os.path.splitext(name)
|
||||
if 'json' in ext:
|
||||
raise FileNotFoundError(f"File {name} doesn't exist")
|
||||
_, ext = os.path.splitext(name)
|
||||
ext = ext.lower()
|
||||
if ext == '.json':
|
||||
return read_json(name)
|
||||
elif 'properties' in ext:
|
||||
elif ext == '.properties':
|
||||
return read_prop(name)
|
||||
elif 'yaml' in ext or 'yml' in ext:
|
||||
elif ext in ('.yaml', '.yml'):
|
||||
return read_yaml(name)
|
||||
else:
|
||||
raise Exception("Wrong file type")
|
||||
raise ValueError(f"Wrong file type: {ext}")
|
||||
|
||||
|
||||
def read_json(name):
|
||||
with open(name, 'r', encoding='utf-8') as f:
|
||||
j_conf = json.load(f)
|
||||
conf = {}
|
||||
for key, value in j_conf.items():
|
||||
conf[key] = value
|
||||
return conf
|
||||
return dict(json.load(f))
|
||||
|
||||
|
||||
def read_prop(filepath, sep='=', comment_char='#'):
|
||||
"""
|
||||
Read the file passed as parameter as a properties file.
|
||||
"""
|
||||
conf = {}
|
||||
with open(filepath, "rt") as f:
|
||||
with open(filepath, "rt", encoding='utf-8') as f:
|
||||
for line in f:
|
||||
l = line.strip()
|
||||
if l and not l.startswith(comment_char):
|
||||
key_value = l.split(sep)
|
||||
key = key_value[0].strip()
|
||||
value = sep.join(key_value[1:]).strip().strip('"')
|
||||
conf[key] = value
|
||||
key, _, value = l.partition(sep)
|
||||
conf[key.strip()] = value.strip().strip('"')
|
||||
return conf
|
||||
|
||||
|
||||
def read_yaml(name, secrets_file='secrets.yaml'):
|
||||
# Load secrets first
|
||||
secrets = {}
|
||||
@@ -47,28 +47,24 @@ def read_yaml(name, secrets_file='secrets.yaml'):
|
||||
with open(secrets_path, 'r', encoding='utf-8') as f:
|
||||
secrets = yaml.safe_load(f) or {}
|
||||
|
||||
# Define a custom constructor for !secret tag
|
||||
def secret_constructor(loader, node):
|
||||
secret_key = loader.construct_scalar(node)
|
||||
if secret_key not in secrets:
|
||||
raise ValueError(f"Secret '{secret_key}' not found in {secrets_file}")
|
||||
return secrets[secret_key]
|
||||
|
||||
# Register the custom constructor
|
||||
yaml.add_constructor('!secret', secret_constructor, Loader=yaml.SafeLoader)
|
||||
# Own loader class, so the global yaml.SafeLoader is not modified
|
||||
class SecretLoader(yaml.SafeLoader):
|
||||
pass
|
||||
|
||||
SecretLoader.add_constructor('!secret', secret_constructor)
|
||||
|
||||
# Load the main configuration
|
||||
conf = {}
|
||||
with open(name, 'r', encoding='utf-8') as f:
|
||||
y_conf = yaml.safe_load(f)
|
||||
if y_conf:
|
||||
for key, value in y_conf.items():
|
||||
conf[key] = value
|
||||
y_conf = yaml.load(f, Loader=SecretLoader)
|
||||
|
||||
return conf
|
||||
|
||||
def main():
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
if y_conf is None:
|
||||
return {}
|
||||
if not isinstance(y_conf, dict):
|
||||
raise ValueError(f"Wrong config structure in {name}: top level must be a mapping")
|
||||
return dict(y_conf)
|
||||
|
||||
Reference in New Issue
Block a user