Skip to main content

A zero-configuration library with smart environment variable support and type-aware defaults

Project description

Zero Config ๐Ÿš€

A zero-configuration library with smart environment variable support and type-aware defaults. Perfect for LLM applications, APIs, and any Python project that needs intelligent configuration management.

โœจ Features

  • ๐Ÿ›ก๏ธ Safety-First Type Conversion: Comma-containing strings stay safe, only explicit JSON becomes lists
  • ๐Ÿ—๏ธ Section Headers: Organize config with llm.models โ†’ LLM__MODELS environment variables
  • ๐Ÿ›ค๏ธ Dynamic Path Helpers: Ruby on Rails style config.cache_path(), config.models_path() for any directory
  • ๐Ÿ“ฆ Section Access: Get entire config sections with config.get_section('llm')
  • ๐ŸŽฏ Smart Defaults: Your application defines the configuration schema
  • ๐Ÿ”„ Multiple Sources: Environment variables, .env.zero_config files, and programmatic config
  • ๐Ÿ” Project Root Detection: Automatically finds your project root using .git, pyproject.toml, etc.
  • โšก Zero Dependencies: Only requires python-dotenv (optional)

๐Ÿš€ Quick Start

from zero_config import setup_environment, get_config

# Define your application's default configuration
default_config = {
    'temperature': 0.0,
    'max_tokens': 1024,
    'timeout': 30,
    'debug': False,
    'models': ['gpt-4o-mini'],

    # Section headers for organized configuration
    'llm.models': ['gpt-4o-mini', 'claude-3'],
    'llm.temperature': 0.0,
    'database.host': 'localhost',
    'database.port': 5432,
}

# Initialize with your defaults (call once at startup)
setup_environment(default_config=default_config)

# Use anywhere in your code
config = get_config()

# Access configuration values with smart type conversion
temperature = config.get('temperature')  # 0.0 (float from defaults)
api_key = config.get('openai_api_key')   # From OPENAI_API_KEY env var
debug = config.get('debug')              # False (bool from defaults)

# Access section configuration
llm_config = config.get_section('llm')   # {'models': [...], 'temperature': 0.0}
db_config = config.get_section('database') # {'host': 'localhost', 'port': 5432}

# Environment variables override defaults with type conversion
# export TEMPERATURE="0.7"  -> becomes float 0.7
# export DEBUG="true"       -> becomes bool True
# export MODELS="gpt-4,claude-3" -> becomes list ['gpt-4', 'claude-3']

# Get all config as dict
all_config = config.to_dict()

๐Ÿ“ Configuration Sources (Priority Order)

  1. Default Config - Your application's default configuration passed to setup_environment()
  2. Environment Variables - Any uppercase environment variable matching config keys
  3. Domain Environment File - .env.zero_config in your project root

Environment Variables

# Any uppercase environment variable is automatically detected
export OPENAI_API_KEY="sk-..."              # Becomes: openai_api_key
export ANTHROPIC_API_KEY="sk-ant-..."       # Becomes: anthropic_api_key
export TEMPERATURE="0.7"                    # Becomes: temperature (with type conversion)
export MAX_TOKENS="2048"                    # Becomes: max_tokens (with type conversion)
export DEBUG="true"                         # Becomes: debug (with type conversion)

# Lists require explicit JSON array format (safe for comma-containing values):
export MODELS='["gpt-4", "claude-3"]'       # JSON array (only supported format)
export DATABASE_URL="host1,host2,host3"     # Stays as string (safe!)
export WELCOME="Hello, world!"              # Stays as string (safe!)

# Section headers with double underscore:
export LLM__MODELS='["gpt-4", "claude-3"]'  # Becomes: llm.models
export LLM__TEMPERATURE="0.7"               # Becomes: llm.temperature
export DATABASE__HOST="remote.db.com"       # Becomes: database.host
export DATABASE__PORT="3306"                # Becomes: database.port

Domain Environment File

Create .env.zero_config in your project root:

# API Keys
openai_api_key=sk-your-key-here
anthropic_api_key=sk-ant-your-key-here

# Configuration with smart type conversion
temperature=0.2
max_tokens=2048
debug=true

# Lists require explicit JSON array format (safe for comma-containing values):
models=["gpt-4", "claude-3", "gemini-pro"]  # JSON array (only supported format)
database_url=postgresql://host1,host2,host3/db  # Stays as string (safe!)
welcome_message=Hello, welcome to our app!      # Stays as string (safe!)

# Any key defined in your default config gets type conversion
# New keys are added as strings

๐ŸŽฏ Smart Configuration Philosophy

