Skip to main content

WL Config Manager

A flexible configuration manager for Python applications that supports multiple file formats, environment variable overrides, and dot notation access.

Features

  • Multiple Formats - YAML, JSON, and INI configuration files
  • Dot Notation - Access nested values with config.server.port
  • Environment Variables - Override config values with environment variables
  • Default Values - Built-in defaults with easy overrides
  • File Search - Automatically find config files in standard locations
  • Validation - Ensure required keys are present
  • CLI Tool - Command-line interface for config manipulation
  • Type Conversion - Automatic type conversion for environment variables
  • Live Reload - Reload configuration without restarting

Installation

pip install wl-config-manager

Dependencies

  • wl_version_manager
  • pyyaml>=5.1

Quick Start

Basic Usage

from wl_config_manager import ConfigManager

# Load config from file
config = ConfigManager(config_path="config.yaml")

# Access values with dot notation
port = config.server.port
debug = config.app.debug

# Or use get() method
database_url = config.get("database.url", default="sqlite:///app.db")

Configuration File Example

# config.yaml
app:
  name: "My Application"
  debug: false
  version: "1.0.0"

server:
  host: "0.0.0.0"
  port: 8080
  workers: 4

database:
  url: "postgresql://localhost/myapp"
  pool_size: 10
  echo: false

logging:
  level: "INFO"
  format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"

Configuration Loading

Search Paths

If no config path is specified, the manager searches these locations in order:

from wl_config_manager import ConfigManager, DEFAULT_SEARCH_PATHS

# Default search paths on Fedora/CentOS:
# - ~/.config/
# - /etc/
# - /etc/app/
# - current working directory

# Use default search paths
config = ConfigManager(search_paths=DEFAULT_SEARCH_PATHS)

# Or specify custom search paths
config = ConfigManager(search_paths=["/opt/myapp", "/etc/myapp"])

File Formats

The format is auto-detected by file extension, or can be specified:

# Auto-detect format
config = ConfigManager(config_path="settings.json")  # JSON
config = ConfigManager(config_path="app.ini")       # INI
config = ConfigManager(config_path="config.yaml")   # YAML

# Explicitly specify format
config = ConfigManager(config_path="myconfig", format="yaml")

Environment Variable Overrides

Override configuration values using environment variables:

# Configure with env prefix
config = ConfigManager(
    config_path="config.yaml",
    env_prefix="MYAPP_"
)

# Environment variables override config file values
# MYAPP_SERVER__PORT=9000 overrides server.port
# MYAPP_APP__DEBUG=true overrides app.debug
# MYAPP_DATABASE__URL=postgres://prod-server/db overrides database.url

Environment variable rules:

  • Prefix + double underscore (__) for nested values
  • Values are automatically converted to appropriate types (bool, int, float, string)
  • Case-insensitive (environment vars are converted to lowercase)

Default Configuration

Provide default values that are used if not found in config file or environment:

default_config = {
    "app": {
        "name": "DefaultApp",
        "debug": False
    },
    "server": {
        "port": 8080,
        "host": "localhost"
    }
}

config = ConfigManager(
    config_path="config.yaml",
    default_config=default_config
)

Validation

Ensure required configuration keys are present:

# Validate required keys
config = ConfigManager(
    config_path="config.yaml",
    required_keys=["app.name", "server.port", "database.url"]
)
# Raises ConfigValidationError if any required keys are missing

Accessing Configuration Values

Dot Notation Access

# Direct attribute access
app_name = config.app.name
port = config.server.port

# Nested access
log_level = config.logging.level

# Safe access with get()
smtp_host = config.get("email.smtp.host", default="localhost")

# Get entire sections
server_config = config.server  # Returns namespace object
server_dict = config.get("server")  # Returns dict

Dictionary-like Access

# The configuration objects support dict-like operations
if "debug" in config.app:
    print(f"Debug mode: {config.app.debug}")

# Iterate over sections
for section, values in config:
    print(f"{section}: {values}")

# Get items from a section
for key, value in config.items("server"):
    print(f"{key} = {value}")

Modifying Configuration

Set Values

# Set single value
config.set("app.version", "2.0.0")
config.set("server.port", 9000)

# Create nested structures
config.set("new_feature.enabled", True)
config.set("new_feature.options.timeout", 30)

# Update multiple values
config.update({
    "version": "2.0.0",
    "debug": True
})

