A powerful configuration management library with beautiful display, environment variables and YAML support
Project description
ConfigPlusPlus
Beautiful configuration management for Python with environment variables and YAML support
Features
โจ Beautiful Display - Pretty formatted configuration output with automatic grouping and secret masking
๐ Secret Masking - Automatically hides sensitive values (API keys, passwords, tokens)
๐ Environment Variables - Load configuration from environment variables with type casting
๐ YAML Support - Load configuration from YAML files with custom parsing
๐ฏ Type Casting - Automatic type conversion (str, int, float, bool, Path)
๐ท๏ธ Static & Instance - Support for both static class-based and instance-based configs
Installation
pip install configplusplus
Or with Poetry:
poetry add configplusplus
Quick Start
Environment-Based Configuration
from configplusplus import EnvConfigLoader, env
import pathlib
class AppConfig(EnvConfigLoader):
# Required variables
DATABASE_HOST = env("DATABASE_HOST")
DATABASE_PORT = env("DATABASE_PORT", cast=int)
# Optional with defaults
DEBUG_MODE = env("DEBUG_MODE", cast=bool, default=False)
# Paths
DATA_DIR = env("DATA_DIR", cast=pathlib.Path)
# Secrets (automatically masked in output)
SECRET_API_KEY = env("SECRET_API_KEY")
# Use as static class
print(AppConfig.DATABASE_HOST)
print(AppConfig) # Beautiful formatted output
Output:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ APPCONFIG โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โถ DATABASE
DATABASE_HOST = 'localhost'
DATABASE_PORT = 5432
โถ DEBUG
DEBUG_MODE = False
โถ DATA
DATA_DIR = '/var/data/myapp'
โถ SECRET
SECRET_API_KEY = 'sec...et (hidden)'
YAML-Based Configuration
from configplusplus import YamlConfigLoader
class UiConfig(YamlConfigLoader):
def __post_init__(self) -> None:
# Parse the loaded YAML data
self.app_name = self._raw_config["application"]["name"]
self.theme = self._raw_config["display"]["theme"]
# Parse nested structures
self.filters = [
FilterConfig(**f)
for f in self._raw_config["filters"]
]
# Instantiate with path
config = UiConfig("config.yaml")
print(config.app_name)
print(config) # Beautiful formatted output
Environment Variables
Basic Usage
from configplusplus import env
# String (default)
DATABASE_HOST = env("DATABASE_HOST")
# Integer
DATABASE_PORT = env("DATABASE_PORT", cast=int)
# Boolean
DEBUG_MODE = env("DEBUG_MODE", cast=bool)
# Float
TEMPERATURE = env("TEMPERATURE", cast=float)
# Path
DATA_DIR = env("DATA_DIR", cast=pathlib.Path)
# With default value
TIMEOUT = env("TIMEOUT", cast=int, default=30)
# Optional (won't raise if missing)
OPTIONAL = env("OPTIONAL", required=False, default=None)
Boolean Casting
When cast=bool, these strings are considered False:
"false","False","FALSE""0""no","No","NO"""(empty string)
All other values are considered True.
Loading .env Files
from configplusplus import safe_load_envs
# Load .env file with logging
safe_load_envs() # Loads from ".env"
# Load from custom path
safe_load_envs("config/.env")
# Silent loading
safe_load_envs(verbose=False)
YAML Configuration
Basic Usage
from configplusplus import YamlConfigLoader
class MyConfig(YamlConfigLoader):
def __post_init__(self) -> None:
# Access raw YAML data
self.database_host = self._raw_config["database"]["host"]
self.database_port = self._raw_config["database"]["port"]
Helper Methods
config = MyConfig("config.yaml")
# Get values with dot notation
host = config.get("database.host")
port = config.get("database.port")
# Get with default
timeout = config.get("api.timeout", default=30)
# Check if key exists
if config.has("database.host"):
print("Database configured")
# Convert to dictionary
config_dict = config.to_dict()
Advanced Features
Custom Validation
class ValidatedConfig(EnvConfigLoader):
DATABASE_PORT = env("DATABASE_PORT", cast=int)
@classmethod
def validate(cls) -> None:
super().validate()
if cls.DATABASE_PORT < 1024:
raise RuntimeError("DATABASE_PORT must be >= 1024")
# Validate configuration
ValidatedConfig.validate()
Structured Data from YAML
from dataclasses import dataclass
from typing import List
@dataclass
class FilterConfig:
name: str
type: str
enabled: bool = True
class UiConfig(YamlConfigLoader):
def __post_init__(self) -> None:
# Parse list of structured objects
self.filters: List[FilterConfig] = [
FilterConfig(**f)
for f in self._raw_config["filters"]
]
Multiple Configuration Sources
# Combine environment and YAML configs
class AppConfig(EnvConfigLoader):
# From environment
SECRET_API_KEY = env("SECRET_API_KEY")
DATABASE_HOST = env("DATABASE_HOST")
# Load YAML for features
@classmethod
def load_features(cls) -> None:
yaml_config = YamlConfigLoader("features.yaml")
cls.FEATURES = yaml_config.get("features")
AppConfig.load_features()
Secret Masking
Variables containing these keywords are automatically masked in output:
SECRETAPI_KEYPASSWORDTOKENCREDENTIAL
Example:
SECRET_API_KEY = "sk_live_abc123xyz789"
# Output: "sk_...89 (hidden)"
PASSWORD = "short"
# Output: "***hidden***"
Configuration Grouping
Configuration values are automatically grouped by prefix:
class AppConfig(EnvConfigLoader):
DATABASE_HOST = env("DATABASE_HOST")
DATABASE_PORT = env("DATABASE_PORT", cast=int)
API_ENDPOINT = env("API_ENDPOINT")
API_KEY = env("API_KEY")
Output shows grouped display:
โถ DATABASE
DATABASE_HOST = 'localhost'
DATABASE_PORT = 5432
โถ API
API_ENDPOINT = 'https://api.example.com'
API_KEY = 'key...23 (hidden)'
Real-World Examples
FastAPI Application Config
from configplusplus import EnvConfigLoader, env, safe_load_envs
import pathlib
safe_load_envs()
class APIConfig(EnvConfigLoader):
# Server
HOST = env("HOST", default="0.0.0.0")
PORT = env("PORT", cast=int, default=8000)
# Database
DATABASE_URL = env("DATABASE_URL")
DATABASE_POOL_SIZE = env("DATABASE_POOL_SIZE", cast=int, default=10)
# Redis
REDIS_HOST = env("REDIS_HOST", default="localhost")
REDIS_PORT = env("REDIS_PORT", cast=int, default=6379)
# Security
SECRET_JWT_KEY = env("SECRET_JWT_KEY")
TOKEN_EXPIRE_MINUTES = env("TOKEN_EXPIRE_MINUTES", cast=int, default=60)
# Features
ENABLE_CORS = env("ENABLE_CORS", cast=bool, default=True)
ENABLE_DOCS = env("ENABLE_DOCS", cast=bool, default=False)
@classmethod
def validate(cls) -> None:
if cls.PORT < 1024 or cls.PORT > 65535:
raise RuntimeError("Invalid PORT")
# Use in FastAPI
from fastapi import FastAPI
app = FastAPI(
title="My API",
docs_url="/docs" if APIConfig.ENABLE_DOCS else None,
)
Document Processing Pipeline Config
from configplusplus import YamlConfigLoader
from typing import List
from dataclasses import dataclass
@dataclass
class ProcessorConfig:
name: str
enabled: bool
priority: int
class PipelineConfig(YamlConfigLoader):
def __post_init__(self) -> None:
# Parse processors
self.processors: List[ProcessorConfig] = [
ProcessorConfig(**p)
for p in self._raw_config["processors"]
]
# Parse paths
self.input_dir = pathlib.Path(self._raw_config["paths"]["input"])
self.output_dir = pathlib.Path(self._raw_config["paths"]["output"])
# Parse settings
self.batch_size = self._raw_config["settings"]["batch_size"]
self.max_workers = self._raw_config["settings"]["max_workers"]
# Load configuration
config = PipelineConfig("pipeline.yaml")
# Use in pipeline
for processor in sorted(config.processors, key=lambda x: x.priority):
if processor.enabled:
print(f"Running {processor.name}")
Documentation
- Quick Reference: See REFERENCE.md for a cheat sheet
- Detailed Guide: See USAGE.md for comprehensive documentation
- Examples: Check the
examples/directory for working code samples
Links
- PyPI: https://pypi.org/project/configplusplus/
- GitHub: https://github.com/Florian-BARRE/ConfigPlusPlus
- Issues: https://github.com/Florian-BARRE/ConfigPlusPlus/issues
License
MIT License - See LICENSE file for details.
Author: Florian BARRE
Project details
Release history Release notifications | RSS feed
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 configplusplus-0.1.1.tar.gz.
File metadata
- Download URL: configplusplus-0.1.1.tar.gz
- Upload date:
- Size: 11.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
80b618c059bf9b71e67b8490bf6b0c6d77620eb33d92bdac08725347f6131fe2
|
|
| MD5 |
a13a7d385b3620a876a73ce7c48521f0
|
|
| BLAKE2b-256 |
535ba2b8fc6b5ce248b919f7ad160fb09388403f62518dd6a89cfe4afe8f96b2
|
Provenance
The following attestation bundles were made for configplusplus-0.1.1.tar.gz:
Publisher:
publish.yml on Florian-BARRE/ConfigPlusPlus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
configplusplus-0.1.1.tar.gz -
Subject digest:
80b618c059bf9b71e67b8490bf6b0c6d77620eb33d92bdac08725347f6131fe2 - Sigstore transparency entry: 947435158
- Sigstore integration time:
-
Permalink:
Florian-BARRE/ConfigPlusPlus@8036093db0330aa565779595f3d754bea5e08486 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/Florian-BARRE
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8036093db0330aa565779595f3d754bea5e08486 -
Trigger Event:
push
-
Statement type:
File details
Details for the file configplusplus-0.1.1-py3-none-any.whl.
File metadata
- Download URL: configplusplus-0.1.1-py3-none-any.whl
- Upload date:
- Size: 12.5 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 |
78da6ee3c4e84cdce46eead581ebd9999137fecb31cc1cd53f6d1668abb7a385
|
|
| MD5 |
676ee8df9be2d2728d83cb3af0622b0e
|
|
| BLAKE2b-256 |
e6973adb7f0cb39b319dd3f9aea0caca8d89f95615d083d70f9b85d2cee33d42
|
Provenance
The following attestation bundles were made for configplusplus-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on Florian-BARRE/ConfigPlusPlus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
configplusplus-0.1.1-py3-none-any.whl -
Subject digest:
78da6ee3c4e84cdce46eead581ebd9999137fecb31cc1cd53f6d1668abb7a385 - Sigstore transparency entry: 947435163
- Sigstore integration time:
-
Permalink:
Florian-BARRE/ConfigPlusPlus@8036093db0330aa565779595f3d754bea5e08486 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/Florian-BARRE
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8036093db0330aa565779595f3d754bea5e08486 -
Trigger Event:
push
-
Statement type: