geronimo.config.user_config

User configuration management for Geronimo.

Provides persistent global settings stored in ~/.geronimo/config.yaml. Settings apply as defaults for all projects.

  1"""User configuration management for Geronimo.
  2
  3Provides persistent global settings stored in ~/.geronimo/config.yaml.
  4Settings apply as defaults for all projects.
  5"""
  6
  7import os
  8from dataclasses import dataclass, field
  9from pathlib import Path
 10from typing import Literal, Optional
 11
 12import yaml
 13
 14
 15# Default config location
 16USER_CONFIG_DIR = Path.home() / ".geronimo"
 17USER_CONFIG_FILE = USER_CONFIG_DIR / "config.yaml"
 18
 19
 20@dataclass
 21class ArtifactConfig:
 22    """Configuration for ArtifactStore defaults."""
 23    
 24    backend: Literal["local", "s3", "gdc"] = "local"
 25    """Default storage backend."""
 26
 27    s3_bucket: Optional[str] = None
 28    """Default S3 bucket (if backend is s3)."""
 29
 30    base_path: str = "~/.geronimo/artifacts"
 31    """Default local base path (if backend is local)."""
 32
 33
 34@dataclass
 35class DefaultsConfig:
 36    """Default project initialization settings."""
 37    
 38    framework: str = "sklearn"
 39    """Default ML framework."""
 40
 41    template: str = "realtime"
 42    """Default project template."""
 43
 44
 45@dataclass
 46class UserConfig:
 47    """Global user configuration.
 48    
 49    Stored in ~/.geronimo/config.yaml.
 50    """
 51    
 52    artifacts: ArtifactConfig = field(default_factory=ArtifactConfig)
 53    """Artifact storage configuration."""
 54
 55    defaults: DefaultsConfig = field(default_factory=DefaultsConfig)
 56    """Default project settings."""
 57
 58
 59def load_user_config() -> UserConfig:
 60    """Load global config from ~/.geronimo/config.yaml.
 61    
 62    Returns default config if file doesn't exist.
 63    
 64    Returns:
 65        UserConfig with loaded or default settings.
 66    """
 67    if not USER_CONFIG_FILE.exists():
 68        return UserConfig()
 69    
 70    try:
 71        with open(USER_CONFIG_FILE) as f:
 72            data = yaml.safe_load(f) or {}
 73        
 74        # Parse artifacts section
 75        artifacts_data = data.get("artifacts", {})
 76        artifacts = ArtifactConfig(
 77            backend=artifacts_data.get("backend", "local"),
 78            s3_bucket=artifacts_data.get("s3_bucket"),
 79            base_path=artifacts_data.get("base_path", "~/.geronimo/artifacts"),
 80        )
 81        
 82        # Parse defaults section
 83        defaults_data = data.get("defaults", {})
 84        defaults = DefaultsConfig(
 85            framework=defaults_data.get("framework", "sklearn"),
 86            template=defaults_data.get("template", "realtime"),
 87        )
 88        
 89        return UserConfig(artifacts=artifacts, defaults=defaults)
 90    except Exception:
 91        # Return defaults on any parsing error
 92        return UserConfig()
 93
 94
 95def save_user_config(config: UserConfig) -> None:
 96    """Save global config to ~/.geronimo/config.yaml.
 97    
 98    Creates ~/.geronimo directory if it doesn't exist.
 99    
100    Args:
101        config: UserConfig to save.
102    """
103    USER_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
104    
105    data = {
106        "artifacts": {
107            "backend": config.artifacts.backend,
108            "s3_bucket": config.artifacts.s3_bucket,
109            "base_path": config.artifacts.base_path,
110        },
111        "defaults": {
112            "framework": config.defaults.framework,
113            "template": config.defaults.template,
114        },
115    }
116    
117    # Remove None values for cleaner YAML
118    data["artifacts"] = {k: v for k, v in data["artifacts"].items() if v is not None}
119    
120    with open(USER_CONFIG_FILE, "w") as f:
121        yaml.dump(data, f, default_flow_style=False, sort_keys=False)
122
123
124def get_config_value(key: str) -> Optional[str]:
125    """Get a specific config value by dot-notation key.
126    
127    Args:
128        key: Dot-notation key like "artifacts.backend"
129        
130    Returns:
131        Value as string, or None if not found.
132    """
133    config = load_user_config()
134    
135    parts = key.split(".")
136    if len(parts) != 2:
137        return None
138    
139    section, field = parts
140    
141    if section == "artifacts":
142        return getattr(config.artifacts, field, None)
143    elif section == "defaults":
144        return getattr(config.defaults, field, None)
145    
146    return None
147
148
149def set_config_value(key: str, value: str) -> bool:
150    """Set a specific config value by dot-notation key.
151    
152    Args:
153        key: Dot-notation key like "artifacts.backend"
154        value: Value to set
155        
156    Returns:
157        True if successful, False if invalid key.
158    """
159    config = load_user_config()
160    
161    parts = key.split(".")
162    if len(parts) != 2:
163        return False
164    
165    section, field_name = parts
166    
167    if section == "artifacts":
168        if field_name == "backend":
169            if value not in ("local", "s3", "gdc"):
170                return False
171            config.artifacts.backend = value
172        elif field_name == "s3_bucket":
173            config.artifacts.s3_bucket = value
174        elif field_name == "base_path":
175            config.artifacts.base_path = value
176        else:
177            return False
178    elif section == "defaults":
179        if field_name == "framework":
180            config.defaults.framework = value
181        elif field_name == "template":
182            config.defaults.template = value
183        else:
184            return False
185    else:
186        return False
187    
188    save_user_config(config)
189    return True
190
191
192def reset_user_config() -> None:
193    """Reset config to defaults by deleting the config file."""
194    if USER_CONFIG_FILE.exists():
195        USER_CONFIG_FILE.unlink()
USER_CONFIG_DIR = PosixPath('/Users/csweet/.geronimo')
USER_CONFIG_FILE = PosixPath('/Users/csweet/.geronimo/config.yaml')
@dataclass
class ArtifactConfig:
21@dataclass
22class ArtifactConfig:
23    """Configuration for ArtifactStore defaults."""
24    
25    backend: Literal["local", "s3", "gdc"] = "local"
26    """Default storage backend."""
27
28    s3_bucket: Optional[str] = None
29    """Default S3 bucket (if backend is s3)."""
30
31    base_path: str = "~/.geronimo/artifacts"
32    """Default local base path (if backend is local)."""

