Config master.py: Difference between revisions

From Chrysalis Archive
Jump to navigation Jump to search
mNo edit summary
mNo edit summary
Line 1: Line 1:
{{menuPromptEngineerCode}}
{{menuPromptEngineerCode}}
<pre style="width:880px; padding:10px; color:lime; background-color:#302; margin:0 auto;">
<pre style="width:880px; padding:10px; color:lime; background-color:#302; margin:0 auto;">
"""
"""
ConfigMaster Class
ConfigMaster Class v.2024.05.15
v.2024.05.15


Author: Claude (Opus 3 LLM @claude.ai)
Author: Claude (Opus 3 LLM @claude.ai)
Line 11: Line 11:
This module provides a class for handling configuration files in a simple and intuitive way.
This module provides a class for handling configuration files in a simple and intuitive way.
The ConfigMaster class allows reading, writing, and manipulating configuration data
The ConfigMaster class allows reading, writing, and manipulating configuration data
stored in a format similar to INI files. It supports fail-graceful behavior when the
stored in a format similar to INI files. It supports a variety of data types, including
configuration file doesn't exist during the initial load and saves defaulted values
integers, floats, booleans, lists, tuples, and datetimes, with convenient methods for
provided by the calling code.
retrieving values of specific types.


Features:
Features:
- Load and save configuration data from/to files
- Load and save configuration data from/to files
- Get, set, update, and remove values in sections
- Get, set, update, and remove values in sections
- Support for different data types (int, float, boolean, list, tuple, datetime)
- Case-insensitive section and key names
- Case-insensitive section and key names
- Support for default values
- Support for default values and fallback values
- Handling of comment lines
- Handling of comment lines
- Dictionary-like access to sections and key-value pairs
- Dictionary-like access to sections and key-value pairs
Line 25: Line 26:
- Merging configuration data from multiple sources
- Merging configuration data from multiple sources
- Error handling and validation for section and key names
- Error handling and validation for section and key names
- Fail-graceful behavior when the configuration file doesn't exist during initial load
- Persistence of defaulted values provided by the calling code


Usage:
Usage:
Line 41: Line 40:
   config.save()
   config.save()


5. Iterate over sections and key-value pairs:
5. Retrieve values of specific data types:
   for section in config.sections():
   int_value = config.getint('Section1', 'IntKey', fallback=0)
      for key, value in config.items(section):
  float_value = config.getfloat('Section1', 'FloatKey', fallback=0.0)
          print(f"{key}: {value}")
  bool_value = config.getboolean('Section1', 'BoolKey', fallback=False)
  list_value = config.getlist('Section1', 'ListKey', fallback=[])
  tuple_value = config.gettuple('Section1', 'TupleKey', fallback=())
  datetime_value = config.getdatetime('Section1', 'DateTimeKey', fallback=None)


Example configuration file format:
Example configuration file format:
Line 61: Line 63:


import os
import os
from datetime import datetime


class ConfigMaster:
class ConfigMaster:
     def __init__(self, file_path):
     def __init__(self, file_path):
         self.file_path = file_path
         self.file_path = file_path
         self.config = {} # Dictionary to store the configuration data
         self.config = {}
         self.comments = [] # List to store comment lines
         self.comments = []
         self.load() # Load the configuration data from the file
         self.load()


     def load(self):
     def load(self):
        """
        Load the configuration data from the file.
        If the file doesn't exist, create an empty configuration.
        """
         if not os.path.isfile(self.file_path):
         if not os.path.isfile(self.file_path):
            # File doesn't exist, create an empty configuration
             self.config = {'default': {}}
             self.config = {}
         else:
         else:
             # File exists, load the configuration data
             current_section = 'default'
             current_section = None
             self.config[current_section] = {}
             with open(self.file_path, 'r') as config_file:
             with open(self.file_path, 'r') as config_file:
                 for line in config_file:
                 for line in config_file:
