Skip to content

Commit 09c359c

Browse files
committed
docs: Enhanced ConfigurationManager Documentation
- Expanded the constructor section for clearer parameter explanations. - Detailed method functionalities, including `get_value`, `set_value`, `evaluate_path`, `get_environment`, and `get_logger`. - Updated `get_logger` method documentation to reflect new `logger_format` parameter. - Provided comprehensive usage examples showcasing key class functionalities. - Included error handling details for methods where applicable. Refined documentation for better clarity and user guidance.
1 parent 11512f1 commit 09c359c

File tree

1 file changed

+225
-69
lines changed

1 file changed

+225
-69
lines changed

docs/manager/configuration.md

Lines changed: 225 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,276 @@
11
# ConfigurationManager Class
22

3-
The `ConfigurationManager` class is a key component of the JSON-Py-Craft library. It provides a high-level interface for managing configuration data in a JSON-based format. This class is designed to simplify the process of handling configuration settings, including loading, saving, backing up, and accessing values within the configuration data.
3+
The `ConfigurationManager` class is a key component of the **JSONPyCraft** library. It provides a high-level interface for managing configuration data in a JSON-based format. This class is designed to simplify the process of handling configuration settings, including loading, saving, backing up, and accessing values within the configuration data.
44

55
## Class Hierarchy
66

77
- `Singleton` (Inherits from)
88
- `ConfigurationManager`
99

10-
## Constructor
10+
### `ConfigurationManager(file_path: str, initial_data: Optional[JSONMap] = None, indent: int = 2)`
1111

12-
### `ConfigurationManager(file_path: str, initial_data: Optional[JSONMap] = None, logger: Optional[Logger] = None)`
12+
- **Purpose**: The constructor initializes a new `ConfigurationManager` instance, setting up the essential links to a JSON configuration file. It is designed to manage configuration settings, whether creating a new file or handling an existing one.
1313

14-
- Initializes a new `ConfigurationManager` instance.
15-
- Parameters:
16-
- `file_path` (str): The path to the configuration JSON file.
17-
- `initial_data` (Optional[JSONMap]): Optional initial configuration data.
18-
- `logger` (Optional[Logger]): Optional logger for error-handling.
14+
- **Parameters**:
15+
- `file_path` (str): The path to the JSON configuration file. This parameter is crucial as it determines which file the manager will interact with for all operations. The path can be relative or absolute.
16+
- `initial_data` (Optional[JSONMap]): Optional initial data to populate a new configuration file. This parameter is particularly useful for establishing default settings in a configuration. It is important to note that if the specified JSON file already exists, this initial data does not merge with the existing data; instead, it's used only if the file does not exist or when explicitly saving this data.
17+
- `indent` (int, optional): Sets the JSON indentation level for the output format, affecting the readability of the saved configuration file. The default is 2, which is a standard practice for JSON formatting.
18+
19+
- **Functionality**:
20+
- Upon instantiation, `ConfigurationManager` prepares to manage the specified JSON file. The `initial_data` is held in readiness to be used if needed (e.g., creating a new file or explicitly saving this initial data). No automatic merging of `initial_data` with existing data occurs.
21+
- The `indent` parameter influences the aesthetics of the JSON file, making it more readable when opened in a text editor.
22+
23+
- **Error Handling**:
24+
- The constructor itself does not handle errors related to file operations or data handling. These are managed within their respective methods (`load`, `save`, and `backup`). This design choice keeps the constructor simple and delegates error handling to the specific operations where errors are more likely to occur.
25+
26+
- **Example Usage**:
27+
- Showcasing the initialization of the `ConfigurationManager` with and without the `initial_data` parameter.
28+
29+
```python
30+
# Initializing ConfigurationManager for an existing configuration file
31+
config_manager = ConfigurationManager("existing_config.json")
32+
33+
# Initializing ConfigurationManager with initial data for a new configuration file
34+
initial_config = {"app_name": "MyApp", "version": "1.0"}
35+
config_manager = ConfigurationManager("new_config.json", initial_data=initial_config)
36+
```
1937

2038
## Methods
2139

22-
### `load() -> bool`
40+
### `load() -> None`
2341

2442
- Loads configuration data from the file.
25-
- Returns:
26-
- `True` if the data was loaded successfully, `False` otherwise.
43+
- Raises:
44+
- `JSONFileErrorHandler`: If there is a file-related error accessing the JSON file.
45+
- `JSONDecodeErrorHandler`: If there is an error loading JSON data from the file.
2746

28-
### `save() -> bool`
47+
### `save() -> None`
2948

3049
- Saves configuration data to the file.
31-
- Returns:
32-
- `True` if the data was saved successfully, `False` otherwise.
50+
- Raises:
51+
- `JSONFileErrorHandler`: If there is a file-related error accessing the JSON file.
52+
- `JSONEncodeErrorHandler`: If there is an error saving JSON data to the file.
3353

34-
### `backup() -> bool`
54+
### `backup() -> None`
3555

3656
- Creates a backup of the configuration file.
37-
- Returns:
38-
- `True` if the backup was created successfully, `False` otherwise.
57+
- Raises:
58+
- `JSONFileErrorHandler`: If there is an error creating a backup of the JSON file.
59+
- `JSONDecodeErrorHandler`: If there is an error loading JSON data from the file during backup.
60+
- `JSONEncodeErrorHandler`: If there is an error saving JSON data to the file during backup.
3961

4062
### `get_value(key: str, default: Optional[Any] = None) -> Any`
4163

42-
- Gets a configuration value based on the provided key.
64+
- Retrieves a configuration value based on the provided key. Supports accessing nested values in the configuration data.
4365
- Parameters:
44-
- `key` (str): The key to retrieve the value for.
45-
- `default` (Optional[Any]): The default value to return if the key is not found.
66+
- `key` (str): The key for the desired value. Supports dot notation for nested keys (e.g., "section.subsection.key").
67+
- `default` (Optional[Any]): The default value to return if the key is not found. Ensures type consistency with the expected return value.
4668
- Returns:
47-
- The configuration value corresponding to the key, or the default value if not found.
69+
- The value corresponding to the key or the default value if the key is not found. If a non-existent key is provided and no default is specified, returns `None`.
70+
71+
Examples:
72+
73+
```python
74+
# Retrieving a simple configuration value with a default
75+
app_name = config_manager.get_value("app.name", "MyApp")
76+
print(f"Application Name: {app_name}")
77+
78+
# Accessing a nested configuration value
79+
db_port = config_manager.get_value("database.settings.port", 3306)
80+
print(f"Database Port: {db_port}")
81+
82+
# Handling non-existent keys
83+
unknown_key_value = config_manager.get_value("nonexistent.key")
84+
if unknown_key_value is None:
85+
print("The key 'nonexistent.key' was not found in the configuration.")
86+
```
4887

4988
### `set_value(key: str, value: Any) -> bool`
5089

51-
- Sets a configuration value for the provided key.
52-
- Parameters:
53-
- `key` (str): The key to set the value for.
54-
- `value` (Any): The value to set.
55-
- Returns:
56-
- `True` if the value was set successfully, `False` otherwise.
90+
- **Purpose**: Assigns a new value to a specified configuration key. This method is versatile and can handle both top-level and nested keys within the configuration structure.
5791

58-
### `evaluate_path(key: str, default: Optional[Any] = None) -> Optional[str]`
92+
- **Parameters**:
93+
- `key` (str): The key under which the value will be set. Supports dot notation for nested keys (e.g., "section.subsection.key"), allowing for deep updates within the configuration structure.
94+
- `value` (Any): The new value to be assigned. This can be of any data type supported by JSON (e.g., string, number, object).
5995

