mirror of
https://github.com/ParisNeo/lollms.git
synced 2025-03-12 07:23:53 +00:00
589 lines
21 KiB
Python
589 lines
21 KiB
Python
from pathlib import Path
|
|
from ascii_colors import ASCIIColors
|
|
|
|
|
|
import yaml
|
|
from enum import Enum
|
|
|
|
class InstallOption(Enum):
|
|
"""Enumeration for installation options."""
|
|
|
|
NEVER_INSTALL = 1
|
|
"""Do not install under any circumstances."""
|
|
|
|
INSTALL_IF_NECESSARY = 2
|
|
"""Install if necessary, but do not force installation."""
|
|
|
|
FORCE_INSTALL = 3
|
|
"""Force installation, regardless of current state."""
|
|
|
|
|
|
class ConfigTemplate:
|
|
"""
|
|
A class representing a configuration template.
|
|
|
|
The `ConfigTemplate` class provides functionality to define and manage configuration entries in the form of a template.
|
|
|
|
Attributes:
|
|
template (list): A list of dictionaries representing configuration entries.
|
|
|
|
Methods:
|
|
add_entry(entry_name, entry_value, entry_type, entry_min=None, entry_max=None):
|
|
Adds a new entry to the configuration template.
|
|
__getitem__(key):
|
|
Retrieves the configuration entry with the specified key.
|
|
__getattr__(key):
|
|
Retrieves the configuration entry with the specified key as an attribute.
|
|
__setattr__(key, value):
|
|
Sets the value of the configuration entry with the specified key.
|
|
__setitem__(key, value):
|
|
Sets the value of the configuration entry with the specified key.
|
|
__contains__(item):
|
|
Checks if a configuration entry with the specified name exists in the template.
|
|
"""
|
|
|
|
def __init__(self, template: list = None) -> None:
|
|
"""
|
|
Initializes a new instance of the `ConfigTemplate` class.
|
|
|
|
Args:
|
|
template (list, optional): A list of dictionaries representing configuration entries. Defaults to an empty list.
|
|
|
|
Raises:
|
|
ValueError: If the `template` parameter is not a list of dictionaries or if any entry is missing required fields.
|
|
"""
|
|
if template is None:
|
|
template = []
|
|
elif not isinstance(template, list):
|
|
raise ValueError("Template must be a list of dictionaries.")
|
|
else:
|
|
for entry in template:
|
|
if not isinstance(entry, dict):
|
|
raise ValueError("Each entry in the template must be a dictionary.")
|
|
required_fields = ["name", "value", "type"]
|
|
missing_fields = [field for field in required_fields if field not in entry]
|
|
if missing_fields:
|
|
raise ValueError(f"Missing fields {', '.join(missing_fields)} in template entry.")
|
|
self.template = template
|
|
|
|
def add_entry(self, entry_name, entry_value, entry_type, entry_min=None, entry_max=None, entry_help=""):
|
|
"""
|
|
Adds a new entry to the configuration template.
|
|
|
|
Args:
|
|
entry_name (str): The name of the configuration entry.
|
|
entry_value (Any): The value of the configuration entry.
|
|
entry_type (str): The type of the configuration entry.
|
|
entry_min (Any, optional): The minimum allowed value for the configuration entry. Defaults to None.
|
|
entry_max (Any, optional): The maximum allowed value for the configuration entry. Defaults to None.
|
|
entry_help (str, optional): the help string to describe the entry
|
|
"""
|
|
self.template.append({
|
|
"name": entry_name,
|
|
"value": entry_value,
|
|
"type": entry_type,
|
|
"min": entry_min,
|
|
"max": entry_max,
|
|
"help": entry_help
|
|
})
|
|
|
|
def __getitem__(self, key):
|
|
"""
|
|
Retrieves the configuration entry with the specified key.
|
|
|
|
Args:
|
|
key (str): The name of the configuration entry.
|
|
|
|
Returns:
|
|
dict: The configuration entry with the specified key, or None if not found.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
"""
|
|
if self.template is None:
|
|
raise ValueError("No configuration loaded.")
|
|
for entry in self.template:
|
|
if entry["name"] == key:
|
|
return entry
|
|
return None
|
|
|
|
def __getattr__(self, key):
|
|
"""
|
|
Retrieves the configuration entry with the specified key as an attribute.
|
|
|
|
Args:
|
|
key (str): The name of the configuration entry.
|
|
|
|
Returns:
|
|
dict: The configuration entry with the specified key, or None if not found.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
"""
|
|
if key == "exceptional_keys":
|
|
return super().__getattribute__(key)
|
|
if key in ["template"] or key.startswith("__"):
|
|
return super().__getattribute__(key)
|
|
else:
|
|
if self.template is None:
|
|
raise ValueError("No configuration loaded.")
|
|
for entry in self.template:
|
|
if entry["name"] == key:
|
|
return entry
|
|
return None
|
|
|
|
def __setattr__(self, key, value):
|
|
"""
|
|
Sets the value of the configuration entry with the specified key.
|
|
|
|
Args:
|
|
key (str): The name of the configuration entry.
|
|
value (Any): The new value for the configuration entry.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded or if the specified key is not found.
|
|
"""
|
|
if key == "exceptional_keys":
|
|
return super().__setattr__(key, value)
|
|
if key in ["template"] or key.startswith("__"):
|
|
super().__setattr__(key, value)
|
|
else:
|
|
if self.template is None:
|
|
raise ValueError("No configuration loaded.")
|
|
for entry in self.template:
|
|
if entry["name"] == key:
|
|
entry["value"] = value
|
|
return
|
|
raise ValueError(f"Configuration entry '{key}' not found.")
|
|
|
|
def __setitem__(self, key, value):
|
|
"""
|
|
Sets the value of the configuration entry with the specified key.
|
|
|
|
Args:
|
|
key (str): The name of the configuration entry.
|
|
value (Any): The new value for the configuration entry.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded or if the specified key is not found.
|
|
"""
|
|
if self.template is None:
|
|
raise ValueError("No configuration loaded.")
|
|
for entry in self.template:
|
|
if entry["name"] == key:
|
|
entry["value"] = value
|
|
return
|
|
raise ValueError(f"Configuration entry '{key}' not found.")
|
|
|
|
def __contains__(self, item):
|
|
"""
|
|
Checks if a configuration entry with the specified name exists in the template.
|
|
|
|
Args:
|
|
item (str): The name of the configuration entry.
|
|
|
|
Returns:
|
|
bool: True if the configuration entry exists, False otherwise.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
"""
|
|
if self.template is None:
|
|
raise ValueError("No configuration loaded.")
|
|
for entry in self.template:
|
|
if entry["name"] == item:
|
|
return True
|
|
return False
|
|
|
|
|
|
|
|
class BaseConfig:
|
|
"""
|
|
A base class for managing configuration data.
|
|
|
|
The `BaseConfig` class provides basic functionality to load, save, and access configuration data.
|
|
|
|
Attributes:
|
|
exceptional_keys (list): A list of exceptional keys that can be accessed directly as attributes.
|
|
config (dict): The configuration data stored as a dictionary.
|
|
|
|
Methods:
|
|
to_dict():
|
|
Returns the configuration data as a dictionary.
|
|
__getitem__(key):
|
|
Retrieves the configuration value associated with the specified key.
|
|
__getattr__(key):
|
|
Retrieves the configuration value associated with the specified key as an attribute.
|
|
__setattr__(key, value):
|
|
Sets the value of the configuration key.
|
|
__setitem__(key, value):
|
|
Sets the value of the configuration key.
|
|
__contains__(item):
|
|
Checks if the configuration contains the specified key.
|
|
load_config(file_path):
|
|
Loads the configuration from a YAML file.
|
|
save_config(file_path):
|
|
Saves the configuration to a YAML file.
|
|
"""
|
|
|
|
def __init__(self, exceptional_keys: list = [], config: dict = None, file_path:Path|str=None):
|
|
"""
|
|
Initializes a new instance of the `BaseConfig` class.
|
|
|
|
Args:
|
|
exceptional_keys (list, optional): A list of exceptional keys that can be accessed directly as attributes.
|
|
Defaults to an empty list.
|
|
config (dict, optional): The configuration data stored as a dictionary. Defaults to None.
|
|
"""
|
|
self.exceptional_keys = exceptional_keys
|
|
self.config = config
|
|
self.file_path = file_path
|
|
|
|
@staticmethod
|
|
def from_template(template:ConfigTemplate, exceptional_keys: list = [], file_path: Path | str = None):
|
|
config = {}
|
|
for entry in template.template:
|
|
config[entry["name"]]=entry["value"]
|
|
|
|
return BaseConfig(exceptional_keys, config, file_path)
|
|
|
|
def to_dict(self):
|
|
"""
|
|
Returns the configuration data as a dictionary.
|
|
|
|
Returns:
|
|
dict: The configuration data as a dictionary.
|
|
"""
|
|
return self.config
|
|
|
|
def __getitem__(self, key):
|
|
"""
|
|
Retrieves the configuration value associated with the specified key.
|
|
|
|
Args:
|
|
key (Any): The key to retrieve the configuration value.
|
|
|
|
Returns:
|
|
Any: The configuration value associated with the key.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
KeyError: If the specified key is not found in the configuration.
|
|
"""
|
|
if self.config is None:
|
|
raise ValueError("No configuration loaded.")
|
|
return self.config[key]
|
|
|
|
def __getattr__(self, key):
|
|
"""
|
|
Retrieves the configuration value associated with the specified key as an attribute.
|
|
|
|
Args:
|
|
key (str): The key to retrieve the configuration value.
|
|
|
|
Returns:
|
|
Any: The configuration value associated with the key.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
AttributeError: If the specified key is not found in the configuration.
|
|
"""
|
|
if key == "exceptional_keys":
|
|
return super().__getattribute__(key)
|
|
if key in self.exceptional_keys + ["config","file_path"] or key.startswith("__"):
|
|
return super().__getattribute__(key)
|
|
else:
|
|
if self.config is None:
|
|
raise ValueError("No configuration loaded.")
|
|
return self.config[key]
|
|
|
|
def __setattr__(self, key, value):
|
|
"""
|
|
Sets the value of the configuration key.
|
|
|
|
Args:
|
|
key (str): The key of the configuration.
|
|
value (Any): The new value for the configuration key.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
"""
|
|
if key == "exceptional_keys":
|
|
return super().__setattr__(key, value)
|
|
if key in self.exceptional_keys + ["config","file_path"] or key.startswith("__"):
|
|
super().__setattr__(key, value)
|
|
else:
|
|
if self.config is None:
|
|
raise ValueError("No configuration loaded.")
|
|
self.config[key] = value
|
|
|
|
def __setitem__(self, key, value):
|
|
"""
|
|
Sets the value of the configuration key.
|
|
|
|
Args:
|
|
key (str): The key of the configuration.
|
|
value (Any): The new value for the configuration key.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
"""
|
|
if self.config is None:
|
|
raise ValueError("No configuration loaded.")
|
|
self.config[key] = value
|
|
|
|
def __contains__(self, item):
|
|
"""
|
|
Checks if the configuration contains the specified key.
|
|
|
|
Args:
|
|
item (str): The key to check.
|
|
|
|
Returns:
|
|
bool: True if the key is present in the configuration, False otherwise.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
"""
|
|
if self.config is None:
|
|
raise ValueError("No configuration loaded.")
|
|
return item in self.config
|
|
|
|
def load_config(self, file_path: Path | str = None):
|
|
"""
|
|
Loads the configuration from a YAML file.
|
|
|
|
Args:
|
|
file_path (str or Path, optional): The path to the YAML file. If not provided, uses the previously set file path.
|
|
|
|
Raises:
|
|
ValueError: If no configuration file path is specified.
|
|
FileNotFoundError: If the specified file path does not exist.
|
|
yaml.YAMLError: If there is an error parsing the YAML file.
|
|
"""
|
|
if file_path is None:
|
|
if self.file_path is None:
|
|
raise ValueError("No configuration file path specified.")
|
|
file_path = self.file_path
|
|
|
|
file_path = Path(file_path)
|
|
if not file_path.exists():
|
|
raise FileNotFoundError(f"Configuration file not found: {file_path}")
|
|
|
|
with open(file_path, 'r', encoding='utf-8') as stream:
|
|
self.config = yaml.safe_load(stream)
|
|
|
|
def save_config(self, file_path=None):
|
|
"""
|
|
Saves the configuration to a YAML file.
|
|
|
|
Args:
|
|
file_path (str or Path, optional): The path to the YAML file. If not provided, uses the previously set file path.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
ValueError: If no configuration file path is specified.
|
|
PermissionError: If the user does not have permission to write to the specified file path.
|
|
yaml.YAMLError: If there is an error serializing the configuration to YAML.
|
|
"""
|
|
if file_path is None:
|
|
if self.file_path is None:
|
|
raise ValueError("No configuration file path specified.")
|
|
file_path = self.file_path
|
|
|
|
if self.config is None:
|
|
raise ValueError("No configuration loaded.")
|
|
|
|
file_path = Path(file_path)
|
|
with open(file_path, "w") as f:
|
|
yaml.dump(self.config, f)
|
|
|
|
|
|
|
|
|
|
|
|
class TypedConfig:
|
|
"""
|
|
This type of configuration contains a template of descriptions for the fields of the configuration.
|
|
Field types: int, float, str.
|
|
"""
|
|
|
|
def __init__(self, config_template: ConfigTemplate, config: BaseConfig):
|
|
"""
|
|
Initializes a new instance of the `TypedConfig` class.
|
|
|
|
Args:
|
|
config_template (ConfigTemplate): The template of descriptions for the fields of the configuration.
|
|
config (BaseConfig): The base configuration object containing the configuration values.
|
|
"""
|
|
self.config = config
|
|
self.config_template = config_template
|
|
|
|
# Fill the template values from the config values
|
|
self.sync()
|
|
|
|
def addConfigs(self, cfg_template:list):
|
|
self.config_template.template += cfg_template
|
|
self.sync()
|
|
|
|
def update_template(self, new_template):
|
|
self.config_template.template = new_template
|
|
self.config = BaseConfig.from_template(self.config_template,self.config.exceptional_keys, self.config.file_path)
|
|
|
|
def get(self, key, default_value=None):
|
|
if self.config is None:
|
|
raise ValueError("No configuration loaded.")
|
|
if key in self.config:
|
|
return self.config[key]
|
|
else:
|
|
return default_value
|
|
|
|
|
|
def __getattr__(self, key):
|
|
"""
|
|
Retrieves the configuration entry with the specified key as an attribute.
|
|
|
|
Args:
|
|
key (str): The name of the configuration entry.
|
|
|
|
Returns:
|
|
dict: The configuration entry with the specified key, or None if not found.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
"""
|
|
if key in ["config","config_template"] or key.startswith("__"):
|
|
return super().__getattribute__(key)
|
|
else:
|
|
if self.config is None:
|
|
raise ValueError("No configuration loaded.")
|
|
return self.config[key]
|
|
|
|
def __setattr__(self, key, value):
|
|
"""
|
|
Retrieves the configuration entry with the specified key as an attribute.
|
|
|
|
Args:
|
|
key (str): The name of the configuration entry.
|
|
|
|
Returns:
|
|
dict: The configuration entry with the specified key, or None if not found.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
"""
|
|
if key in ["config","config_template"] or key.startswith("__"):
|
|
super().__setattr__(key, value)
|
|
else:
|
|
if self.config is None:
|
|
raise ValueError("No configuration loaded.")
|
|
self.config[key] = value
|
|
self.sync()
|
|
|
|
|
|
def __getitem__(self, key):
|
|
"""
|
|
Retrieves the configuration entry with the specified key as an attribute.
|
|
|
|
Args:
|
|
key (str): The name of the configuration entry.
|
|
|
|
Returns:
|
|
dict: The configuration entry with the specified key, or None if not found.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
"""
|
|
if self.config is None:
|
|
raise ValueError("No configuration loaded.")
|
|
return self.config[key]
|
|
|
|
def __setitem__(self, key, value):
|
|
"""
|
|
Retrieves the configuration entry with the specified key as an attribute.
|
|
|
|
Args:
|
|
key (str): The name of the configuration entry.
|
|
|
|
Returns:
|
|
dict: The configuration entry with the specified key, or None if not found.
|
|
|
|
Raises:
|
|
ValueError: If no configuration is loaded.
|
|
"""
|
|
if self.config is None:
|
|
raise ValueError("No configuration loaded.")
|
|
self.config[key] = value
|
|
self.sync()
|
|
|
|
def sync(self):
|
|
"""
|
|
Fills the template values from the config values.
|
|
"""
|
|
if self.config_template is None:
|
|
raise ValueError("No configuration template loaded.")
|
|
if self.config is None:
|
|
raise ValueError("No configuration loaded.")
|
|
|
|
for entry in self.config_template.template:
|
|
entry_name = entry["name"]
|
|
if entry_name in self.config:
|
|
entry_value = self.config[entry_name]
|
|
entry_type = entry["type"]
|
|
|
|
# Validate and convert the entry value based on its type
|
|
if entry_type == "int":
|
|
entry_value = int(entry_value)
|
|
elif entry_type == "float":
|
|
entry_value = float(entry_value)
|
|
elif entry_type == "str" or entry_type == "text" or entry_type == "string" or entry_type == "btn":
|
|
entry_value = str(entry_value)
|
|
elif entry_type == "bool":
|
|
entry_value = bool(entry_value)
|
|
elif entry_type == "list":
|
|
entry_value = list(entry_value)
|
|
elif entry_type == "dict":
|
|
entry_value = eval(entry_value)
|
|
else:
|
|
raise ValueError(f"Invalid field type '{entry_type}' for entry '{entry_name}'.")
|
|
|
|
# Skip checking min and max if the entry type is not numeric
|
|
if entry_type == "int" or entry_type == "float":
|
|
entry_min = entry.get("min")
|
|
entry_max = entry.get("max")
|
|
|
|
# Check if the value is within the allowed range (if specified)
|
|
if entry_min is not None and entry_max is not None:
|
|
if entry_value < entry_min:
|
|
entry_value = entry_min
|
|
elif entry_value > entry_max:
|
|
entry_value = entry_max
|
|
elif entry_min is not None:
|
|
if entry_value < entry_min:
|
|
entry_value = entry_min
|
|
elif entry_max is not None:
|
|
if entry_value > entry_max:
|
|
entry_value = entry_max
|
|
|
|
# Update the template entry with the converted value
|
|
entry["value"] = entry_value
|
|
else:
|
|
self.config[entry_name] = entry["value"]
|
|
|
|
def set_config(self, config: BaseConfig):
|
|
"""
|
|
Sets the configuration and updates the values of the template.
|
|
|
|
Args:
|
|
config (BaseConfig): The base configuration object containing the configuration values.
|
|
"""
|
|
self.config = config
|
|
self.sync()
|
|
|
|
def save(self, file_path:str|Path|None=None):
|
|
self.config.save_config(file_path=file_path)
|
|
def to_dict(self, use_template=False):
|
|
if not use_template:
|
|
return self.config
|
|
else:
|
|
return self.config_template |