Line 91: Line 89:
                         key, value = line.split(':', 1)
                         key, value = line.split(':', 1)
                         self.config[current_section][key.strip().lower()] = value.strip()
                         self.config[current_section][key.strip().lower()] = value.strip()


     def save(self):
     def save(self):
        """
        Save the configuration data to the file.
        """
         with open(self.file_path, 'w') as config_file:
         with open(self.file_path, 'w') as config_file:
             config_file.writelines(line + '\n' for line in self.comments)
             config_file.writelines(line + '\n' for line in self.comments)
Line 106: Line 100:
                 config_file.write("\n")
                 config_file.write("\n")


     def get(self, section, key, default=None):
     def get(self, section, key, fallback=None):
        """
        Get the value of a specific key in a section.
        If the key doesn't exist, return the default value and update the configuration.
        """
         section = section.lower()
         section = section.lower()
         key = key.lower()
         key = key.lower()
Line 116: Line 106:
             return self.config[section][key]
             return self.config[section][key]
         else:
         else:
             # Key doesn't exist, update the configuration with the default value
             return fallback
             self.set(section, key, default)
 
             return default
    def getint(self, section, key, fallback=None):
        value = self.get(section, key, fallback=None)
        if value is None:
            return fallback
        try:
            return int(value)
        except ValueError:
            return fallback
 
    def getfloat(self, section, key, fallback=None):
        value = self.get(section, key, fallback=None)
        if value is None:
            return fallback
        try:
            return float(value)
        except ValueError:
            return fallback
 
    def getboolean(self, section, key, fallback=None):
        value = self.get(section, key, fallback=None)
        if value is None:
            return fallback
        value = value.lower()
        if value in ['true', 'yes', '1']:
            return True
        elif value in ['false', 'no', '0']:
            return False
        else:
            return fallback
 
    def getlist(self, section, key, fallback=None, delimiter=','):
        value = self.get(section, key, fallback=None)
        if value is None:
            return fallback
        return [item.strip() for item in value.split(delimiter)]
 
    def gettuple(self, section, key, fallback=None, delimiter=','):
        value = self.get(section, key, fallback=None)
        if value is None:
             return fallback
        return tuple(item.strip() for item in value.split(delimiter))
 
    def getdatetime(self, section, key, fallback=None, format='%Y-%m-%d %H:%M:%S'):
        value = self.get(section, key, fallback=None)
        if value is None:
            return fallback
        try:
            return datetime.strptime(value, format)
        except ValueError:
             return fallback


     def set(self, section, key, value):
     def set(self, section, key, value):
        """
        Set the value of a specific key in a section.
        If the section doesn't exist, create it.
        """
         section = section.lower()
         section = section.lower()
         key = key.lower()
         key = key.lower()
Line 133: Line 168:


     def update(self, section, data):
     def update(self, section, data):
        """
        Update the configuration data in a specific section with the provided data.
        The data should be a dictionary containing key-value pairs.
        """
         section = section.lower()
         section = section.lower()
         self._validate_section(section)
         self._validate_section(section)
Line 142: Line 173:


     def remove(self, section, key):
     def remove(self, section, key):
        """
        Remove a specific key from a section.
        """
         section = section.lower()
         section = section.lower()
         key = key.lower()
         key = key.lower()
Line 151: Line 179:


     def add_section(self, section):
     def add_section(self, section):
        """
        Add a new section to the configuration.
        If the section already exists, no action is taken.
        """
         section = section.lower()
         section = section.lower()
         if section not in self.config:
         if section not in self.config:
             self.config[section] = {}
             self.config[section] = {}
           
 
     def remove_section(self, section):
     def remove_section(self, section):
        """
        Remove a specific section from the configuration.
        """
         section = section.lower()
         section = section.lower()
         if section in self.config:
         if section in self.config:
Line 168: Line 189:


     def has_key(self, section, key):
     def has_key(self, section, key):
        """
        Check if a specific key exists in a section.
        """
         section = section.lower()
         section = section.lower()
         key = key.lower()
         key = key.lower()
Line 176: Line 194:


     def has_section(self, section):
     def has_section(self, section):
        """
        Check if a specific section exists in the configuration.
        """
         return section.lower() in self.config
         return section.lower() in self.config


     def sections(self):
     def sections(self):
        """
        Get a list of all section names.
        """
         return list(self.config.keys())
         return list(self.config.keys())


     def items(self, section):
     def items(self, section):
        """
        Get a list of key-value pairs in a specific section.
        """
         section = section.lower()
         section = section.lower()
         return list(self.config.get(section, {}).items())
         return list(self.config.get(section, {}).items())


     def merge(self, other_config):
     def merge(self, other_config):
        """
        Merge the configuration data from another ConfigMaster instance or a dictionary.
        The other_config parameter can be either a ConfigMaster instance or a dictionary
        containing section-key-value mappings.
        """
         if isinstance(other_config, ConfigMaster):
         if isinstance(other_config, ConfigMaster):
             other_config = other_config.config
             other_config = other_config.config
Line 206: Line 210:


     def _validate_section_key(self, section, key):
     def _validate_section_key(self, section, key):
        """
        Validate the section and key names.
        Raise an error if the names are invalid.
        """
         if not section or not key:
         if not section or not key:
             raise ValueError("Section and key cannot be empty")
             raise ValueError("Section and key cannot be empty")
Line 216: Line 216:


     def _validate_section(self, section):
     def _validate_section(self, section):
        """
        Validate the section name.
        Raise an error if the name is invalid.
        """
         if not section:
         if not section:
             raise ValueError("Section cannot be empty")
             raise ValueError("Section cannot be empty")


     def __getitem__(self, section):
     def __getitem__(self, section):
        """
        Get the configuration dictionary of a specific section.
        """
         return self.config[section.lower()]
         return self.config[section.lower()]


     def __setitem__(self, section, section_config):
     def __setitem__(self, section, section_config):
        """
        Set the configuration dictionary of a specific section.
        """
         self.config[section.lower()] = {k.lower(): v for k, v in section_config.items()}
         self.config[section.lower()] = {k.lower(): v for k, v in section_config.items()}


     def __delitem__(self, section):
     def __delitem__(self, section):
        """
        Remove a specific section from the configuration.
        """
         del self.config[section.lower()]
         del self.config[section.lower()]


     def __contains__(self, section):
     def __contains__(self, section):
        """
        Check if a specific section exists in the configuration.
        """
         return section.lower() in self.config
         return section.lower() in self.config


if __name__ == "__main__":
    # Quick test of the ConfigMaster class
    config = ConfigMaster("test_config.ini")
    # Set values of different data types
    config.set("Section1", "IntKey", "10")
    config.set("Section1", "FloatKey", "3.14")
    config.set("Section1", "BoolKey", "true")
    config.set("Section1", "ListKey", "apple, banana, cherry")
    config.set("Section1", "TupleKey", "red, green, blue")
    config.set("Section1", "DateTimeKey", "2023-06-08 12:30:00")
    # Save the configuration to the file
    config.save()
    # Retrieve values of different data types
    int_value = config.getint("Section1", "IntKey", fallback=0)
    float_value = config.getfloat("Section1", "FloatKey", fallback=0.0)
    bool_value = config.getboolean("Section1", "BoolKey", fallback=False)
    list_value = config.getlist("Section1", "ListKey", fallback=[])
    tuple_value = config.gettuple("Section1", "TupleKey", fallback=())
    datetime_value = config.getdatetime("Section1", "DateTimeKey", fallback=None)
    # Print the retrieved values
    print("Int Value:", int_value)
    print("Float Value:", float_value)
    print("Bool Value:", bool_value)
    print("List Value:", list_value)
    print("Tuple Value:", tuple_value)
    print("DateTime Value:", datetime_value)


</pre>
</pre>

Revision as of 14:17, 15 May 2024


PromptEngineer Python Code Category
main.py ☀  prompt_engineer.py ☀  config_master.py ☀  README.md


