A robust, schema-driven configuration management library for Python with encryption, versioning, nested sections, and multiple backends.
Project description
ConfigGuard
Stop fighting inconsistent, error-prone, and insecure configuration files! 🚀
ConfigGuard transforms your Python application's configuration management from a potential source of bugs and security risks into a robust, reliable, and developer-friendly system. Moving beyond simple dictionaries or basic file parsing, ConfigGuard introduces a schema-driven fortress for your settings, offering unparalleled control and safety.
Leverage a comprehensive suite of features designed for modern applications:
- Define strict Type Safety and complex Validation Rules (
min,max,options,nullable). - Protect sensitive data effortlessly with built-in, handler-transparent Encryption.
- Manage configuration changes across application updates with seamless Versioning (using standard
__version__key) and automated Migration (with optional automatic file updates). - Choose your preferred Storage Format (JSON, YAML, TOML, SQLite included) without altering your core logic.
- Organize complex configurations intuitively using Nested Sections.
- Accommodate unpredictable structures with flexible Dynamic Sections.
Why waste time debugging subtle configuration typos or managing insecure secrets manually? ConfigGuard catches errors early, simplifies maintenance, and secures your sensitive data, allowing you to focus on building great features.
Adopt ConfigGuard and configure with confidence!
✨ Key Features
- 📝 Schema-Driven: Define your configuration's expected structure, types, defaults, and validation rules within a Python dictionary or a JSON file. This acts as the single source of truth, ensuring consistency and enabling static analysis benefits. Use the standard
__version__key for robust version tracking, or override with theinstance_versionparameter during initialization. - <0xF0><0x9F><0xA7><0xB1> Nested Configuration: Structure complex settings logically using sections, defined directly within your schema (
"type": "section"). Access nested settings intuitively through standard attribute or dictionary notation (e.g.,config.database.connection.pool_size,config['server']['ssl']['enabled']). - <0xF0><0x9F><0x94><0x91> Dynamic Sections: Define sections with an empty schema (
"schema": {}) to allow adding/removing arbitrary key-value pairs at runtime, bypassing schema validation for those items while still benefiting from saving, loading, and encryption. - 🔒 Built-in Encryption: Secure sensitive configuration values transparently using Fernet symmetric encryption (requires
cryptography). Encryption is handled automatically by the storage backend during save/load operations. - 💾 Multiple Backends: Persist configurations in various formats (JSON, YAML, TOML, SQLite). ConfigGuard automatically detects the format based on the file extension.
- 🔄 Versioning & Migration: Embed a version string (e.g.,
"1.2.0") using the standard__version__key or provide it viainstance_version. ConfigGuard compares file version with instance version duringload(), preventing loading of newer configurations and migrating older ones (merging existing values, applying new defaults, skipping removed items). Migration operates recursively through nested sections. Optionally auto-save the migrated configuration back to the file usingload(update_file=True). - <0xF0><0x9F><0x97><0x84>️ Standardized Save/Export Keys: Uses consistent keys for metadata:
__version__: Holds the configuration version. Included in bothvaluesandfullsave modes.__schema__: Holds the schema definition. Included only inmode='full'saves and exports.__settings__: Holds the configuration values structure. Included only inmode='full'saves and exports.
- <0xF0><0x9F><0x97><0x84>️ Flexible Save Modes: Control the granularity of saved data:
mode='values'(default): Saves only the current configuration key-value pairs, prepended with the__version__key.mode='full': Saves the complete state using standard keys:__version__,__schema__, and__settings__.
- <0xF0><0x9F><0xA7><0xB1> Supported Types: Define settings with standard Python types:
str,int,float,bool,list. Dynamic sections can store any JSON-serializable type. - 🐍 Intuitive Access: Interact naturally via attribute (
config.section.setting) or dictionary (config['section']['setting']) syntax. Retrieve schema details usingconfig.sc_section.sc_setting. Usesection.get_schema_dict()andsection.get_config_dict()for section introspection. - ✔️ Automatic Validation: Validates values against schema rules on modification or load for standard settings. Dynamic section values bypass schema validation.
- 📤 Easy Export/Import:
export_schema_with_values(): Get a snapshot using standard keys (__version__,__schema__,__settings__).import_config(data, ignore_unknown=True): Update values from a dictionary, merging data, validating standard settings, and adding/updating dynamic keys. Ignores__version__key in inputdata.
- 🧩 Extensible: Implement custom
StorageHandlerclasses for additional backends.
🤔 Why Choose ConfigGuard?
(Reasons remain largely the same, but updated phrasing for versioning/keys)
- Eliminate Runtime Config Errors: Catch errors early with schema validation.
- Secure Your Secrets with Ease: Integrated, transparent encryption.
- Future-Proof Your Application: Versioning (
__version__) allows confident schema updates. Migration handles older files, andload(update_file=True)can automatically bring them up-to-date. - Improve Code Clarity and Maintainability: Schemas act as self-documentation. Standard keys (
__version__,__schema__,__settings__) provide predictable structure. - Manage Complexity Effectively: Organize settings with nested and dynamic sections.
- Increase Developer Productivity: Reduces boilerplate for parsing, validation, defaults, and encryption.
- Gain Storage Freedom: Switch backends (JSON, YAML, TOML, SQLite) easily.
🚀 Installation
(Installation instructions remain the same)
# Base
pip install configguard
# Extras (encryption, yaml, toml, all, dev)
pip install configguard[encryption]
pip install configguard[yaml]
pip install configguard[toml]
pip install configguard[all]
# For development
git clone https://github.com/ParisNeo/ConfigGuard.git
cd ConfigGuard
pip install -e .[dev]
⚡ Quick Start
from configguard import ConfigGuard, ValidationError, generate_encryption_key
from pathlib import Path
import typing
# 1. Define schema with standard __version__ key
SCHEMA_VERSION = "1.1.0"
my_schema: typing.Dict[str, typing.Any] = {
"__version__": SCHEMA_VERSION,
# ... (rest of schema definition as before) ...
"server": {
"type": "section", "help": "Core web server settings.",
"schema": {
"host": { "type": "str", "default": "127.0.0.1", "help": "IP address to bind to." },
"port": { "type": "int", "default": 8080, "min_val": 1024, "max_val": 65535, "help": "Port number." }
}
},
"plugin_data": { "type": "section", "schema": {}, "help": "Dynamic data."}, # Dynamic
"log_level": { "type": "str", "default": "INFO", "options": [...], "help": "Verbosity."}
}
# 2. Setup
config_file = Path("my_app_config.yaml")
encryption_key = generate_encryption_key()
# 3. Initialize (using schema version in this case)
try:
config = ConfigGuard(
schema=my_schema,
config_path=config_file,
encryption_key=encryption_key
)
print(f"Initialized with Version: {config.version}") # -> 1.1.0
# Handle missing dependencies
except ImportError as e: print(f"ERROR: Missing dependency for {config_file.suffix}: {e}"); exit()
except Exception as e: print(f"ERROR: Failed to initialize: {e}"); exit()
# 4. Access defaults
print(f"Initial Host: {config.server.host}") # -> '127.0.0.1'
# 5. Modify values
config.server.port = 9090
config.plugin_data['active'] = True # Dynamic add
# 6. Save configuration (values mode)
# This will save {'__version__': '1.1.0', 'server': {'host': ..., 'port': 9090}, ...}
config.save()
print(f"Config saved to {config_file} (encrypted, with version key).")
# To save full state (version, schema, settings) using standard keys:
# config.save(mode='full', filepath='my_app_config_full.yaml')
# 7. Load older version and auto-update file (Example)
# Assume 'old_config_v1.yaml' exists (saved with version 1.0.0)
# try:
# print("\nLoading old config with auto-update...")
# # Load V1 data into V1.1.0 instance, triggering migration and save
# config_migrated = ConfigGuard(
# schema=my_schema, # V1.1.0 schema
# config_path="old_config_v1.yaml",
# load_options={'update_file': True} # <--- Enable auto-save on migrate
# )
# # Now 'old_config_v1.yaml' should contain migrated data with '__version__': '1.1.0'
# print(f"Loaded and potentially updated file. New instance version: {config_migrated.version}")
# except Exception as e:
# print(f"Error during migration load: {e}")
📚 Core Concepts Detailed
- Schema: Definition using Python dict or JSON.
- Versioning: Use
__version__key in schema orinstance_versionparameter (priority). Standardpackagingformat. Defaults to"0.0.0". - Standard Keys:
__version__,__schema__,__settings__used for save/export structure. - Sections & Dynamic Sections: As before (
"type": "section","schema": {}).
- Versioning: Use
- ConfigGuard Object: Main interaction point. Version set at init. Handles load/save/access.
- ConfigSection Object: Represents nested sections. Access/modify contents.
get_schema_dict()/get_config_dict(). - Dynamic Sections: Flexible key-value stores within the config.
- Storage Handlers: Abstract persistence (JSON, YAML, TOML, SQLite built-in). Handle standard keys and encryption.
- Save Modes (
valuesvsfull):mode='values': Saves__version__+ config values structure.mode='full': Saves__version__,__schema__,__settings__.
- Versioning & Migration: Compares instance vs file
__version__. Migrates older files.load(update_file=True)saves migrated state back to file invaluesmode. - Encryption: Fernet-based, transparent via handlers.
📖 Detailed Usage
1. Defining the Schema
(Use __version__ standard key)
# Example schema definition (use __version__)
schema_v3 = {
"__version__": "3.0.0",
# ... rest of complex_schema definition ...
}
2. Initializing ConfigGuard
(Pass schema, path, key, optional instance_version, load_options)
# Example init with auto-update on migration enabled
config = ConfigGuard(
schema=schema_v3,
config_path="app_v3.db",
encryption_key=enc_key,
load_options={'update_file': True} # Enable save on migrate
)
3. Accessing Settings and Schema
(Remains the same: config.section.setting, config['section']['setting'], config.sc_section.sc_setting)
4. Modifying Settings
(Remains the same: attribute/item assignment triggers validation)
5. Working with Sections: Introspection
(Remains the same: section.get_schema_dict(), section.get_config_dict())
6. Saving & Loading
save() uses standard keys based on mode. load() detects standard/legacy keys and structure. load(update_file=True) triggers save after migration.
# Save values (includes __version__)
config.save() # or config.save(mode='values')
# Save full state (__version__, __schema__, __settings__)
config.save(mode='full', filepath='backup.json')
# Load (will check standard keys first)
try:
config.load() # Load from default path
# Load older file and update it automatically
config.load(filepath='old_config.toml', update_file=True)
except Exception as e:
print(f"Load failed: {e}")
7. Versioning & Migration
(Mostly automatic. Use load(update_file=True) to persist migrated state).
8. Encryption
(Remains the same: provide key at init)
9. Handling Nested Configurations
(Remains the same: access follows structure)
10. Import/Export
export_schema_with_values() uses standard keys. import_config() ignores __version__ in input data.
# Export (uses __version__, __schema__, __settings__)
full_state = config.export_schema_with_values()
# print(json.dumps(full_state, indent=2))
# Import (input data should be value structure, __version__ ignored)
update_data = {
"server": {"port": 8888},
"__version__": "ignored", # This key is skipped on import
# ... other values ...
}
config.import_config(update_data)
💡 Use Cases
(Use cases remain the same)
🔧 Advanced Topics
(Advanced topics remain the same, focusing on custom handlers and potential future features)
🤝 Contributing
(Contributing guidelines remain the same)
📜 License
(License remains the same: Apache 2.0)
Built with ❤️ by ParisNeo with the help of Gemini 2.5
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 configguard-0.6.1.tar.gz.
File metadata
- Download URL: configguard-0.6.1.tar.gz
- Upload date:
- Size: 50.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.0.1 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce262d265e020568d59a4a8b6b008ee38b104c995ca0f717bf088c13619100d0
|
|
| MD5 |
e3c3cb80f70040c36799246d0adf9533
|
|
| BLAKE2b-256 |
15b0569a565fdb340ef54a0383281c1fcb31e6c93bed8eaade57a2b6c3520b6c
|
File details
Details for the file configguard-0.6.1-py3-none-any.whl.
File metadata
- Download URL: configguard-0.6.1-py3-none-any.whl
- Upload date:
- Size: 54.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.0.1 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63603973736152dc2c1a994ddbeced823e19b5337439a79e100641c984d16daf
|
|
| MD5 |
f4a7d4177b02e023338bb4e1f0324f87
|
|
| BLAKE2b-256 |
e81afd8e8180aa625428513a20fda2b63f9cb4ec3f89ee5ca131cb0a7f79b4be
|