60-
- Evaluates a configuration path based on the provided key.
61-
- Parameters:
62-
- `key` (str): The key to retrieve the path for.
63-
- `default` (Optional[Any]): The default value to return if the path is not found.
64-
- Returns:
65-
- The evaluated path, or the default value if not found.
96+
- **Returns**:
97+
- `bool`: Always returns `True` if the update is successful.
98+
99+
- **Behavior and Error Handling**:
100+
- The method internally uses `JSONMapTemplate.update_nested` to handle nested keys. In this process, keys are expanded and coerced into strings, facilitating the handling of deeply nested structures.
101+
- Exceptions are raised in rare edge cases, such as when an invalid key structure is passed. The method will raise a `ValueError` for invalid keys or a `TypeError` for incompatible value types.
102+
- It's important to note that while `set_value` is designed to be robust and handle most typical use cases smoothly, the underlying complexity of `update_nested` should be considered when dealing with highly nested or complex configurations.
103+
104+
- **Examples**:
105+
- Demonstrating both simple and nested key updates, as well as error handling:
106+
107+
```python
108+
# Setting a simple configuration value
109+
try:
110+
config_manager.set_value("app.version", "1.0")
111+
print("Configuration value 'app.version' set to '1.0'")
112+
except (ValueError, TypeError) as e:
113+
print(f"Error setting 'app.version': {str(e)}")
114+
115+
# Updating a nested configuration value
116+
try:
117+
config_manager.set_value("database.settings.hostname", "db.example.com")
118+
print("Database hostname updated successfully.")
119+
except (ValueError, TypeError) as e:
120+
print(f"Error updating database hostname: {str(e)}")
121+
```
122+
123+
### `evaluate_path(key: str, default_path: Optional[Any] = None, default_type: str = "dir") -> Optional[str]`
124+
125+
- **Purpose**: This method is designed to retrieve and validate paths from the configuration data. It is particularly useful for dynamically determining file or directory paths based on the configuration settings.
126+
127+
- **Parameters**:
128+
- `key` (str): The key corresponding to the path in the configuration data. This key can be a simple string or a dot-notated string for nested keys.
129+
- `default_path` (Optional[str], optional): A fallback path to return when the specified key is not found in the configuration. This parameter allows for a default behavior when a configuration entry is missing.
130+
- `default_type` (str, optional): Specifies the expected type of the path – either "file" or "dir". This is used to determine the nature of the path validation and creation process. Defaults to "dir", implying that in the absence of explicit specification, the path is treated as a directory.
131+
132+
- **Returns**:
133+
- `Optional[str]`: The method returns the evaluated path as a string. If the key is not found, and a `default_path` is provided, that path is returned. If no `default_path` is specified, it returns `None`.
134+
135+
- **Functionality and Behavior**:
136+
- The method first attempts to retrieve the path specified by the `key`. If the path is not found in the configuration, and `default_path` is provided, the method returns this default path.
137+
- If the path does not exist in the file system, the method will attempt to create it based on the `default_type` parameter. For example, if `default_type` is "dir", it will try to create the directory structure. If it is "file", it will create an empty file at that location.
138+
- This functionality is particularly useful for ensuring that required directories or files are available at runtime, especially in scenarios where the application dynamically generates or modifies paths.
139+
140+
- **Examples**:
141+
- Demonstrating how to retrieve and automatically create paths:
142+
143+
```python
144+
# Retrieve a configuration path for logging
145+
log_path = config_manager.evaluate_path("logging.directory", default_path="/var/logs/myapp", default_type="dir")
146+
print(f"Log Path: {log_path}")
147+
148+
# Handle a configuration path for a data file
149+
data_file_path = config_manager.evaluate_path("data.filepath", default_path="data/default_data.json", default_type="file")
150+
print(f"Data File Path: {data_file_path}")
151+
```
66152

67153
### `get_environment(variable: str, key: Optional[str] = None) -> str`
68154

69-
- Gets the value of an environment variable.
70-
- Parameters:
71-
- `variable` (str): The name of the environment variable.
72-
- `key` (Optional[str]): The key in the configuration data where the environment variable is stored.
73-
- Returns:
74-
- The value of the environment variable.
155+
- **Purpose**: Retrieves the value of an environment variable, optionally mapping it to a configuration key. This method is designed to bridge the gap between the application's runtime environment and its configuration settings.
75156

