๐ฎ Prism Config - Type-safe configuration with tiered loading, environment overrides, and secret resolution
Project description
โโโโโโโ โโโโโโโ โโโโโโโโโโโโโโโ โโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโ โโโ โโโโโโโโโโโโโโโโโ โโโ โโโ
โโโ โโโ โโโโโโโโโโโโโโโโโ โโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Configuration, Crystallized โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ฎ Prism Config
Type-safe Python configuration with tiered loading, environment overrides, and secret resolution
A modern Python configuration library that brings type safety, validation, and production-ready features to your applications. Built on Pydantic v2, prism-config makes configuration management simple, safe, and beautiful.
โจ Why Prism Config?
๐ฏ For Developers:
- Type-safe configuration with IDE autocomplete
- Clear error messages that help you fix issues fast
- Beautiful terminal output for debugging
- Works seamlessly with Docker, Kubernetes, and 12-factor apps
๐ For Production:
- Secure secret resolution (ENV and FILE providers)
- Immutable configurations prevent runtime bugs
- 16KB+ value support for post-quantum cryptography
- Comprehensive testing (101 unit tests + 1,100+ property tests)
โก For Performance:
- <0.3ms YAML file loading
- <0.003ms dictionary loading
- Built-in caching for display operations
- Zero-overhead type validation via Pydantic
๐ Quick Start
Installation
pip install prism-config
Basic Usage
from prism.config import PrismConfig
# Load from YAML file
config = PrismConfig.from_file("config.yaml")
# Type-safe access with autocomplete
print(config.app.name) # "my-app"
print(config.database.port) # 5432 (int, not string!)
# Beautiful terminal display
config.display()
Your First Config File
Create config.yaml:
app:
name: my-app
environment: production
database:
host: localhost
port: 5432
name: mydb
password: REF::ENV::DB_PASSWORD # Secret from environment
That's it! You now have type-safe, validated configuration.
๐ Complete Guide
Table of Contents
- Loading Methods
- Environment Variables
- CLI Arguments
- Secret Resolution
- Terminal Display
- Custom Schemas (v2.0.0+)
- Advanced Features
- Error Handling
- Integration Guide
1. Loading Methods
Prism Config provides three primary loading methods:
Load from Dictionary
Perfect for testing or programmatic configuration:
from prism.config import PrismConfig
config_data = {
"app": {
"name": "my-app",
"environment": "production"
},
"database": {
"host": "localhost",
"port": 5432,
"name": "mydb"
}
}
config = PrismConfig.from_dict(config_data)
print(config.app.name) # "my-app"
Load from YAML File
Most common for production use:
from prism.config import PrismConfig
# From string path or Path object
config = PrismConfig.from_file("config.yaml")
# With all overrides applied
config = PrismConfig.from_file(
"config.yaml",
apply_env=True, # Environment variables
resolve_secrets=True # Secret resolution
)
Load from All Sources (Recommended)
Convenience method that applies full precedence chain:
import sys
from prism.config import PrismConfig
# Automatically applies: CLI > Secrets > ENV > File
config = PrismConfig.from_all(
"config.yaml",
cli_args=sys.argv[1:] # Pass CLI arguments
)
Precedence Order:
CLI Arguments (highest priority)
โ
Secrets (REF:: resolution)
โ
Environment Variables
โ
YAML File Values
โ
Dictionary/Defaults (lowest priority)
2. Environment Variable Overrides
Override any configuration value using environment variables - perfect for Docker and Kubernetes!
Quick Example
import os
from prism.config import PrismConfig
# Set environment variables
os.environ["APP_DATABASE__HOST"] = "prod-db.example.com"
os.environ["APP_DATABASE__PORT"] = "3306"
# Load with environment overrides
config = PrismConfig.from_file("config.yaml", apply_env=True)
print(config.database.host) # "prod-db.example.com" (from env!)
print(config.database.port) # 3306 (auto-converted to int)
Environment Variable Format
# Pattern: APP_{SECTION}__{KEY}
# Double underscore (__) separates nested levels
export APP_APP__NAME="production-app"
export APP_APP__ENVIRONMENT="production"
export APP_DATABASE__HOST="prod.db.example.com"
export APP_DATABASE__PORT="5432" # Strings are auto-converted
Docker Example
Dockerfile:
ENV APP_DATABASE__HOST=db.production.com
ENV APP_DATABASE__PORT=5432
ENV APP_APP__ENVIRONMENT=production
Python code:
config = PrismConfig.from_file("config.yaml", apply_env=True)
# Automatically uses Docker environment variables!
Features
- โ Automatic Type Coercion - Strings converted to correct types
- โ
Case Insensitive - Both
APP_DATABASE__HOSTandapp_database__hostwork - โ
Safe by Default - Only variables with
APP_prefix are used - โ
Custom Prefix - Use your own:
env_prefix="MYAPP_" - โ
Deep Nesting - Use
__for any nesting level
3. CLI Argument Overrides
Override configuration at runtime with command-line arguments:
Quick Example
import sys
from prism.config import PrismConfig
# Pass CLI args (or use sys.argv[1:])
config = PrismConfig.from_file(
"config.yaml",
cli_args=["--database.port=9999", "--app.environment=staging"]
)
print(config.database.port) # 9999 (from CLI)
Supported Formats
Both dot and dash notation work:
# Dot notation (recommended)
python app.py --database.host=prod.example.com --database.port=5432
# Dash notation
python app.py --database-host=prod.example.com --database-port=5432
Integration with argparse
import argparse
from prism.config import PrismConfig
parser = argparse.ArgumentParser()
parser.add_argument("--database.host", help="Database host")
parser.add_argument("--database.port", type=int, help="Database port")
parser.add_argument("--app.environment", help="Environment")
args = parser.parse_args()
# Convert to prism-config format
cli_args = [f"--{k}={v}" for k, v in vars(args).items() if v is not None]
config = PrismConfig.from_file("config.yaml", apply_env=True, cli_args=cli_args)
Features
- โ Highest Precedence - Overrides everything (env, secrets, files)
- โ Automatic Type Coercion - CLI strings converted to correct types
- โ Dot or Dash Notation - Use whichever you prefer
- โ Safe by Default - Invalid paths silently ignored
4. Secret Resolution
Securely manage secrets from environment variables or files using the REF:: syntax.
Quick Example
import os
from prism.config import PrismConfig
# Set secret in environment
os.environ["DB_PASSWORD"] = "super-secret-pass"
config_data = {
"database": {
"password": "REF::ENV::DB_PASSWORD" # Reference to secret
}
}
config = PrismConfig.from_dict(config_data, resolve_secrets=True)
print(config.database.password) # "super-secret-pass" (resolved!)
Reference Format
REF::PROVIDER::KEY_PATH
- REF:: - Prefix indicating a secret reference
- PROVIDER - Secret provider (ENV or FILE)
- KEY_PATH - Provider-specific path to secret
ENV Provider
Read secrets from environment variables:
# config.yaml
database:
password: REF::ENV::DB_PASSWORD
api_key: REF::ENV::API_KEY
import os
os.environ["DB_PASSWORD"] = "my-password"
os.environ["API_KEY"] = "my-api-key"
config = PrismConfig.from_file("config.yaml", resolve_secrets=True)
FILE Provider (Docker Secrets)
Read secrets from files:
# config.yaml
database:
password: REF::FILE::/run/secrets/db_password
ssl_cert: REF::FILE::/run/secrets/ssl_cert
docker-compose.yml:
version: '3.8'
services:
app:
image: my-app
secrets:
- db_password
- ssl_cert
volumes:
- ./config.yaml:/app/config.yaml
secrets:
db_password:
file: ./secrets/db_password.txt
ssl_cert:
file: ./secrets/ssl_cert.pem
Python code:
config = PrismConfig.from_file("config.yaml", resolve_secrets=True)
# Secrets automatically resolved from Docker secret files
Kubernetes Secrets
# kubernetes-deployment.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: my-app
volumeMounts:
- name: secrets
mountPath: /var/run/secrets
readOnly: true
volumes:
- name: secrets
secret:
secretName: db-credentials
# config.yaml
database:
password: REF::FILE::/var/run/secrets/db-password
Post-Quantum Cryptography (PQC) Support
Prism Config supports large values up to 16KB+ for post-quantum cryptographic keys:
# Store large Kyber-1024 key (16KB)
config_data = {
"database": {
"encryption_key": "REF::FILE::/run/secrets/kyber1024_key" # 16KB file
}
}
config = PrismConfig.from_dict(config_data, resolve_secrets=True)
# Fully supports PQC keys!
Features
- โ ENV Provider - Environment variable secrets
- โ FILE Provider - File-based secrets (Docker/Kubernetes)
- โ Automatic Newline Stripping - File content cleaned
- โ 16KB+ Value Support - Ready for post-quantum crypto
- โ Multiple Secrets - Resolve many secrets in one config
- โ Mixed Providers - Use ENV and FILE together
- โ Fail-Fast - Clear errors for missing secrets
5. Beautiful Terminal Display
Visualize your configuration with the "Neon Dump" - a vaporwave-inspired terminal display:
Basic Usage
from prism.config import PrismConfig
config = PrismConfig.from_file("config.yaml")
config.display() # Shows banner + colored table
Output:
CONFIGURATION LOADED
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฆโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Configuration Key โ Value โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ
โ ๐ app.environment โ production โ
โ ๐ app.name โ my-app โ
โ ๐พ database.host โ localhost โ
โ ๐พ database.name โ mydb โ
โ ๐พ database.password โ [๐ REDACTED] โ
โ ๐พ database.port โ 5432 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Get Table as String
# Get formatted table without banner
table_output = config.dump()
print(table_output)
# Or save to file
with open("config-output.txt", "w") as f:
f.write(config.dump())
Show Secrets (v2.1.0+)
For debugging purposes, you can disable secret redaction:
# Show actual secret values (use with caution!)
config.display(redact_secrets=False)
# Or get unredacted dump as string
table = config.dump(redact_secrets=False)
โ ๏ธ Warning: Only use redact_secrets=False in secure development environments. Never expose secrets in logs or shared outputs.
Disable Colors
# Explicitly disable
config.display(use_color=False)
# Or via environment variable
import os
os.environ["NO_COLOR"] = "1"
config.display() # Auto-detects
Customize Theme
Create prism-palette.toml:
[theme]
name = "Custom Theme"
[colors]
header_bg = 197 # Hot pink
header_fg = 231 # White
key_color = 51 # Cyan
value_color = 183 # Light purple
border_color = 213 # Pink
secret_color = 196 # Red
[box_style]
style = "double" # single, double, rounded, bold
[emojis]
app = "๐"
database = "๐พ"
api = "๐"
Features
- โ Automatic Secret Redaction - Passwords/tokens hidden
- โ ANSI 256-Color Support - Beautiful on modern terminals
- โ Box-Drawing Characters - Professional table rendering
- โ Category Emojis - Visual categorization
- โ Customizable Themes - Full theme configuration
- โ NO_COLOR Support - Respects standard conventions
6. Custom Schemas (v2.0.0+)
Define your own configuration structure with full type safety and IDE autocomplete.
Why Custom Schemas?
- Type Safety: IDE knows the types of all your configuration values
- Autocomplete: Full IntelliSense support for your custom sections
- Validation: Pydantic validates your configuration at load time
- Documentation: Your schema documents your configuration structure
Quick Example
from prism.config import PrismConfig, BaseConfigSection, BaseConfigRoot
# Define custom sections
class AuthConfig(BaseConfigSection):
jwt_secret: str
token_expiry: int = 3600
enable_refresh: bool = True
class RateLimitConfig(BaseConfigSection):
requests_per_minute: int = 100
burst_size: int = 20
# Create your root configuration
class MyAppConfig(BaseConfigRoot):
app: AppConfig # Built-in
database: DatabaseConfig # Built-in
auth: AuthConfig # Custom!
rate_limit: RateLimitConfig
# Load with your schema
config = PrismConfig.from_file("config.yaml", schema=MyAppConfig)
# Full type safety!
config.auth.jwt_secret # str
config.auth.token_expiry # int
config.rate_limit.burst_size # int
Flexible Mode (No Schema)
Don't know your configuration structure upfront? Use flexible mode:
# Accept ANY configuration structure
config = PrismConfig.from_file("config.yaml", strict=False)
# Access any nested path
config.my_custom_section.nested.value
config.analytics.providers.google.tracking_id
Hybrid Mode (Typed + Flexible)
Combine type safety for core settings with flexibility for extensions:
class MyConfig(BaseConfigRoot):
app: AppConfig # Typed, validated
database: DatabaseConfig # Typed, validated
model_config = {"extra": "allow"} # Allow additional sections
config = PrismConfig.from_file("config.yaml", schema=MyConfig)
config.app.name # Typed access
config.plugin_config.option # Also works (flexible)
Custom Emoji Registration
Register emojis for your custom sections in the display:
from prism.config import register_emoji
register_emoji("auth", "๐")
register_emoji("rate_limit", "โฑ๏ธ")
register_emoji("my_custom_section", "๐ฏ")
config.display() # Uses your custom emojis!
See the examples/ directory for complete working examples:
- 06-fastapi - FastAPI with auth and rate limiting
- 07-django - Django-style settings
- 08-microservice - Multiple backends
- 09-multi-env - Environment-specific configs
- 10-flexible - Catch-all flexible mode
See the Migration Guide for upgrading from v1.x.
7. Advanced Features
Configuration Freezing (Immutability)
All configurations are immutable by default:
config = PrismConfig.from_file("config.yaml")
# Attempting to modify raises an error
try:
config._config.app.name = "modified" # โ Raises ValidationError
except Exception as e:
print("Configuration is immutable!")
Benefits:
- Prevents accidental runtime changes
- Thread-safe by design
- Catches bugs early
- Ensures configuration integrity
Export & Serialization
Export configuration to various formats:
from prism.config import PrismConfig
config = PrismConfig.from_file("config.yaml")
# Export to dictionary
config_dict = config.to_dict()
safe_dict = config.to_dict(redact_secrets=True) # With redaction
# Export to YAML
yaml_str = config.to_yaml()
config.to_yaml_file("output.yaml")
config.to_yaml_file("safe.yaml", redact_secrets=True) # With redaction
# Export to JSON
json_str = config.to_json()
config.to_json_file("output.json")
config.to_json_file("safe.json", redact_secrets=True) # With redaction
Use Cases:
- Share configs with teammates (secrets redacted)
- Generate configuration templates
- Archive configuration snapshots
- Convert between formats
Configuration Diffing
Compare configurations to detect changes:
from prism.config import PrismConfig
# Load two configs
config_v1 = PrismConfig.from_file("config-v1.yaml")
config_v2 = PrismConfig.from_file("config-v2.yaml")
# Get differences as dict
diff = config_v1.diff(config_v2)
print(diff)
# {
# "app.name": {"old": "app-v1", "new": "app-v2"},
# "database.host": {"old": "localhost", "new": "prod.example.com"}
# }
# Get human-readable diff
print(config_v1.diff_str(config_v2))
Output:
Configuration Differences:
app.name:
- Old: app-v1
+ New: app-v2
database.host:
- Old: localhost
+ New: prod.example.com
Use Cases:
- Detect configuration drift between environments
- Validate changes before deployment
- Audit configuration history
- Debug configuration issues
8. Error Handling
Prism Config provides clear, actionable error messages:
Exception Types
All exceptions inherit from PrismConfigError:
from prism.config import PrismConfig
from prism.config.exceptions import (
PrismConfigError, # Base exception
ConfigFileNotFoundError, # File not found
ConfigParseError, # YAML parsing failed
ConfigValidationError, # Validation failed
SecretResolutionError, # Secret resolution failed
SecretProviderNotFoundError, # Unknown provider
InvalidSecretReferenceError # Invalid REF:: syntax
)
# Catch all prism-config errors
try:
config = PrismConfig.from_file("config.yaml")
except PrismConfigError as e:
print(f"Configuration error: {e}")
Example Error Messages
Missing File:
Configuration file not found: /path/to/config.yaml
Searched at: /absolute/path/to/config.yaml
Suggestion: Check if the file exists and the path is correct
YAML Syntax Error:
Failed to parse configuration file: config.yaml
Line 5
Reason: YAML syntax error
Suggestion: Check YAML syntax and file encoding
Validation Error:
Configuration validation failed for field: database.port
Expected type: int
Actual type: str
Actual value: 'not_a_number'
Suggestion: Check configuration schema and value types
Secret Resolution Error:
Failed to resolve secret: ENV::DATABASE_PASSWORD
Reason: Environment variable not found
Suggestion: Set environment variable 'DATABASE_PASSWORD' or check variable name
Type Safety
Prism Config includes full type hints and py.typed marker:
# Verify types with mypy
mypy your_code.py
# Verify with pyright
pyright your_code.py
9. Integration Guide for Prism Libraries
For Claude Code and developers building other prism libraries: This section shows you exactly how to integrate prism-config into your prism library.
Step 1: Install Prism Config
pip install prism-config
Or add to your pyproject.toml:
[project]
dependencies = [
"prism-config>=1.0.0,<2.0.0",
]
Step 2: Define Your Configuration Schema
Create a configuration module for your library (e.g., your_library/config.py):
from pydantic import BaseModel, Field
from prism.config import PrismConfig as BasePrismConfig
class YourLibraryConfig(BaseModel):
"""Configuration specific to your library."""
feature_enabled: bool = Field(default=True, description="Enable main feature")
timeout: int = Field(default=30, description="Operation timeout in seconds")
api_endpoint: str = Field(..., description="API endpoint URL")
api_key: str = Field(..., description="API authentication key")
model_config = {
"frozen": True, # Immutable
"extra": "forbid" # Reject unknown fields
}
class AppConfig(BaseModel):
"""Application-level configuration."""
name: str = Field(..., description="Application name")
environment: str = Field(..., description="Environment (dev, staging, prod)")
model_config = {"frozen": True}
class DatabaseConfig(BaseModel):
"""Database configuration."""
host: str = Field(default="localhost", description="Database host")
port: int = Field(default=5432, description="Database port")
name: str = Field(..., description="Database name")
password: str | None = Field(default=None, description="Database password")
model_config = {"frozen": True}
class ConfigRoot(BaseModel):
"""Root configuration combining all sections."""
app: AppConfig
database: DatabaseConfig
your_library: YourLibraryConfig # Your library's config section
model_config = {
"frozen": True,
"extra": "forbid",
"validate_assignment": True
}
class YourLibraryPrismConfig(BasePrismConfig):
"""
Prism Config for YourLibrary.
This extends the base PrismConfig with your library's configuration schema.
Usage:
>>> config = YourLibraryPrismConfig.from_file("config.yaml")
>>> print(config.your_library.api_endpoint)
>>> print(config.database.host)
"""
def __init__(self, config_root: ConfigRoot):
"""Initialize with custom ConfigRoot."""
# Store the config root that includes your library's config
self._config = config_root
@property
def your_library(self) -> YourLibraryConfig:
"""Access your library's configuration."""
return self._config.your_library
# Inherit all loading methods from BasePrismConfig:
# - from_dict()
# - from_file()
# - from_all()
# - to_dict(), to_yaml(), to_json()
# - diff(), display(), etc.
Step 3: Create Your Configuration File
Create config.yaml in your project:
app:
name: your-app
environment: production
database:
host: localhost
port: 5432
name: yourdb
password: REF::ENV::DB_PASSWORD # Secret from environment
your_library: # Your library's configuration section
feature_enabled: true
timeout: 60
api_endpoint: https://api.example.com
api_key: REF::FILE::/run/secrets/api_key # Secret from file
Step 4: Load and Use Configuration
In your library's main module:
from your_library.config import YourLibraryPrismConfig
def initialize_library(config_path: str = "config.yaml"):
"""Initialize your library with configuration."""
# Load configuration with all features
config = YourLibraryPrismConfig.from_all(
config_path,
cli_args=sys.argv[1:] # Optional CLI args
)
# Access your library's configuration
if config.your_library.feature_enabled:
print(f"Feature enabled with timeout: {config.your_library.timeout}")
# Access shared configuration (app, database)
print(f"App: {config.app.name}")
print(f"Database: {config.database.host}:{config.database.port}")
# Display configuration (with secrets redacted)
config.display()
return config
# Usage
config = initialize_library("config.yaml")
# Use configuration throughout your library
api_client = APIClient(
endpoint=config.your_library.api_endpoint,
api_key=config.your_library.api_key,
timeout=config.your_library.timeout
)
db_connection = Database(
host=config.database.host,
port=config.database.port,
name=config.database.name,
password=config.database.password
)
Step 5: Testing Your Configuration
Create tests for your configuration:
import pytest
from your_library.config import YourLibraryPrismConfig
def test_config_loading():
"""Test basic configuration loading."""
config_data = {
"app": {"name": "test-app", "environment": "testing"},
"database": {"host": "localhost", "port": 5432, "name": "testdb"},
"your_library": {
"feature_enabled": True,
"timeout": 30,
"api_endpoint": "https://test.example.com",
"api_key": "test-key"
}
}
config = YourLibraryPrismConfig.from_dict(config_data)
assert config.your_library.feature_enabled is True
assert config.your_library.timeout == 30
assert config.database.host == "localhost"
def test_config_with_secrets():
"""Test secret resolution."""
import os
os.environ["API_KEY"] = "secret-key-123"
config_data = {
"app": {"name": "test-app", "environment": "testing"},
"database": {"host": "localhost", "port": 5432, "name": "testdb"},
"your_library": {
"feature_enabled": True,
"timeout": 30,
"api_endpoint": "https://test.example.com",
"api_key": "REF::ENV::API_KEY" # Secret reference
}
}
config = YourLibraryPrismConfig.from_dict(config_data, resolve_secrets=True)
assert config.your_library.api_key == "secret-key-123"
def test_config_validation():
"""Test that invalid config is rejected."""
config_data = {
"app": {"name": "test-app", "environment": "testing"},
"database": {"host": "localhost", "port": "not-a-number", "name": "testdb"},
"your_library": {
"feature_enabled": True,
"timeout": 30,
"api_endpoint": "https://test.example.com",
"api_key": "test-key"
}
}
with pytest.raises(Exception): # Will raise ConfigValidationError
YourLibraryPrismConfig.from_dict(config_data)
Step 6: Documentation for Your Users
Document configuration for your library's users:
# Configuration
YourLibrary uses [prism-config](https://github.com/lukeudell/prism-config) for type-safe configuration management.
## Quick Start
Create `config.yaml`:
\`\`\`yaml
app:
name: my-app
environment: production
database:
host: localhost
port: 5432
name: mydb
password: REF::ENV::DB_PASSWORD
your_library:
feature_enabled: true
timeout: 60
api_endpoint: https://api.example.com
api_key: REF::FILE::/run/secrets/api_key
\`\`\`
Load in your code:
\`\`\`python
from your_library import YourLibraryPrismConfig
config = YourLibraryPrismConfig.from_file("config.yaml", resolve_secrets=True)
\`\`\`
## Configuration Options
### `your_library` Section
- `feature_enabled` (bool): Enable the main feature (default: true)
- `timeout` (int): Operation timeout in seconds (default: 30)
- `api_endpoint` (str): API endpoint URL (required)
- `api_key` (str): API authentication key (required)
### Environment Variables
Override any setting:
\`\`\`bash
export APP_YOUR_LIBRARY__TIMEOUT=120
export APP_YOUR_LIBRARY__FEATURE_ENABLED=false
\`\`\`
### Secrets
Use `REF::ENV::` or `REF::FILE::` for secrets:
\`\`\`yaml
your_library:
api_key: REF::ENV::API_KEY # From environment variable
ssl_cert: REF::FILE::/run/secrets/cert # From Docker secret
\`\`\`
See [prism-config documentation](https://github.com/lukeudell/prism-config) for more features.
Key Integration Points
โ Extend BasePrismConfig: Inherit all loading methods โ Add Your Schema: Create Pydantic models for your config section โ Use ConfigRoot: Combine app, database, and your config โ Support Secrets: Use REF:: syntax for sensitive values โ Enable Overrides: Support ENV and CLI overrides โ Test Thoroughly: Test loading, validation, and secrets โ Document Well: Show users how to configure your library
๐ Features Summary
Core Features
| Feature | Status | Description |
|---|---|---|
| Dictionary Loading | โ | Load config from Python dicts |
| YAML File Loading | โ | Load config from YAML files |
| Environment Overrides | โ | Override with APP_SECTION__KEY env vars |
| CLI Arguments | โ | Override with --section.key=value args |
| Secret Resolution | โ | ENV and FILE providers with REF:: syntax |
| Type Safety | โ | Pydantic v2 validation with type hints |
| Immutability | โ | Frozen models prevent runtime changes |
| Beautiful Display | โ | Vaporwave-inspired terminal output |
| Secret Redaction | โ | Auto-hide passwords in display/export |
| Export (YAML/JSON) | โ | Export to multiple formats |
| Configuration Diffing | โ | Compare configs, detect changes |
| PQC Support | โ | 16KB+ values for quantum-safe keys |
| Custom Exceptions | โ | Clear error messages with suggestions |
| Type Checking | โ | PEP 561 compliant with py.typed |
Testing & Quality
- 101 unit tests covering all features
- 1,100+ property-based tests via Hypothesis
- 6 cross-language parity tests for behavioral consistency
- 86% code coverage with detailed reports
- Zero linter errors (Ruff)
- Type-checked (mypy, pyright)
๐ Project Status
Version: 2.1.1 (Production Ready)
Completed:
- โ All development iterations (100%)
- โ Custom schemas and flexible mode (v2.0.0)
- โ Secret unredaction option (v2.1.0)
- โ Comprehensive documentation with examples
- โ Structured error metadata for observability (v2.1.1)
- โ Full test coverage (318 tests)
- โ GitHub Actions CI/CD
- โ PyPI package published
- โ Production-ready code quality
๐ ๏ธ Development
Setup
# Clone repository
git clone https://github.com/lukeudell/prism-config.git
cd prism-config
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # Linux/Mac
.venv\Scripts\activate # Windows
# Install dependencies
pip install -e ".[dev]"
Run Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=src/prism/config --cov-report=term-missing
# Run specific test file
pytest tests/test_loader.py -v
# Run parity tests
python tests/parity/test_parity.py
Run Benchmarks
# Performance benchmarks
python -m benchmarks.bench_loader
# Profiling
python -m benchmarks.profile_loader
Project Structure
prism-config/
โโโ src/prism/config/
โ โโโ __init__.py # Public API
โ โโโ loader.py # PrismConfig class
โ โโโ models.py # Pydantic models
โ โโโ providers.py # Secret providers
โ โโโ display.py # Terminal display
โ โโโ exceptions.py # Custom exceptions
โ โโโ py.typed # Type marker
โโโ tests/
โ โโโ test_*.py # 11 test files
โ โโโ parity/ # Cross-language parity tests
โโโ examples/ # 10 complete examples
โโโ docs/ # Documentation
โ โโโ CODEX.md # Technical design guide
โ โโโ RELEASE_NOTES.md # Release announcements
โ โโโ migration-v2.md # v1.x to v2.x migration guide
โโโ CHANGELOG.md # Version history
โโโ pyproject.toml # Project metadata
๐ Documentation
- CHANGELOG.md - Version history and changes
- docs/CODEX.md - Technical design and architecture guide
- docs/RELEASE_NOTES.md - Release announcements
- docs/migration-v2.md - v1.x to v2.x migration guide
- examples/ - 10 complete usage examples
๐ค Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
Built with:
- Pydantic v2 - Data validation and settings management
- PyYAML - YAML parsing
- Hypothesis - Property-based testing
Inspired by:
- 12-factor app configuration principles
- Docker and Kubernetes secret management patterns
- Post-quantum cryptography readiness
๐ Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: README.md
- Changelog: CHANGELOG.md
๐ฎ Built with precision and care by the Prism Config team ๐ฎ
Production-ready โข Type-safe โข Developer-friendly
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file prism_config-2.1.2.tar.gz.
File metadata
- Download URL: prism_config-2.1.2.tar.gz
- Upload date:
- Size: 1.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8953aa8630ce7899cbe976f36e1f3ea66747b7bce0bfefd70d865950a653a981
|
|
| MD5 |
9136d58a6c9cbdd9369a94ef3b052e6f
|
|
| BLAKE2b-256 |
2f7535db1d7e7c659ffb9df70e3c666cb8c14028f1605e181a510f717e8d3a7b
|
Provenance
The following attestation bundles were made for prism_config-2.1.2.tar.gz:
Publisher:
publish.yml on lukeudell/prism-config
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
prism_config-2.1.2.tar.gz -
Subject digest:
8953aa8630ce7899cbe976f36e1f3ea66747b7bce0bfefd70d865950a653a981 - Sigstore transparency entry: 749837835
- Sigstore integration time:
-
Permalink:
lukeudell/prism-config@1c2646a4852121934cc9c6923668e8533216bbe7 -
Branch / Tag:
refs/tags/v2.1.2 - Owner: https://github.com/lukeudell
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1c2646a4852121934cc9c6923668e8533216bbe7 -
Trigger Event:
release
-
Statement type:
File details
Details for the file prism_config-2.1.2-py3-none-any.whl.
File metadata
- Download URL: prism_config-2.1.2-py3-none-any.whl
- Upload date:
- Size: 42.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae5067f1e94b79f365080c3c3066141da054aacd8c787b8b27542940eb5eb11a
|
|
| MD5 |
f6623ab8c655a5f63f015c9060bab7c7
|
|
| BLAKE2b-256 |
f0768c3416623e06ccbfaf2e397f7d2a595554e25dd4effd58dc13cd43507d9c
|
Provenance
The following attestation bundles were made for prism_config-2.1.2-py3-none-any.whl:
Publisher:
publish.yml on lukeudell/prism-config
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
prism_config-2.1.2-py3-none-any.whl -
Subject digest:
ae5067f1e94b79f365080c3c3066141da054aacd8c787b8b27542940eb5eb11a - Sigstore transparency entry: 749837890
- Sigstore integration time:
-
Permalink:
lukeudell/prism-config@1c2646a4852121934cc9c6923668e8533216bbe7 -
Branch / Tag:
refs/tags/v2.1.2 - Owner: https://github.com/lukeudell
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1c2646a4852121934cc9c6923668e8533216bbe7 -
Trigger Event:
release
-
Statement type: