156 lines
5.6 KiB
Python
156 lines
5.6 KiB
Python
import os
|
|
import json
|
|
|
|
class Config:
|
|
"""
|
|
Manages application configuration stored in a JSON file.
|
|
|
|
Provides attribute-style access to configuration values.
|
|
"""
|
|
def __init__(self, file_path='/data/config.json'):
|
|
"""
|
|
Initializes the Config manager.
|
|
|
|
Loads configuration from the JSON file. Creates the file with an
|
|
empty JSON object if it doesn't exist.
|
|
|
|
Args:
|
|
file_path (str): The path to the JSON configuration file.
|
|
"""
|
|
self.file_path = file_path
|
|
self._config_data = {} # Internal dictionary to hold config data
|
|
self._load_config()
|
|
|
|
def _load_config(self):
|
|
"""Loads configuration key-value pairs from the JSON file."""
|
|
# Check if the file exists. If not, create it with an empty JSON object.
|
|
if not os.path.exists(self.file_path):
|
|
self._save_config() # Create the file with empty data
|
|
|
|
try:
|
|
with open(self.file_path, 'r') as f:
|
|
# Load data from the file. Handle empty file case.
|
|
content = f.read()
|
|
if content:
|
|
self._config_data = json.loads(content)
|
|
else:
|
|
self._config_data = {} # Initialize as empty if file is empty
|
|
except (FileNotFoundError, json.JSONDecodeError) as e:
|
|
print(f"Error loading config file {self.file_path}: {e}")
|
|
# If there's an error loading, initialize with empty data
|
|
self._config_data = {}
|
|
# Optionally, you might want to back up the problematic file
|
|
# or log the error more severely in a real application.
|
|
|
|
def _save_config(self):
|
|
"""Saves the current configuration data to the JSON file."""
|
|
try:
|
|
with open(self.file_path, 'w') as f:
|
|
json.dump(self._config_data, f, indent=4) # Use indent for readability
|
|
except IOError as e:
|
|
print(f"Error saving config file {self.file_path}: {e}")
|
|
except TypeError as e:
|
|
print(f"Error serializing config data to JSON: {e}. Ensure all values are JSON serializable.")
|
|
|
|
def get(self, key, default=None):
|
|
"""
|
|
Retrieves a configuration value by key.
|
|
|
|
Args:
|
|
key (str): The configuration key.
|
|
default: The value to return if the key is not found.
|
|
|
|
Returns:
|
|
The configuration value or the default value if not found.
|
|
"""
|
|
return self._config_data.get(key, default)
|
|
|
|
def set(self, key, value):
|
|
"""
|
|
Sets or updates a configuration value in memory and saves to the file.
|
|
|
|
Args:
|
|
key (str): The configuration key.
|
|
value: The configuration value. Must be JSON serializable.
|
|
"""
|
|
self._config_data[key] = value
|
|
self._save_config()
|
|
|
|
def delete(self, key):
|
|
"""
|
|
Deletes a configuration key-value pair from memory and saves to the file.
|
|
|
|
Args:
|
|
key (str): The configuration key to delete.
|
|
"""
|
|
if key in self._config_data:
|
|
del self._config_data[key]
|
|
self._save_config()
|
|
else:
|
|
print(f"Warning: Key '{key}' not found in config.")
|
|
|
|
def __str__(self):
|
|
"""
|
|
Returns a neat, formatted string representation of all configuration
|
|
key-value pairs. This method is automatically called when the object
|
|
is converted to a string (e.g., by print()).
|
|
"""
|
|
if not self._config_data:
|
|
return "\n--- Configuration is Empty ---\n"
|
|
|
|
output = ["\n--- Current Configuration ---"]
|
|
max_key_len = max(len(key) for key in self._config_data)
|
|
for key, value in self._config_data.items():
|
|
output.append(f"{key.ljust(max_key_len)} : {json.dumps(value, indent=None)}")
|
|
output.append("-----------------------------\n")
|
|
return "\n".join(output)
|
|
|
|
def __getattr__(self, name):
|
|
"""
|
|
Allows accessing configuration values using attribute notation (e.g., config.my_key).
|
|
|
|
Args:
|
|
name (str): The attribute name (configuration key).
|
|
|
|
Returns:
|
|
The configuration value associated with the key.
|
|
|
|
Raises:
|
|
AttributeError: If the key is not found in the configuration.
|
|
"""
|
|
if name in self._config_data:
|
|
return self._config_data[name]
|
|
# Fallback for standard attributes if not found in config data
|
|
try:
|
|
return self.__getattribute__(name)
|
|
except AttributeError:
|
|
raise AttributeError(f"'Config' object has no attribute '{name}' and key '{name}' not found in config.")
|
|
|
|
def __setattr__(self, name, value):
|
|
"""
|
|
Allows setting configuration values using attribute notation (e.g., config.my_key = value).
|
|
|
|
Args:
|
|
name (str): The attribute name (configuration key).
|
|
value: The value to set. Must be JSON serializable.
|
|
"""
|
|
# Handle setting internal attributes like file_path or _config_data
|
|
if name in ('file_path', '_config_data'):
|
|
super().__setattr__(name, value)
|
|
else:
|
|
# Treat other attribute assignments as setting config values
|
|
self.set(name, value)
|
|
|
|
def __delattr__(self, name):
|
|
"""
|
|
Allows deleting configuration values using attribute notation (e.g., del config.my_key).
|
|
|
|
Args:
|
|
name (str): The attribute name (configuration key) to delete.
|
|
"""
|
|
if name in self._config_data:
|
|
self.delete(name)
|
|
else:
|
|
# Fallback for standard attributes
|
|
super().__delattr__(name)
|