Configuration for ArtifactStore defaults.

ArtifactConfig( backend: Literal['local', 's3', 'gdc'] = 'local', s3_bucket: Optional[str] = None, base_path: str = '~/.geronimo/artifacts')
backend: Literal['local', 's3', 'gdc'] = 'local'

Default storage backend.

s3_bucket: Optional[str] = None

Default S3 bucket (if backend is s3).

base_path: str = '~/.geronimo/artifacts'

Default local base path (if backend is local).

@dataclass
class DefaultsConfig:
35@dataclass
36class DefaultsConfig:
37    """Default project initialization settings."""
38    
39    framework: str = "sklearn"
40    """Default ML framework."""
41
42    template: str = "realtime"
43    """Default project template."""

Default project initialization settings.

DefaultsConfig(framework: str = 'sklearn', template: str = 'realtime')
framework: str = 'sklearn'

Default ML framework.

template: str = 'realtime'

Default project template.

@dataclass
class UserConfig:
46@dataclass
47class UserConfig:
48    """Global user configuration.
49    
50    Stored in ~/.geronimo/config.yaml.
51    """
52    
53    artifacts: ArtifactConfig = field(default_factory=ArtifactConfig)
54    """Artifact storage configuration."""
55
56    defaults: DefaultsConfig = field(default_factory=DefaultsConfig)
57    """Default project settings."""

Global user configuration.

Stored in ~/.geronimo/config.yaml.

UserConfig( artifacts: ArtifactConfig = <factory>, defaults: DefaultsConfig = <factory>)
artifacts: ArtifactConfig

Artifact storage configuration.

defaults: DefaultsConfig

Default project settings.

