CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-cement

Advanced Application Framework for Python with a focus on Command Line Interfaces

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

configuration.mddocs/

Configuration Management

The configuration system provides comprehensive configuration file handling with support for multiple formats, default values, and hierarchical configuration merging. It integrates seamlessly with argument parsing for unified application configuration.

Capabilities

Configuration Handler Interface

Base interface for configuration management handlers that defines the contract for configuration operations.

class ConfigHandler:
    """
    Configuration handler interface for managing application configuration.
    
    Provides methods for parsing configuration files, merging configuration
    data, and accessing configuration values in a structured way.
    """
    
    def parse_file(self, file_path: str) -> bool:
        """
        Parse and load a configuration file.
        
        Args:
            file_path: Path to configuration file to parse
            
        Returns:
            True if file was successfully parsed, False otherwise
        """
    
    def merge(self, dict_obj: Dict[str, Any]) -> None:
        """
        Merge a dictionary into the configuration.
        
        Args:
            dict_obj: Dictionary to merge into configuration
        """
    
    def get(self, section: str, key: str) -> Any:
        """
        Get a configuration value.
        
        Args:
            section: Configuration section name
            key: Configuration key name
            
        Returns:
            Configuration value
            
        Raises:
            KeyError: If section or key not found
        """
    
    def get_section_dict(self, section: str) -> Dict[str, Any]:
        """
        Get an entire configuration section as a dictionary.
        
        Args:
            section: Section name to retrieve
            
        Returns:
            Dictionary containing all key-value pairs in the section
            
        Raises:
            KeyError: If section not found
        """
    
    def get_sections(self) -> List[str]:
        """
        Get list of all configuration sections.
        
        Returns:
            List of section names
        """
    
    def add_section(self, section: str) -> None:
        """
        Add a new configuration section.
        
        Args:
            section: Section name to add
        """
    
    def has_section(self, section: str) -> bool:
        """
        Check if a configuration section exists.
        
        Args:
            section: Section name to check
            
        Returns:
            True if section exists, False otherwise
        """
    
    def keys(self, section: str) -> List[str]:
        """
        Get list of keys in a configuration section.
        
        Args:
            section: Section name
            
        Returns:
            List of key names in the section
            
        Raises:
            KeyError: If section not found
        """
    
    def set(self, section: str, key: str, value: Any) -> None:
        """
        Set a configuration value.
        
        Args:
            section: Configuration section name
            key: Configuration key name
            value: Value to set
        """

Configuration Helper Functions

Utility functions for working with configuration defaults and initialization.

def init_defaults(*sections: str) -> Dict[str, Any]:
    """
    Create a standard dictionary for application configuration defaults.
    
    Creates a nested dictionary structure with the specified sections.
    This is commonly used for setting up application configuration defaults.
    
    Args:
        *sections: Section names to create in the defaults dictionary
        
    Returns:
        Dictionary with nested sections for configuration defaults
        
    Example:
        config = init_defaults('myapp', 'database', 'logging')
        # Returns: {'myapp': {}, 'database': {}, 'logging': {}}
    """

Usage Examples

Basic Configuration Setup

from cement import App, init_defaults

# Initialize configuration defaults
CONFIG = init_defaults('myapp')
CONFIG['myapp']['debug'] = False
CONFIG['myapp']['log_level'] = 'INFO'
CONFIG['myapp']['max_connections'] = 100

class MyApp(App):
    class Meta:
        label = 'myapp'
        config_defaults = CONFIG
        config_files = [
            '/etc/myapp.conf',
            '~/.myapp.conf',
            './myapp.conf'
        ]

with MyApp() as app:
    app.setup()
    
    # Access configuration values
    debug = app.config.get('myapp', 'debug')
    log_level = app.config.get('myapp', 'log_level')
    max_conn = app.config.get('myapp', 'max_connections')
    
    print(f"Debug: {debug}")
    print(f"Log Level: {log_level}")
    print(f"Max Connections: {max_conn}")

Configuration File Formats

ConfigParser Format (.conf, .ini)

# /etc/myapp.conf
[myapp]
debug = false
log_level = INFO
max_connections = 100

[database]
host = localhost
port = 5432
name = myapp_db
user = myapp_user
password = secret123