76-
### `get_logger(key: str, logger_name: str, level: str = "DEBUG") -> Logger`
157+
- **Parameters**:
158+
- `variable` (str): Specifies the name of the environment variable to retrieve. This should match the variable's name as it is set in the system's environment.
159+
- `key` (Optional[str]): If provided, this parameter points to a key within the configuration data where the environment variable value is expected to be mirrored or overridden. This allows for dynamic configuration changes based on environmental conditions.
77160

78-
- Gets a logger instance with specified configuration.
79-
- Parameters:
80-
- `key` (str): A unique key identifying the logger configuration.
81-
- `logger_name` (str): The name of the logger.
82-
- `level` (str, optional): The log level for the logger (default is "DEBUG").
83-
- Returns:
84-
- A configured logger instance.
161+
- **Returns**:
162+
- `str`: The value of the specified environment variable. If the variable is not found in the system's environment and a `key` is provided, the method will attempt to retrieve the value from the configuration data associated with that key.
163+
164+
- **Behavior and Use Cases**:
165+
- The method first checks the system's environment for the specified `variable`. If found, its value is returned.
166+
- If the environment variable is not set, and a `key` is provided, the method looks up this key in the configuration data. This feature is useful for scenarios where certain settings might be overridden or specified within the application configuration instead of the environment.
167+
- This dual approach (environment variable first, then configuration data) provides flexibility and a fallback mechanism, allowing applications to adapt to different deployment environments and configurations seamlessly.
168+
169+
- **Examples**:
170+
- Demonstrating how to retrieve an environment variable and fallback to configuration data:
171+
172+
```python
173+
# Retrieving a database URL from an environment variable or configuration file
174+
db_url = config_manager.get_environment("DATABASE_URL", key="database.url")
175+
print(f"Database URL: {db_url}")
176+
177+
# Getting an API key with fallback to configuration if not set in the environment
178+
api_key = config_manager.get_environment("API_KEY", key="api.credentials.key")
179+
print(f"API Key: {api_key}")
180+
```
181+
182+
### `get_logger(key: str, logger_name: str, level: str = "DEBUG", logger_format: Optional[str] = None) -> Logger`
183+
184+
- **Purpose**: Retrieves a logger instance that is configured based on provided settings. This method offers customization for the logger's name, log level, and format, allowing for tailored logging setups according to different parts of an application.
185+
186+
- **Parameters**:
187+
- `key` (str): A unique key identifying the logger's configuration. This key is used to retrieve log settings such as file path and level from the configuration data.
188+
- `logger_name` (str): The name of the logger, which can be used to retrieve the same logger instance across different parts of the application.
189+
- `level` (str, optional): Specifies the log level (e.g., "DEBUG", "INFO", "ERROR"). The default level is "DEBUG".
190+
- `logger_format` (str, optional): Defines the format of the log messages. If not specified, a default format or the format specified in the configuration is used.
191+
192+
- **Returns**:
193+
- `Logger`: A configured logger instance tailored for logging messages as per the specified settings.
194+
195+
- **Behavior and Error Handling**:
196+
- The method uses the `key` to fetch specific configuration settings related to logging, such as file paths and log levels.
197+
- If a logger with the given `logger_name` already exists, it returns that instance to ensure consistent logging throughout the application.
198+
- Log messages are written to a file as specified in the configuration, and if `logger_format` is provided, it customizes the appearance of log messages.
199+
- A `ValueError` is raised if the logger configuration for the specified `key` is not found.
200+
201+
- **Examples**:
202+
- Illustrating the creation of a custom logger:
203+
204+
```python
205+
# Creating a logger with a specific level and format
206+
logger = config_manager.get_logger("logger_config", "my_logger", "INFO", "%(asctime)s - %(levelname)s - %(message)s")
207+
logger.info("This is an info message.")
208+
```
209+
210+
- **Notes**:
211+
- The method's flexibility in specifying logger configuration makes it ideal for applications that require different logging behaviors in various components or modules.
212+
- The addition of `logger_format` provides greater control over log message formatting, enhancing readability and debugging.
85213

