增强配置系统
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
@@ -28,6 +29,43 @@ def _replace_placeholders(value: Any, project_root: Path) -> Any:
|
||||
return value
|
||||
|
||||
|
||||
def _import_from_path(import_path: str) -> Any:
|
||||
module_path, sep, attr_path = import_path.partition(":")
|
||||
if not module_path:
|
||||
raise ValueError(f"Invalid import path: {import_path}")
|
||||
|
||||
module = importlib.import_module(module_path)
|
||||
if not sep:
|
||||
return module
|
||||
|
||||
obj: Any = module
|
||||
for attr_name in attr_path.split("."):
|
||||
obj = getattr(obj, attr_name)
|
||||
return obj
|
||||
|
||||
|
||||
def _apply_datasource_bootstraps(payload: Dict[str, Any]) -> Dict[str, Any]:
|
||||
extensions = payload.pop("extensions", None)
|
||||
if extensions is None:
|
||||
return payload
|
||||
if not isinstance(extensions, dict):
|
||||
raise ValueError("extensions must be an object mapping")
|
||||
|
||||
bootstrap_paths = extensions.get("datasource_bootstraps") or []
|
||||
if not isinstance(bootstrap_paths, list):
|
||||
raise ValueError("extensions.datasource_bootstraps must be a list")
|
||||
|
||||
for item in bootstrap_paths:
|
||||
if not isinstance(item, str) or not item.strip():
|
||||
raise ValueError("extensions.datasource_bootstraps entries must be non-empty strings")
|
||||
loaded = _import_from_path(item)
|
||||
if not callable(loaded):
|
||||
raise TypeError(f"datasource bootstrap must resolve to a callable: {item}")
|
||||
loaded()
|
||||
|
||||
return payload
|
||||
|
||||
|
||||
def list_preset_names() -> List[str]:
|
||||
return sorted(PRESET_FILES.keys())
|
||||
|
||||
@@ -77,7 +115,7 @@ def load_overrides_from_file(file_path: Path, project_root: Path) -> Dict[str, A
|
||||
resolved = _replace_placeholders(payload, project_root)
|
||||
if not isinstance(resolved, dict):
|
||||
raise ValueError(f"Preset file must contain object mapping: {file_path}")
|
||||
return resolved
|
||||
return _apply_datasource_bootstraps(resolved)
|
||||
|
||||
|
||||
def load_named_preset_overrides(project_root: Path, preset_name: str) -> Tuple[Dict[str, Any], Path, bool]:
|
||||
|
||||
Reference in New Issue
Block a user