[logging]
file = /var/log/myapp.log
rotate = true
max_size = 10MB

YAML Format (with yaml extension)

# ~/.myapp.yaml
myapp:
  debug: false
  log_level: INFO
  max_connections: 100

database:
  host: localhost
  port: 5432
  name: myapp_db
  user: myapp_user
  password: secret123

logging:
  file: /var/log/myapp.log
  rotate: true
  max_size: 10MB

Multi-Section Configuration

from cement import App, init_defaults

# Initialize with multiple sections
CONFIG = init_defaults('myapp', 'database', 'logging', 'cache')

# Set defaults for each section
CONFIG['myapp']['debug'] = False
CONFIG['myapp']['version'] = '1.0.0'

CONFIG['database']['host'] = 'localhost'
CONFIG['database']['port'] = 5432
CONFIG['database']['timeout'] = 30

CONFIG['logging']['level'] = 'INFO'
CONFIG['logging']['file'] = None
CONFIG['logging']['format'] = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'

CONFIG['cache']['enabled'] = True
CONFIG['cache']['ttl'] = 3600
CONFIG['cache']['max_size'] = 1000

class MyApp(App):
    class Meta:
        label = 'myapp'
        config_defaults = CONFIG
        config_files = ['./myapp.conf']

with MyApp() as app:
    app.setup()
    
    # Access different sections
    db_config = app.config.get_section_dict('database')
    print(f"Database config: {db_config}")
    
    # Check if sections exist
    if app.config.has_section('cache'):
        cache_enabled = app.config.get('cache', 'enabled')
        print(f"Cache enabled: {cache_enabled}")
    
    # List all sections
    sections = app.config.get_sections()
    print(f"Available sections: {sections}")

Dynamic Configuration Management

from cement import App, Controller, ex, init_defaults

CONFIG = init_defaults('myapp')

class ConfigController(Controller):
    class Meta:
        label = 'config'
        stacked_on = 'base'
        stacked_type = 'nested'
    
    @ex(
        help='show configuration values',
        arguments=[
            (['--section'], {'help': 'show specific section only'})
        ]
    )
    def show(self):
        """Display current configuration."""
        if self.app.pargs.section:
            section = self.app.pargs.section
            if self.app.config.has_section(section):
                config_dict = self.app.config.get_section_dict(section)
                print(f"[{section}]")
                for key, value in config_dict.items():
                    print(f"{key} = {value}")
            else:
                print(f"Section '{section}' not found")
        else:
            # Show all sections
            for section in self.app.config.get_sections():
                print(f"[{section}]")
                config_dict = self.app.config.get_section_dict(section)
                for key, value in config_dict.items():
                    print(f"{key} = {value}")
                print()
    
    @ex(
        help='set configuration value',
        arguments=[
            (['section'], {'help': 'configuration section'}),
            (['key'], {'help': 'configuration key'}),
            (['value'], {'help': 'configuration value'})
        ]
    )
    def set(self):
        """Set a configuration value."""
        section = self.app.pargs.section
        key = self.app.pargs.key
        value = self.app.pargs.value
        
        # Create section if it doesn't exist
        if not self.app.config.has_section(section):
            self.app.config.add_section(section)
        
        self.app.config.set(section, key, value)
        print(f"Set {section}.{key} = {value}")
    
    @ex(
        help='get configuration value',
        arguments=[
            (['section'], {'help': 'configuration section'}),
            (['key'], {'help': 'configuration key'})
        ]
    )
    def get(self):
        """Get a configuration value."""
        section = self.app.pargs.section
        key = self.app.pargs.key
        
        try:
            value = self.app.config.get(section, key)
            print(f"{section}.{key} = {value}")
        except KeyError:
            print(f"Configuration key '{section}.{key}' not found")

class BaseController(Controller):
    class Meta:
        label = 'base'

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        config_defaults = CONFIG
        handlers = [
            BaseController,
            ConfigController
        ]

with MyApp() as app:
    app.run()

# Usage:
# myapp config show
# myapp config show --section database
# myapp config set database host localhost
# myapp config get database host

Configuration with Environment Variables

import os
from cement import App, init_defaults

CONFIG = init_defaults('myapp')