Zero Config provides intelligent configuration management with:

  1. Your Defaults First - You define what configuration your application needs
  2. Smart Type Conversion - Environment variables are automatically converted to match your default types
  3. Flexible Override - Any uppercase environment variable can override configuration
  4. No Prefixes Required - Clean environment variable names without artificial prefixes

This approach gives you full control over your application's configuration while providing maximum flexibility for deployment and testing.

๐Ÿ› ๏ธ Advanced Usage

Dynamic Path Helpers (Ruby on Rails Style)

Zero Config provides dynamic path helpers - any attribute ending with _path automatically creates a path helper function:

from zero_config import setup_environment, get_config, data_path, logs_path

setup_environment()
config = get_config()

# Built-in path helpers (for backward compatibility)
db_file = data_path('database.db')  # /project/data/database.db
log_file = logs_path('app.log')     # /project/logs/app.log

# Dynamic path helpers - any directory name + '_path'
cache_file = config.cache_path('session.json')    # /project/cache/session.json
temp_dir = config.temp_path()                     # /project/temp/
models_file = config.models_path('gpt4.bin')      # /project/models/gpt4.bin
uploads_dir = config.uploads_path()               # /project/uploads/
static_file = config.static_path('style.css')     # /project/static/style.css

# Any directory name works! (Ruby on Rails style)
config.backups_path('backup.tar.gz')             # /project/backups/backup.tar.gz
config.downloads_path('file.pdf')                # /project/downloads/file.pdf
config.assets_path('logo.png')                   # /project/assets/logo.png
config.exports_path()                            # /project/exports/

# How it works:
# 1. Python calls config.__getattr__('cache_path')
# 2. Detects '_path' suffix
# 3. Extracts 'cache' as directory name
# 4. Returns a function that creates /project/cache/* paths

Smart Type Conversion

Zero Config automatically converts environment variables to match your default config types with safety-first approach:

# Your default config defines the types
default_config = {
    'temperature': 0.0,      # float
    'max_tokens': 1024,      # int
    'debug': False,          # bool
    'models': ['gpt-4'],     # list
    'database_url': '',      # string
    'welcome_message': ''    # string
}

# Environment variables are converted to match default types
# export TEMPERATURE="0.7"                    โ†’ float: 0.7
# export MAX_TOKENS="2048"                    โ†’ int: 2048
# export DEBUG="true"                         โ†’ bool: True
# export MODELS='["gpt-4", "claude-3"]'       โ†’ list: ['gpt-4', 'claude-3'] (JSON only)
# export DATABASE_URL="host1,host2,host3"     โ†’ string: "host1,host2,host3" (safe!)
# export WELCOME="Hello, world!"              โ†’ string: "Hello, world!" (safe!)

Type Conversion Details

Numbers (int, float):

export PORT="8000"        # โ†’ int: 8000
export TEMPERATURE="0.7"  # โ†’ float: 0.7
export PORT="invalid"     # โ†’ string: "invalid" (safe fallback)

Booleans:

export DEBUG="true"    # โ†’ bool: True
export DEBUG="1"       # โ†’ bool: True
export DEBUG="yes"     # โ†’ bool: True
export DEBUG="on"      # โ†’ bool: True
export DEBUG="enabled" # โ†’ bool: True
export DEBUG="false"   # โ†’ bool: False
export DEBUG="0"       # โ†’ bool: False
export DEBUG="invalid" # โ†’ bool: False (safe fallback)

Lists (JSON-only for safety):

# โœ… Explicit JSON format (only supported)
export MODELS='["gpt-4", "claude-3"]'     # โ†’ list: ['gpt-4', 'claude-3']

# โœ… Comma-containing strings stay safe
export DATABASE_URL="host1,host2,host3"   # โ†’ string: "host1,host2,host3"
export WELCOME="Hello, world!"            # โ†’ string: "Hello, world!"
export API_ENDPOINT="api.com?q=a,b,c"     # โ†’ string: "api.com?q=a,b,c"

Section Configuration Access

Get entire configuration sections with clean, prefix-free keys:

# Default config with sections
default_config = {
    'llm.models': ['gpt-4o-mini'],
    'llm.temperature': 0.0,
    'llm.max_tokens': 1024,
    'database.host': 'localhost',
    'database.port': 5432,
    'cache.enabled': True,
    'cache.ttl': 3600,
}

setup_environment(default_config=default_config)
config = get_config()

# Get entire sections
llm_config = config.get_section('llm')
# Returns: {'models': ['gpt-4o-mini'], 'temperature': 0.0, 'max_tokens': 1024}

