Reusable pydantic/dataclass-driven configuration framework with an optional Hydra bridge.
Project description
cfgable
English | 简体中文
A small, reusable configuration framework for Python, built on
pydantic. It lets every component declare a single
config object and be constructed uniformly — from Python, from a YAML file, or from
Hydra — with validation happening once at the boundary.
The core depends only on pydantic; the Hydra bridge is optional.
Requirements
- Python 3.8 or newer
- pydantic 2.x
- Hydra support requires the optional
hydraextra
Install
pip install cfgable
pip install "cfgable[hydra]"
From a local checkout, use pip install . for the core package or pip install ".[hydra]" for the optional Hydra bridge.
The idea
- A component's settings are a pydantic model (
*Config), documented with attribute docstrings. - Every class takes one
configparameter and reads fields off it. - Inheriting
ConfigurableBasislets the same class be built from an explicit config, a plain mapping, or flat keyword arguments — the shape Hydra'sinstantiatepasses — because theInitConfigMetametaclass assembles and validates the config for you, then callsconfig_post_init().
from typing import Optional
from pydantic import BaseModel, ConfigDict, PositiveInt
from cfgable import ConfigurableBasis
class CameraConfig(BaseModel, frozen=True):
"""Configuration for a camera."""
model_config = ConfigDict(use_attribute_docstrings=True, extra="forbid")
device: str = "/dev/video0"
"""Video device path."""
fps: PositiveInt = 30
"""Capture rate in frames per second."""
serial: Optional[str] = None
"""Optional camera serial number for disambiguation."""
class Camera(ConfigurableBasis):
"""A camera built from a single validated config."""
def __init__(self, config: CameraConfig):
self.config = config
def config_post_init(self):
super().config_post_init()
self._opened = False
def on_configure(self) -> bool:
self._opened = True
return True
# All three build the same object:
cam = Camera(CameraConfig(fps=60)) # explicit config
cam = Camera({"fps": 60}) # mapping
cam = Camera(fps=60) # flat kwargs (Hydra-style)
Use ConfigurableBasis when the component has a configure lifecycle. For plain
objects that only need config assembly, inherit from InitConfigMixin.
With Hydra
Point _target_ at the class and list the config fields as siblings; the metaclass turns
them into the config model:
# camera.yaml
_target_: my_pkg.Camera
fps: 60
device: /dev/video2
from cfgable.hydra_utils import init_hydra_config, hydra_instance
cam = hydra_instance(init_hydra_config("camera.yaml"))
For plain classes you can also nest the config under its own _target_ so standard
hydra.utils.instantiate builds Camera(config=CameraConfig(...)).
Round-tripping
Because a component keeps its whole config, it can serialize back to the config that
would rebuild it:
cam.dump() # -> dict of fields + a "_target_" pointing at the class
cam.save_config("cam.yaml")
The saved YAML can be loaded again by passing the path back to the component:
cam = Camera("cam.yaml")
What's in the box
ConfigurableBasis,InitConfigMixin,InitConfigABCMixin— base classes for the single-configconstruction protocol.InitConfigMeta/InitConfigABCMeta— the metaclass that assembles configs.NoConfig— placeholder for components that need no settings.StrEnum,ReprEnum— a string-enum backport (use thisStrEnum, notenum.StrEnum, for consistent behavior across Python 3.8–3.13).ForceSetAttr/force_set_attr— controlled mutation of otherwise-frozen configs.import_string,get_fully_qualified_class_name,dump_or_repr,fetch_config.cfgable.hydra_utils—init_hydra_config,hydra_instance,hydra_instance_from_dict,hydra_instance_from_config_path(needs[hydra]).
import cfgable never imports Hydra — the bridge is loaded only when you import
cfgable.hydra_utils.
Development
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest
Contributing
Issues and pull requests are welcome — see CONTRIBUTING.md for the development setup and conventions, and please follow the Code of Conduct. To report a security issue, see SECURITY.md. Release notes are tracked in CHANGELOG.md, and support options are listed in SUPPORT.md.
License
Released under the MIT License.
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 cfgable-0.1.1.tar.gz.
File metadata
- Download URL: cfgable-0.1.1.tar.gz
- Upload date:
- Size: 486.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dab5a6bcaaff4b81cee3e38290a81e41da353c1ad0d12529524d813eee5a6010
|
|
| MD5 |
20707ec7c53d906eda7025e36b6f033f
|
|
| BLAKE2b-256 |
c06724736737f6c8b83b46d367dab12bc2a534abd26fa52369a72404137e2767
|
File details
Details for the file cfgable-0.1.1-py3-none-any.whl.
File metadata
- Download URL: cfgable-0.1.1-py3-none-any.whl
- Upload date:
- Size: 14.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86589dbdead48aaedb4ba671eea41f07eec864958e2326577ca0ac0b5b5ccba5
|
|
| MD5 |
226a9ee31539dfc4d3c916489a80db39
|
|
| BLAKE2b-256 |
9cf9a071252729e5ea6a830ab21b1bafb5956348869dde74b3b26cbf47050f25
|