"""
ConfigMaster Class v.2024.05.15

Author: Claude (Opus 3 LLM @claude.ai)
Prompt Engineer: XenoEngineer@groupKOS.com (Catcliffe Development)
Copyright (c) 2024, Catcliffe Development

This module provides a class for handling configuration files in a simple and intuitive way.
The ConfigMaster class allows reading, writing, and manipulating configuration data
stored in a format similar to INI files. It supports a variety of data types, including
integers, floats, booleans, lists, tuples, and datetimes, with convenient methods for
retrieving values of specific types.

Features:
- Load and save configuration data from/to files
- Get, set, update, and remove values in sections
- Support for different data types (int, float, boolean, list, tuple, datetime)
- Case-insensitive section and key names
- Support for default values and fallback values
- Handling of comment lines
- Dictionary-like access to sections and key-value pairs
- Iteration over sections and key-value pairs
- Merging configuration data from multiple sources
- Error handling and validation for section and key names

Usage:
1. Create an instance of the ConfigMaster class with the file path:
   config = ConfigMaster('config.txt')

2. Get values from sections with default values:
   value = config.get('Section1', 'Key1', 'DefaultValue')

3. Set values in sections:
   config.set('Section1', 'Key1', 'Value1')

4. Save the configuration to the file:
   config.save()

5. Retrieve values of specific data types:
   int_value = config.getint('Section1', 'IntKey', fallback=0)
   float_value = config.getfloat('Section1', 'FloatKey', fallback=0.0)
   bool_value = config.getboolean('Section1', 'BoolKey', fallback=False)
   list_value = config.getlist('Section1', 'ListKey', fallback=[])
   tuple_value = config.gettuple('Section1', 'TupleKey', fallback=())
   datetime_value = config.getdatetime('Section1', 'DateTimeKey', fallback=None)

Example configuration file format:
[Section1]
Key1: Value1
Key2: Value2

[Section2]
Key3: Value3

; This is a comment
# This is also a comment

Developed as a collaboration between Claude (LLM) and XenoEngineer (Catcliffe Development).
"""

import os
from datetime import datetime

