Files
EO_Sevice/config_file.py
T
Anry DasandClaude Opus 5.5 22fc8b38bf 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>
2026-10-13 14:04:18 +03:00

71 lines
2.0 KiB
Python

import json
import os
import yaml
def read_config(name):
if not os.path.isfile(name):
raise FileNotFoundError(f"File {name} doesn't exist")
_, ext = os.path.splitext(name)
ext = ext.lower()
if ext == '.json':
return read_json(name)
elif ext == '.properties':
return read_prop(name)
elif ext in ('.yaml', '.yml'):
return read_yaml(name)
else:
raise ValueError(f"Wrong file type: {ext}")
def read_json(name):
with open(name, 'r', encoding='utf-8') as f:
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", encoding='utf-8') as f:
for line in f:
l = line.strip()
if l and not l.startswith(comment_char):
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 = {}
secrets_path = os.path.join(os.path.dirname(name), secrets_file)
if os.path.exists(secrets_path):
with open(secrets_path, 'r', encoding='utf-8') as f:
secrets = yaml.safe_load(f) or {}
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]
# 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
with open(name, 'r', encoding='utf-8') as f:
y_conf = yaml.load(f, Loader=SecretLoader)
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)