Coverage for src/rhiza_tools/config.py: 100%
30 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-30 13:37 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-30 13:37 +0000
1"""Configuration management for rhiza-tools.
3This module provides configuration loading and access for rhiza-tools.
4It reads configuration from a TOML file and provides convenient access
5to tool-specific settings.
7Example:
8 Load configuration from default path::
10 from rhiza_tools.config import load_config
12 config = load_config()
13 bumpversion_config = config.bumpversion
15 Load configuration from custom path::
17 from pathlib import Path
18 from rhiza_tools.config import load_config
20 config = load_config(Path("custom/.cfg.toml"))
21 value = config.get("custom_key", "default_value")
22"""
24from pathlib import Path
25from typing import Any
27import tomlkit
28import tomlkit.exceptions
29from loguru import logger
31from rhiza_tools import console
33CONFIG_FILENAME = ".rhiza/.cfg.toml"
36class RhizaConfig:
37 """Rhiza tools configuration.
39 Manages loading and accessing configuration from a TOML file. Provides
40 convenient access to tool-specific configuration sections.
42 Attributes:
43 config_path: Path to the configuration TOML file.
45 Example:
46 Basic usage::
48 config = RhizaConfig()
49 bumpversion = config.bumpversion
50 custom_value = config.get("my_key", "default")
52 With custom path::
54 config = RhizaConfig(Path("custom/.cfg.toml"))
55 config.load()
56 """
58 def __init__(self, config_path: Path | None = None) -> None:
59 """Initialize RhizaConfig.
61 Args:
62 config_path: Path to the configuration file. If None, uses the
63 default path defined in CONFIG_FILENAME.
64 """
65 self.config_path = config_path or Path(CONFIG_FILENAME)
66 self._data: tomlkit.TOMLDocument = tomlkit.TOMLDocument()
67 self.load()
69 def load(self) -> None:
70 """Load configuration from file.
72 Reads and parses the TOML configuration file. If the file doesn't exist,
73 the configuration will be empty. Logs errors if parsing fails.
75 Raises:
76 tomlkit.exceptions.ParseError: If the configuration file exists but contains invalid TOML.
77 OSError: If the configuration file cannot be read.
79 Example:
80 config = RhizaConfig(Path("custom/.cfg.toml"))
81 config.load()
82 """
83 if not self.config_path.exists():
84 logger.debug(f"Configuration file {self.config_path} not found.")
85 return
87 try:
88 with open(self.config_path) as f:
89 self._data = tomlkit.parse(f.read())
90 except (tomlkit.exceptions.ParseError, OSError) as e:
91 console.error(f"Failed to parse configuration file {self.config_path}: {e}")
92 raise
94 @property
95 # Returns the raw ``[tool.bumpversion]`` TOML sub-table. Its keys and value
96 # types are user-defined and open-ended (strings, bools, lists, nested
97 # tables), so ``dict[str, Any]`` is the honest type for this passthrough —
98 # the strongly-typed bump path uses bump-my-version's own ``Config`` model.
99 def bumpversion(self) -> dict[str, Any]:
100 """Get bumpversion configuration.
102 Returns:
103 Dictionary containing bumpversion-specific configuration from the
104 [tool.bumpversion] section of the configuration file.
106 Example:
107 config = RhizaConfig()
108 bv_config = config.bumpversion
109 print(bv_config.get("current_version"))
110 """
111 result: dict[str, Any] = self._data.get("tool", {}).get("bumpversion", {})
112 return result
114 # Generic accessor over arbitrary top-level TOML keys; the value type is
115 # only known to the caller, so ``Any`` is intentional here (TOML passthrough).
116 def get(self, key: str, default: Any = None) -> Any:
117 """Get configuration value.
119 Args:
120 key: Configuration key to retrieve.
121 default: Default value to return if key is not found.
123 Returns:
124 The configuration value for the given key, or default if not found.
126 Example:
127 config = RhizaConfig()
128 value = config.get("custom_setting", "default_value")
129 """
130 return self._data.get(key, default)
133def load_config(path: Path | None = None) -> RhizaConfig:
134 """Load configuration.
136 Convenience function to create and load a RhizaConfig instance.
138 Args:
139 path: Path to the configuration file. If None, uses the default path.
141 Returns:
142 A RhizaConfig instance with the configuration loaded.
144 Example:
145 Load default configuration::
147 config = load_config()
149 Load from custom path::
151 from pathlib import Path
152 config = load_config(Path("custom/.cfg.toml"))
153 """
154 return RhizaConfig(path)