# Update with prefix
config.update({"port": 9000, "workers": 8}, prefix="server")

Save Configuration

# Save to original file
config.save()

# Save to different file
config.save("new_config.yaml")

# Save in different format
config.save("config.json")  # Auto-converts to JSON

Advanced Usage

Reload Configuration

# Reload from source file (picks up external changes)
config.reload()

Create from Dictionary

config_dict = {
    "app": {"name": "MyApp"},
    "server": {"port": 8080}
}

config = ConfigManager.from_dict(config_dict)

Create from Environment Only

# Load configuration entirely from environment variables
config = ConfigManager.from_env("MYAPP_")

Logging Configuration

# Set logging level for config manager
config = ConfigManager(
    config_path="config.yaml",
    log_level=logging.DEBUG  # See config loading details
)

# Set up file logging
from wl_config_manager import setup_file_logging

setup_file_logging(
    log_dir="/var/log",
    app_name="myapp",
    log_level=logging.INFO
)

Command Line Interface

The package includes a CLI tool for managing configurations:

View Configuration

# Get entire config
wl_config_manager get config.yaml

# Get specific value
wl_config_manager get config.yaml server.port

# Get with default
wl_config_manager get config.yaml app.missing --default="not found"

# Output as JSON
wl_config_manager get --format=json config.yaml

Modify Configuration

# Set values
wl_config_manager set config.yaml app.debug true
wl_config_manager set config.yaml server.port 9000

# Create new config file
wl_config_manager create --format=yaml new_config.yaml

# Create from template
wl_config_manager create --template=default.yaml --vars='{"app":{"name":"MyApp"}}' config.yaml

Validate Configuration

# Check required keys
wl_config_manager validate --required=app.name,server.port config.yaml

Convert Formats

# Convert between formats
wl_config_manager convert config.ini config.yaml
wl_config_manager convert settings.yaml settings.json

List Configuration

# List all values
wl_config_manager list config.yaml

# List section only
wl_config_manager list config.yaml --section=server

Environment Variables

# Show config from environment variables
wl_config_manager env MYAPP_ --format=json

Error Handling

The module provides specific exceptions for different error types:

from wl_config_manager import (
    ConfigError,           # Base exception
    ConfigFileError,       # File not found/readable
    ConfigFormatError,     # Invalid file format
    ConfigValidationError  # Validation failures
)

try:
    config = ConfigManager(config_path="config.yaml")
except ConfigFileError as e:
    print(f"Config file error: {e}")
    print(f"File path: {e.file_path}")
except ConfigValidationError as e:
    print(f"Validation error: {e}")
    print(f"Missing keys: {e.get_missing_keys()}")

Best Practices

  1. Use Environment Variables for Secrets

    export MYAPP_DATABASE__PASSWORD="secret"
    export MYAPP_API__KEY="secret-key"
    
  2. Provide Sensible Defaults

    default_config = {
        "server": {"port": 8080, "host": "0.0.0.0"},
        "logging": {"level": "INFO"}
    }
    
  3. Validate Critical Configuration

    required_keys = ["database.url", "app.secret_key"]
    config = ConfigManager(required_keys=required_keys)
    
  4. Use Type Hints with Config Objects

    from typing import TYPE_CHECKING
    if TYPE_CHECKING:
        from types import SimpleNamespace
    
    def setup_server(server_config: SimpleNamespace):
        port = server_config.port
        host = server_config.host
    

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wl_config_manager-0.1.43.tar.gz (28.4 kB view details)

Uploaded Source

File details

Details for the file wl_config_manager-0.1.43.tar.gz.

File metadata

  • Download URL: wl_config_manager-0.1.43.tar.gz
  • Upload date:
  • Size: 28.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for wl_config_manager-0.1.43.tar.gz
Algorithm Hash digest
SHA256 4ffce9d37b2d34add38e71b96bf7b775d76fd49c1724aaa82a791506fd7963ac
MD5 9fac175e29e6f348ccdac6888578eb1c
BLAKE2b-256 9eab9f5b224775b27f1bdbf7c2e2d7814fe03abd57cd1e8c38a5aa78b8822e07

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.43 This release

1 file

0.1.40

1 file

0.1.36

1 file

0.1.33

1 file

0.1.31

1 file

0.1.23

1 file

0.1.20

1 file

0.1.18

1 file

0.1.16

1 file

0.1.8

1 file

0.1.5

1 file

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page