def load_user_config() -> UserConfig:
60def load_user_config() -> UserConfig:
61    """Load global config from ~/.geronimo/config.yaml.
62    
63    Returns default config if file doesn't exist.
64    
65    Returns:
66        UserConfig with loaded or default settings.
67    """
68    if not USER_CONFIG_FILE.exists():
69        return UserConfig()
70    
71    try:
72        with open(USER_CONFIG_FILE) as f:
73            data = yaml.safe_load(f) or {}
74        
75        # Parse artifacts section
76        artifacts_data = data.get("artifacts", {})
77        artifacts = ArtifactConfig(
78            backend=artifacts_data.get("backend", "local"),
79            s3_bucket=artifacts_data.get("s3_bucket"),
80            base_path=artifacts_data.get("base_path", "~/.geronimo/artifacts"),
81        )
82        
83        # Parse defaults section
84        defaults_data = data.get("defaults", {})
85        defaults = DefaultsConfig(
86            framework=defaults_data.get("framework", "sklearn"),
87            template=defaults_data.get("template", "realtime"),
88        )
89        
90        return UserConfig(artifacts=artifacts, defaults=defaults)
91    except Exception:
92        # Return defaults on any parsing error
93        return UserConfig()

Load global config from ~/.geronimo/config.yaml.

Returns default config if file doesn't exist.

Returns: UserConfig with loaded or default settings.

def save_user_config(config: UserConfig) -> None:
 96def save_user_config(config: UserConfig) -> None:
 97    """Save global config to ~/.geronimo/config.yaml.
 98    
 99    Creates ~/.geronimo directory if it doesn't exist.
100    
101    Args:
102        config: UserConfig to save.
103    """
104    USER_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
105    
106    data = {
107        "artifacts": {
108            "backend": config.artifacts.backend,
109            "s3_bucket": config.artifacts.s3_bucket,
110            "base_path": config.artifacts.base_path,
111        },
112        "defaults": {
113            "framework": config.defaults.framework,
114            "template": config.defaults.template,
115        },
116    }
117    
118    # Remove None values for cleaner YAML
119    data["artifacts"] = {k: v for k, v in data["artifacts"].items() if v is not None}
120    
121    with open(USER_CONFIG_FILE, "w") as f:
122        yaml.dump(data, f, default_flow_style=False, sort_keys=False)

Save global config to ~/.geronimo/config.yaml.

Creates ~/.geronimo directory if it doesn't exist.

Args: config: UserConfig to save.

def get_config_value(key: str) -> Optional[str]:
125def get_config_value(key: str) -> Optional[str]:
126    """Get a specific config value by dot-notation key.
127    
128    Args:
129        key: Dot-notation key like "artifacts.backend"
130        
131    Returns:
132        Value as string, or None if not found.
133    """
134    config = load_user_config()
135    
136    parts = key.split(".")
137    if len(parts) != 2:
138        return None
139    
140    section, field = parts
141    
142    if section == "artifacts":
143        return getattr(config.artifacts, field, None)
144    elif section == "defaults":
145        return getattr(config.defaults, field, None)
146    
147    return None

Get a specific config value by dot-notation key.

Args: key: Dot-notation key like "artifacts.backend"

Returns: Value as string, or None if not found.

def set_config_value(key: str, value: str) -> bool:
150def set_config_value(key: str, value: str) -> bool:
151    """Set a specific config value by dot-notation key.
152    
153    Args:
154        key: Dot-notation key like "artifacts.backend"
155        value: Value to set
156        
157    Returns:
158        True if successful, False if invalid key.
159    """
160    config = load_user_config()
161    
162    parts = key.split(".")
163    if len(parts) != 2:
164        return False
165    
166    section, field_name = parts
167    
168    if section == "artifacts":
169        if field_name == "backend":
170            if value not in ("local", "s3", "gdc"):
171                return False
172            config.artifacts.backend = value
173        elif field_name == "s3_bucket":
174            config.artifacts.s3_bucket = value
175        elif field_name == "base_path":
176            config.artifacts.base_path = value
177        else:
178            return False
179    elif section == "defaults":
180        if field_name == "framework":
181            config.defaults.framework = value
182        elif field_name == "template":
183            config.defaults.template = value
184        else:
185            return False
186    else:
187        return False
188    
189    save_user_config(config)
190    return True

Set a specific config value by dot-notation key.

Args: key: Dot-notation key like "artifacts.backend" value: Value to set

Returns: True if successful, False if invalid key.

def reset_user_config() -> None:
193def reset_user_config() -> None:
194    """Reset config to defaults by deleting the config file."""
195    if USER_CONFIG_FILE.exists():
196        USER_CONFIG_FILE.unlink()

Reset config to defaults by deleting the config file.