class ConfigMaster:
    def __init__(self, file_path):
        self.file_path = file_path
        self.config = {}
        self.comments = []
        self.load()

    def load(self):
        if not os.path.isfile(self.file_path):
            self.config = {'default': {}}
        else:
            current_section = 'default'
            self.config[current_section] = {}
            with open(self.file_path, 'r') as config_file:
                for line in config_file:
                    line = line.strip()
                    if line.startswith(';') or line.startswith('#'):
                        self.comments.append(line)
                    elif line.startswith('[') and line.endswith(']'):
                        current_section = line[1:-1].lower()
                        self.config[current_section] = {}
                    elif ':' in line:
                        key, value = line.split(':', 1)
                        self.config[current_section][key.strip().lower()] = value.strip()

    def save(self):
        with open(self.file_path, 'w') as config_file:
            config_file.writelines(line + '\n' for line in self.comments)
            for section, section_config in self.config.items():
                if section != 'default':
                    config_file.write(f"[{section}]\n")
                for key, value in section_config.items():
                    config_file.write(f"{key}: {value}\n")
                config_file.write("\n")

    def get(self, section, key, fallback=None):
        section = section.lower()
        key = key.lower()
        if section in self.config and key in self.config[section]:
            return self.config[section][key]
        else:
            return fallback

    def getint(self, section, key, fallback=None):
        value = self.get(section, key, fallback=None)
        if value is None:
            return fallback
        try:
            return int(value)
        except ValueError:
            return fallback

    def getfloat(self, section, key, fallback=None):
        value = self.get(section, key, fallback=None)
        if value is None:
            return fallback
        try:
            return float(value)
        except ValueError:
            return fallback

    def getboolean(self, section, key, fallback=None):
        value = self.get(section, key, fallback=None)
        if value is None:
            return fallback
        value = value.lower()
        if value in ['true', 'yes', '1']:
            return True
        elif value in ['false', 'no', '0']:
            return False
        else:
            return fallback

    def getlist(self, section, key, fallback=None, delimiter=','):
        value = self.get(section, key, fallback=None)
        if value is None:
            return fallback
        return [item.strip() for item in value.split(delimiter)]

    def gettuple(self, section, key, fallback=None, delimiter=','):
        value = self.get(section, key, fallback=None)
        if value is None:
            return fallback
        return tuple(item.strip() for item in value.split(delimiter))

    def getdatetime(self, section, key, fallback=None, format='%Y-%m-%d %H:%M:%S'):
        value = self.get(section, key, fallback=None)
        if value is None:
            return fallback
        try:
            return datetime.strptime(value, format)
        except ValueError:
            return fallback

    def set(self, section, key, value):
        section = section.lower()
        key = key.lower()
        self._validate_section_key(section, key)
        if section not in self.config:
            self.config[section] = {}
        self.config[section][key] = value

    def update(self, section, data):
        section = section.lower()
        self._validate_section(section)
        self.config.setdefault(section, {}).update({k.lower(): v for k, v in data.items()})

    def remove(self, section, key):
        section = section.lower()
        key = key.lower()
        if section in self.config and key in self.config[section]:
            del self.config[section][key]

    def add_section(self, section):
        section = section.lower()
        if section not in self.config:
            self.config[section] = {}

    def remove_section(self, section):
        section = section.lower()
        if section in self.config:
            del self.config[section]

    def has_key(self, section, key):
        section = section.lower()
        key = key.lower()
        return section in self.config and key in self.config[section]

    def has_section(self, section):
        return section.lower() in self.config

    def sections(self):
        return list(self.config.keys())

    def items(self, section):
        section = section.lower()
        return list(self.config.get(section, {}).items())

    def merge(self, other_config):
        if isinstance(other_config, ConfigMaster):
            other_config = other_config.config
        for section, section_config in other_config.items():
            self.config.setdefault(section.lower(), {}).update({k.lower(): v for k, v in section_config.items()})

    def _validate_section_key(self, section, key):
        if not section or not key:
            raise ValueError("Section and key cannot be empty")
        if ':' in key:
            raise ValueError("Key cannot contain ':' character")

    def _validate_section(self, section):
        if not section:
            raise ValueError("Section cannot be empty")

    def __getitem__(self, section):
        return self.config[section.lower()]

    def __setitem__(self, section, section_config):
        self.config[section.lower()] = {k.lower(): v for k, v in section_config.items()}

    def __delitem__(self, section):
        del self.config[section.lower()]

    def __contains__(self, section):
        return section.lower() in self.config


if __name__ == "__main__":
    # Quick test of the ConfigMaster class
    config = ConfigMaster("test_config.ini")

    # Set values of different data types
    config.set("Section1", "IntKey", "10")
    config.set("Section1", "FloatKey", "3.14")
    config.set("Section1", "BoolKey", "true")
    config.set("Section1", "ListKey", "apple, banana, cherry")
    config.set("Section1", "TupleKey", "red, green, blue")
    config.set("Section1", "DateTimeKey", "2023-06-08 12:30:00")

    # Save the configuration to the file
    config.save()

    # Retrieve values of different data types
    int_value = config.getint("Section1", "IntKey", fallback=0)
    float_value = config.getfloat("Section1", "FloatKey", fallback=0.0)
    bool_value = config.getboolean("Section1", "BoolKey", fallback=False)
    list_value = config.getlist("Section1", "ListKey", fallback=[])
    tuple_value = config.gettuple("Section1", "TupleKey", fallback=())
    datetime_value = config.getdatetime("Section1", "DateTimeKey", fallback=None)

    # Print the retrieved values
    print("Int Value:", int_value)
    print("Float Value:", float_value)
    print("Bool Value:", bool_value)
    print("List Value:", list_value)
    print("Tuple Value:", tuple_value)
    print("DateTime Value:", datetime_value)