# Set defaults that can be overridden by environment variables
CONFIG['myapp']['debug'] = os.getenv('MYAPP_DEBUG', 'false').lower() == 'true'
CONFIG['myapp']['log_level'] = os.getenv('MYAPP_LOG_LEVEL', 'INFO')
CONFIG['myapp']['database_url'] = os.getenv('DATABASE_URL', 'sqlite:///app.db')

class MyApp(App):
    class Meta:
        label = 'myapp'
        config_defaults = CONFIG

    def setup(self):
        super().setup()
        
        # Override with environment variables after config file loading
        env_overrides = {}
        
        if 'MYAPP_DEBUG' in os.environ:
            env_overrides['debug'] = os.getenv('MYAPP_DEBUG').lower() == 'true'
        
        if 'MYAPP_LOG_LEVEL' in os.environ:
            env_overrides['log_level'] = os.getenv('MYAPP_LOG_LEVEL')
        
        if 'DATABASE_URL' in os.environ:
            env_overrides['database_url'] = os.getenv('DATABASE_URL')
        
        # Merge environment overrides
        if env_overrides:
            self.config.merge({'myapp': env_overrides})

with MyApp() as app:
    app.setup()
    
    debug = app.config.get('myapp', 'debug')
    log_level = app.config.get('myapp', 'log_level')
    db_url = app.config.get('myapp', 'database_url')
    
    print(f"Configuration loaded:")
    print(f"  Debug: {debug}")
    print(f"  Log Level: {log_level}")
    print(f"  Database URL: {db_url}")

Configuration Validation

from cement import App, init_defaults

CONFIG = init_defaults('myapp', 'database')
CONFIG['myapp']['name'] = 'MyApplication'
CONFIG['myapp']['version'] = '1.0.0'
CONFIG['database']['host'] = 'localhost'
CONFIG['database']['port'] = 5432

class MyApp(App):
    class Meta:
        label = 'myapp'
        config_defaults = CONFIG
        config_files = ['./myapp.conf']
    
    def validate_config(self):
        """Validate configuration after loading."""
        # Check required configuration values
        required_keys = [
            ('myapp', 'name'),
            ('myapp', 'version'),
            ('database', 'host'),
            ('database', 'port')
        ]
        
        for section, key in required_keys:
            try:
                value = self.config.get(section, key)
                if value is None or value == '':
                    raise ValueError(f"Required configuration {section}.{key} is missing or empty")
            except KeyError:
                raise ValueError(f"Required configuration {section}.{key} is missing")
        
        # Validate data types and ranges
        port = self.config.get('database', 'port')
        if not isinstance(port, int) or port < 1 or port > 65535:
            raise ValueError(f"Database port must be an integer between 1 and 65535, got: {port}")
        
        print("Configuration validation passed")
    
    def setup(self):
        super().setup()
        self.validate_config()

with MyApp() as app:
    app.setup()
    app.run()

Hierarchical Configuration Loading

from cement import App, init_defaults
import os

CONFIG = init_defaults('myapp')
CONFIG['myapp']['environment'] = 'development'

class MyApp(App):
    class Meta:
        label = 'myapp'
        config_defaults = CONFIG
    
    def setup(self):
        super().setup()
        
        # Load configuration files in priority order
        config_files = [
            '/etc/myapp/config.conf',          # System-wide config
            '/etc/myapp/myapp.conf',           # System-wide app config  
            os.path.expanduser('~/.myapp.conf'),  # User config
            './myapp.conf',                    # Local config
        ]
        
        # Add environment-specific config
        env = self.config.get('myapp', 'environment')
        env_config = f'./config/{env}.conf'
        config_files.append(env_config)
        
        # Load each config file (later files override earlier ones)
        for config_file in config_files:
            if os.path.exists(config_file):
                print(f"Loading config: {config_file}")
                self.config.parse_file(config_file)

with MyApp() as app:
    app.setup()
    
    # Final configuration reflects the hierarchy
    environment = app.config.get('myapp', 'environment')
    print(f"Running in {environment} environment")
    
    app.run()

Install with Tessl CLI

npx tessl i tessl/pypi-cement

docs

arguments.md

caching.md

configuration.md

controllers.md

extensions.md

foundation.md

hooks.md

index.md

interface-handler.md

logging.md

mail.md

output.md

plugins.md

templates.md

utilities.md

tile.json