86214
# Usage Example
87215

88-
Here's a simple example of how to use the `ConfigurationManager` class to manage configuration data in your Python application:
216+
Here's a comprehensive example of how to use the `ConfigurationManager` class to manage configuration data within a Python application:
89217

90218
```python
219+
from jsonpycraft.core.errors import JSONEncodeErrorHandler, JSONDecodeErrorHandler
91220
from jsonpycraft.manager.configuration import ConfigurationManager
92221

93222
# Initialize the ConfigurationManager with a file path
94223
config_file_path = "config.json"
95224
config_manager = ConfigurationManager(config_file_path)
96225

97226
# Load configuration data from the file
98-
if not config_manager.load():
99-
# Handle the case where loading failed
100-
print("Failed to load configuration data.")
101-
else:
102-
# Get a configuration value
103-
app_name = config_manager.get_value("app.name", "MyApp")
104-
print(f"Application Name: {app_name}")
105-
106-
# Set a new configuration value
107-
config_manager.set_value("app.version", "1.0")
108-
109-
# Save the updated configuration data
110-
if config_manager.save():
111-
print("Configuration data saved successfully.")
112-
113-
# Create a backup of the configuration file
114-
if config_manager.backup():
115-
print("Backup created successfully.")
227+
try:
228+
config_manager.load()
229+
print("Configuration data loaded successfully.")
230+
except JSONDecodeErrorHandler:
231+
raise JSONDecodeErrorHandler("Failed to load configuration data.")
232+
233+
# Get a configuration value
234+
app_name = config_manager.get_value("app.name", "MyApp")
235+
print(f"Application Name: {app_name}")
236+
237+
# Set a new configuration value
238+
config_manager.set_value("app.version", "1.0")
239+
print("Configuration value 'app.version' set to '1.0'")
240+
241+
# Evaluate a path for log files
242+
log_path = config_manager.evaluate_path("logging.directory", default_path="/var/logs/myapp", default_type="dir")
243+
print(f"Log Path: {log_path}")
244+
245+
# Get an environment variable or fallback to a default
246+
db_url = config_manager.get_environment("DATABASE_URL", key="database.url")
247+
print(f"Database URL: {db_url}")
248+
249+
# Create and configure a logger
250+
logger = config_manager.get_logger("logger_config", "my_logger", "INFO")
251+
logger.info("Configuration manager initialized successfully.")
252+
253+
# Save the updated configuration data
254+
try:
255+
config_manager.save()
256+
print("Configuration data saved successfully.")
257+
except JSONEncodeErrorHandler:
258+
raise JSONEncodeErrorHandler("Failed to save configuration data.")
259+
260+
# Create a backup of the configuration file
261+
try:
262+
config_manager.backup()
263+
print("Backup created successfully.")
264+
except JSONEncodeErrorHandler:
265+
raise JSONEncodeErrorHandler("Failed to backup configuration data.")
116266
```
117267

118-
In this example, we first initialize the `ConfigurationManager` with the path to the configuration file (`config.json`). We then load the configuration data, retrieve and print a configuration value, set a new configuration value, save the updated data, and create a backup of the configuration file.
268+
This example demonstrates several key operations:
269+
- Loading configuration data from a file.
270+
- Retrieving and setting configuration values.
271+
- Evaluating paths for specific configurations, such as log directories.
272+
- Integrating environment variables into the configuration.
273+
- Setting up and using a custom logger.
274+
- Saving updates to the configuration and creating backups.
119275

120-
This demonstrates the basic usage of the `ConfigurationManager` class for managing configuration settings in your Python application.
276+
This example provides a practical illustration of how `ConfigurationManager` can be utilized in real-world scenarios, covering a wide range of its capabilities. This holistic approach helps with understanding how different methods and features can work together effectively.

0 commit comments

Comments
 (0)