fdf
This commit is contained in:
@@ -11,7 +11,7 @@ import sys
|
||||
import tempfile
|
||||
from copy import deepcopy
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
|
||||
from SYS.logger import log
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -29,6 +29,7 @@ _CONFIG_CACHE: Dict[str, Any] = {}
|
||||
_LAST_SAVED_CONFIG: Dict[str, Any] = {}
|
||||
_CONFIG_SAVE_MAX_RETRIES = 5
|
||||
_CONFIG_SAVE_RETRY_DELAY = 0.15
|
||||
_CONFIG_MISSING = object()
|
||||
|
||||
|
||||
class ConfigSaveConflict(Exception):
|
||||
@@ -61,6 +62,94 @@ def clear_config_cache() -> None:
|
||||
_LAST_SAVED_CONFIG = {}
|
||||
|
||||
|
||||
def get_nested_config_value(config: Dict[str, Any], *path: str) -> Any:
|
||||
cur: Any = config
|
||||
for key in path:
|
||||
if not isinstance(cur, dict):
|
||||
return None
|
||||
cur = cur.get(key)
|
||||
return cur
|
||||
|
||||
|
||||
def coerce_config_value(
|
||||
value: Any,
|
||||
existing_value: Any = _CONFIG_MISSING,
|
||||
*,
|
||||
on_error: Optional[Callable[[str], None]] = None,
|
||||
) -> Any:
|
||||
if not isinstance(value, str):
|
||||
return value
|
||||
|
||||
text = value.strip()
|
||||
lowered = text.lower()
|
||||
|
||||
if existing_value is _CONFIG_MISSING:
|
||||
if lowered in {"true", "false"}:
|
||||
return lowered == "true"
|
||||
if text.isdigit():
|
||||
return int(text)
|
||||
return value
|
||||
|
||||
if isinstance(existing_value, bool):
|
||||
if lowered in {"true", "yes", "1", "on"}:
|
||||
return True
|
||||
if lowered in {"false", "no", "0", "off"}:
|
||||
return False
|
||||
if on_error is not None:
|
||||
on_error(f"Warning: Could not convert '{value}' to boolean. Using string.")
|
||||
return value
|
||||
|
||||
if isinstance(existing_value, int) and not isinstance(existing_value, bool):
|
||||
try:
|
||||
return int(text)
|
||||
except ValueError:
|
||||
if on_error is not None:
|
||||
on_error(f"Warning: Could not convert '{value}' to int. Using string.")
|
||||
return value
|
||||
|
||||
if isinstance(existing_value, float):
|
||||
try:
|
||||
return float(text)
|
||||
except ValueError:
|
||||
if on_error is not None:
|
||||
on_error(f"Warning: Could not convert '{value}' to float. Using string.")
|
||||
return value
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def set_nested_config_value(
|
||||
config: Dict[str, Any],
|
||||
key_path: str | Sequence[str],
|
||||
value: Any,
|
||||
*,
|
||||
on_error: Optional[Callable[[str], None]] = None,
|
||||
) -> bool:
|
||||
if not isinstance(config, dict):
|
||||
return False
|
||||
|
||||
if isinstance(key_path, str):
|
||||
keys = [part for part in key_path.split(".") if part]
|
||||
else:
|
||||
keys = [str(part) for part in (key_path or []) if str(part)]
|
||||
|
||||
if not keys:
|
||||
return False
|
||||
|
||||
current = config
|
||||
for key in keys[:-1]:
|
||||
next_value = current.get(key)
|
||||
if not isinstance(next_value, dict):
|
||||
next_value = {}
|
||||
current[key] = next_value
|
||||
current = next_value
|
||||
|
||||
last_key = keys[-1]
|
||||
existing_value = current[last_key] if last_key in current else _CONFIG_MISSING
|
||||
current[last_key] = coerce_config_value(value, existing_value, on_error=on_error)
|
||||
return True
|
||||
|
||||
|
||||
def get_hydrus_instance(
|
||||
config: Dict[str, Any], instance_name: str = "home"
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
|
||||
Reference in New Issue
Block a user