database_config = config.get_section('database')
# Returns: {'host': 'localhost', 'port': 5432}

cache_config = config.get_section('cache')
# Returns: {'enabled': True, 'ttl': 3600}

# Access individual values from sections
models = llm_config.get('models')  # ['gpt-4o-mini']
db_host = database_config.get('host')  # 'localhost'

Project Root Configuration

Zero-config automatically detects your project root, but you can override it:

from zero_config import setup_environment, get_config
from pathlib import Path

# Method 1: Environment variable (recommended)
# export PROJECT_ROOT="/path/to/my/project"
setup_environment()
config = get_config()
print(config.get('project_root'))  # Always available as config item

# Method 2: Programmatic override
setup_environment(start_path="/path/to/my/project")

# Method 3: Relative paths are resolved to absolute
# export PROJECT_ROOT="./my_project"  # Becomes /full/path/to/my_project

For Library Usage:

# Libraries get project_root automatically in config dict
def my_library_function(config: dict):
    project_root = config['project_root']  # Always absolute path
    log_file = os.path.join(project_root, 'logs', 'my_lib.log')
    cache_file = os.path.join(project_root, 'cache', 'my_lib.cache')
    return {'log_file': log_file, 'cache_file': cache_file}

# Application passes config to library
config_dict = config.to_dict()  # Contains project_root automatically
result = my_library_function(config_dict)

๐Ÿ“ฆ Installation

pip install zero-config

๐Ÿงช Development

# Clone the repository
git clone https://github.com/zero-config/zero-config.git
cd zero-config

# Install in development mode
pip install -e ".[dev]"

# Run tests
pytest

# Format code
black zero_config/

# Type checking
mypy zero_config/

๐Ÿ“„ License

MIT License - see LICENSE file for details.

๐Ÿ“š Quick Reference

Type Conversion Summary

# Numbers
export PORT="8000"        # โ†’ int: 8000
export TEMP="0.7"         # โ†’ float: 0.7

# Booleans
export DEBUG="true"       # โ†’ bool: True
export ENABLED="false"    # โ†’ bool: False

# Lists (JSON only - safe!)
export MODELS='["a","b"]' # โ†’ list: ['a', 'b']
export URLS="a,b,c"       # โ†’ string: "a,b,c" (safe!)

# Section Headers
export LLM__MODELS='["gpt-4"]'  # โ†’ llm.models
export DB__HOST="localhost"     # โ†’ database.host

# Project Root Override
export PROJECT_ROOT="/custom/path"  # โ†’ project_root (always absolute)

API Reference

# Setup
setup_environment(default_config={...})
config = get_config()

# Access
config.get('key', default)
config['key']  # Raises KeyError if missing
config.get_section('llm')  # Get all llm.* keys
config.get('project_root')  # Always available, always absolute path

# Dynamic Paths (Ruby on Rails style)
config.cache_path('file.txt')    # /project/cache/file.txt
config.models_path()             # /project/models/
config.any_name_path('file')     # /project/any_name/file

Safety Examples

# โœ… These stay as safe strings
DATABASE_URL="host1,host2,host3"     # String with commas
WELCOME="Hello, world!"             # Natural language
API_URL="api.com?q=a,b,c"           # Query parameters

# โœ… Explicit lists work perfectly
MODELS='["gpt-4", "claude-3"]'      # JSON array
SERVERS='["web1", "web2"]'          # JSON array

๐Ÿค Contributing

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

Project details


Download files

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

Source Distribution

zero_config-0.1.0.tar.gz (17.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zero_config-0.1.0-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

Details for the file zero_config-0.1.0.tar.gz.

File metadata

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

File hashes

Hashes for zero_config-0.1.0.tar.gz
Algorithm Hash digest
SHA256 10a5008203b3bcc1db27a94a23dfa905677ad9b5695e2d25367d9469caa070e7
MD5 3dc9bf29708b47a9f71cd4fd0474d1df
BLAKE2b-256 6085ce107429e9780fe172ff612b3dcb94bc1ee3481b191ff87c9a69e13b58d4

See more details on using hashes here.

File details

Details for the file zero_config-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: zero_config-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for zero_config-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9b68d1621522d99c152e9e95b1270e37e1097b7ac1ec4b4e8539a5cf88e9ddd8
MD5 e7a7273ac9e2a8de58ccf3f31933b594
BLAKE2b-256 3b97430708179992e979b4d33cee42f3c9dfcee4402ab3bf77d49b0a4df10218

See more details on using hashes here.

Supported by

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