Merge pull request #16 from amszuidas/experimental

fix: refactor env var resolution to support complex structures and fix in-place mutation bug
This commit is contained in:
Henry Li
2026-01-24 10:14:20 +08:00
committed by GitHub
2 changed files with 12 additions and 16 deletions

View File

@@ -1,6 +1,6 @@
import os import os
from pathlib import Path from pathlib import Path
from typing import Self from typing import Any, Self
import yaml import yaml
from dotenv import load_dotenv from dotenv import load_dotenv
@@ -72,7 +72,7 @@ class AppConfig(BaseModel):
resolved_path = cls.resolve_config_path(config_path) resolved_path = cls.resolve_config_path(config_path)
with open(resolved_path) as f: with open(resolved_path) as f:
config_data = yaml.safe_load(f) config_data = yaml.safe_load(f)
cls.resolve_env_variables(config_data) config_data = cls.resolve_env_variables(config_data)
# Load title config if present # Load title config if present
if "title" in config_data: if "title" in config_data:
@@ -90,7 +90,7 @@ class AppConfig(BaseModel):
return result return result
@classmethod @classmethod
def resolve_env_variables(cls, config: dict) -> dict: def resolve_env_variables(cls, config: Any) -> Any:
"""Recursively resolve environment variables in the config. """Recursively resolve environment variables in the config.
Environment variables are resolved using the `os.getenv` function. Example: $OPENAI_API_KEY Environment variables are resolved using the `os.getenv` function. Example: $OPENAI_API_KEY
@@ -101,18 +101,14 @@ class AppConfig(BaseModel):
Returns: Returns:
The config with environment variables resolved. The config with environment variables resolved.
""" """
for key, value in config.items(): if isinstance(config, str):
if isinstance(value, str): if config.startswith("$"):
if value.startswith("$"): return os.getenv(config[1:], config)
env_value = os.getenv(value[1:], None) return config
if env_value is not None: elif isinstance(config, dict):
config[key] = env_value return {k: cls.resolve_env_variables(v) for k, v in config.items()}
else: elif isinstance(config, list):
config[key] = value return [cls.resolve_env_variables(item) for item in config]
elif isinstance(value, dict):
config[key] = cls.resolve_env_variables(value)
elif isinstance(value, list):
config[key] = [cls.resolve_env_variables(item) for item in value]
return config return config
def get_model_config(self, name: str) -> ModelConfig | None: def get_model_config(self, name: str) -> ModelConfig | None:

View File

@@ -27,7 +27,7 @@ class Sandbox(ABC):
@abstractmethod @abstractmethod
def read_file(self, path: str) -> str: def read_file(self, path: str) -> str:
"""Read tge content of a file. """Read the content of a file.
Args: Args:
path: The absolute path of the file to read. path: The absolute path of the file to read.