ConfigObj

repository·release·Indexed 43 days ago

https://github.com/diffsk/configobj

A Python 3+ compatible library for reading and writing configuration files using an extended INI format. It supports nested sections, complex values, string interpolation, and round-tripping to preserve comments and member order. It includes a validation system via configspec for type checking, conversion, and default value management.

Tokens
17.2K
Snippets
43
Records
69
Agent score
47%

What's inside ConfigObj

  1. Introduction to ConfigObj

    release

    ConfigObj is an INI file 'round tripper' designed for easy reading and writing of configuration files. It supports advanced features while maintaining a simple interface, including:

    • Nested sections: Subsections to any depth.
    • Complex values: List values and multi-line values.
    • String interpolation: Support for variable substitution.
    • Validation: An integrated system for type checking, conversion, and default values.
    • Round-tripping: Preserves comments and the order of members and sections when writing files.
    • Unicode: Full Unicode support.
  2. Overview of configobj

    release
    configobj is a Python 3+ compatible port of the original configobj library. It is used for managing configuration files in a structured way. Note that this is a mature project and is not currently under active maintenance.
  3. Validate configuration using configspecs and Validator

    release

    Validation in ConfigObj is performed using a configspec (a template defining expected types and constraints) and a Validator object.

    Validation performs two roles:

    1. Checking: Verifies a value meets a specification (e.g., an integer between 1 and 6).
    2. Conversion: Automatically converts text values from the config file into the required Python type (e.g., converting a string '8080' to an integer 8080).

    Basic Configspec Syntax

    Configspecs use function-call syntax for constraints:

    port = integer(0, 100)
    user = string(max=25)
    mode = option('quiet', 'loud', 'silent')

    Supported Built-in Types

    • boolean (True/False)
    • integer (supports min/max)
    • float (supports min/max)
    • string (supports min/max length)
    • IP address (v4 only)
    • lists of the above types
    • option (restricts value to a specific set)
  4. Use Sections as Ordered Dictionaries

    release

    Every ConfigObj is itself a section (the root section), and every section is a subclass of the standard Python dict. This means you can use all standard dictionary methods like .update() and .clear() on them.

    Key Characteristics

    • Ordering: Sections are ordered. Iterating over a section (for member in section:), printing it, or accessing .keys(), .values(), and .items() will follow the order defined in the original file.
    • Creation: You create a new section by assigning a dictionary to a key.

    Warning: When you create a section from a dictionary, the new Section object is a copy. Changes made to the original dictionary will not be reflected in the ConfigObj section.

    config = ConfigObj()
    vals = {
        'key1': 'value 1', 
        'key2': 'value 2'
    }
    config['vals'] = vals
    
    # The section is a copy, not a reference
    config['vals'] == vals  # True
    config['vals'] is vals  # False
  5. How the Validator class works

    release

    The Validator class is used to verify that values conform to a specific schema. It performs two primary roles:

    1. Validation: Checking if a value (often a string from a config file) matches a specification.
    2. Conversion: Automatically converting the value to the required type (e.g., converting the string '1' to the integer 1).

    Checks are defined as strings that look like function calls (e.g., 'integer(min=0)'). These strings map to functions stored in the vtor.functions dictionary. When a check fails, the validator raises an exception (typically ValidateError).

    from validate import Validator
    
    vtor = Validator()
    # The check string maps to a function in vtor.functions
    newval = vtor.check('integer(min=0)', '-5') # This would raise an exception
  6. Configure type conversion and default values in validation

    release

    By default, validate() performs type conversion. If a check like integer succeeds, the value in the ConfigObj instance is converted to a Python integer. When writing to a file, these values are converted back to strings using str().

    Controlling Type Conversion

    To prevent validation from changing the type of the values (leaving them as strings), set the stringify_ attribute to False. Note that if stringify_ is False, attempting to set a value to a non-string will raise an error.

    Setting Default Values

    You can specify a default value in your configspec. If a value is missing from the config file, the default is used.

    • If no default is provided, a missing value results in an error returned by validate().
    • To implement optional values, set default=None. This sets the value to the Python None object (or '' if stringify_ is False).
    • Note: Default values must pass the specified check.

    List Defaults

    To use a list as a default value, use the list() constructor to avoid syntax confusion with commas and quotes: checkname(default=list('val1', 'val2', 'val3'))

    # Example configspec definitions
    port = integer(0, 100, default=80)
    user = string(max=25, default=0)
    mode = option('quiet', 'loud', 'silent', default='loud')
    nick = string(default=None)
    
    # List as a default
    items = string(default=list('item1', 'item2'))
  7. Configure String Interpolation styles

    release

    ConfigObj supports two mutually exclusive string interpolation styles. You must choose one style for your entire configuration file.

    • ConfigParser style: Uses %(name)s for substitution. This is the default if interpolation=True is passed to the constructor.
    • Template style: Uses ${name} or $name (if name is a valid Python identifier). This is recommended for being easier to read and write.

    To optimize performance in performance-critical applications where interpolation is not needed, initialize your instance with interpolation=False.

    Interpolation Lookup Order:

    1. The current section.
    2. The DEFAULT sub-section of the current section.
    3. The parent section.
    4. The parent section's DEFAULT sub-section, and so on up to the main section.

    Errors:

    • MissingInterpolationOption: Raised if the specified name is not found.
    • InterpolationLoopError: Raised if circular references cause an infinite loop.
    • Both are subclasses of InterpolationError.
    # Using Template style (recommended)
    from configobj import ConfigObj
    c = ConfigObj('config.ini', interpolation='Template')
    
    # Using ConfigParser style
    c = ConfigObj('config.ini', interpolation='ConfigParser')
    
    # Disabling interpolation for performance
    c = ConfigObj('config.ini', interpolation=False)
  8. Define default values in a configspec

    release

    You can specify default values in your configspec using the default keyword. If a key is missing from the configuration file, the validate() method will populate it with this default value.

    Examples of spec syntax:

    • key1 = integer(0, 30, default=15)
    • key2 = integer(default=15)
    • key3 = boolean(default=True)
    • key4 = option('Hello', 'Goodbye', 'Not Today', default='Not Today')

    Important Notes:

    • Validation: Default values must pass the check defined in the spec.
    • Tracking: ConfigObj tracks these in the defaults attribute of sections. Values in this list are not written out by write() unless you use copy=True during validation.
    • Optional Values: Setting default=None allows you to implement optional values. If the key is missing, it is set to None. (Note: if stringify_ is False, default=None returns '' instead).
  9. Configure encoding and Unicode handling

    release

    By default, ConfigObj does not decode input into Unicode. To work with Unicode keys and members, you must specify an encoding.

    • encoding: Sets the encoding for both reading and writing. If characters cannot be encoded, a UnicodeEncodeError is raised.
    • default_encoding: Used during the write process. If any members or keys are byte strings instead of Unicode, ConfigObj will attempt to decode them using default_encoding before outputting. If None, it defaults to ASCII. For Western European users, latin-1 is often recommended.
    • Automatic Detection: UTF16 encoded files are automatically detected and decoded even if encoding is None to prevent character mangling.
  10. Understand the Config File Format

    release

    ConfigObj uses a specific syntax for configuration files:

    Keywords and Values

    • Basic Pattern: keyword = value (keywords and values can be quoted).
    • Comments: Lines starting with # (optionally preceded by whitespace) are comments. Inline comments are supported: keyword = value # comment.
    • Lists: Comma-separated values.
      • Single member: key = value,
      • Empty list: key = ,
    • Multi-line Values: Surrounded by triple quotes (''' or `"""). Note that there is no safe way to quote values containing both types of triple quotes.

    Sections and Nesting

    • Sections: Indicated by [ section name ]. Names can be quoted.
    • Sub-sections: Indicated by repeating square brackets. The number of brackets represents the nesting level (e.g., [[sub-section]] is one level deep).
    • Nesting Rules: A NestingError is raised if bracket counts are mismatched or if a sub-section's level exceeds its parent's level by more than one.
    • Ordering: In the outer section, single values must appear before any sub-sections. Otherwise, they are assigned to the preceding sub-section.
    # comment line
    keyword = value # inline comment
    
    [section name 1]
    keyword1 = value1
    
        [[sub-section]]
        keyword1 = value1
    
            [[[nested section]]]
            keyword1 = value1
  11. Use __many__ for repeated sections and values

    release

    In a configspec, you can validate multiple sub-sections or multiple values using the __many__ keyword.

    • Repeated Sections: Define a section named __many__ in the configspec. Every sub-section within that section will be validated against the __many__ spec.
    • Repeated Values: Define a member named __many__ within a section to validate repeated values.
    • Mixed Usage: If you need both repeated sections and repeated values, use ___many___ (triple underscores) for one of them.

    __many__ only applies to entries that do not have an explicit, specifically named configspec.

  12. ConfigObj file format specification

    release

    ConfigObj uses an extended INI format. Key features of the syntax include:

    • Separators: Keywords and values are separated by =.
    • Sections: Defined by square brackets [section].
    • Nesting: Subsections are created by increasing the number of brackets (e.g., [[sub-section]], [[[sub-sub-section]]]).
    • Quotes: Keywords, values, and section names can be enclosed in single or double quotes.
    • Lists: Items are separated by commas.
    • Multi-line values: Use triple quotes (''' or """) to span multiple lines.
    • Comments: Supported via # (can be single-line or multi-line).
    # This is a comment
    keyword1 = value1
    'keyword 2' = 'value 2'
    
    [ "section 1" ]
    keyword 3 = value 3
    'keyword 4' = value4, value 5, 'value 6'
    
        [[ sub-section ]]    # Inline comment
        'keyword 5' = 'value 7'
        'keyword 6' = '''A multiline value,
    that spans more than one line.'''
    
            [[[ sub-sub-section ]]]
                'keyword 7' = 'value 8'
    
    [section 2]
    keyword8 = "value 9"