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.
Metadata
Release files for cfgable 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| cfgable-0.1.1.tar.gz | 486.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cfgable-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 500.5 kB
Release files / cfgable-0.1.1.tar.gz
| Download URL | cfgable-0.1.1.tar.gz |
|---|---|
| Size | 486.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dab5a6bcaaff4b81cee3e38290a81e41da353c1ad0d12529524d813eee5a6010
|
|
BLAKE2b-256 checksum How to use checksums |
c06724736737f6c8b83b46d367dab12bc2a534abd26fa52369a72404137e2767
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.8.18
|
Release files / cfgable-0.1.1-py3-none-any.whl
| Download URL | cfgable-0.1.1-py3-none-any.whl |
|---|---|
| Size | 14.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
86589dbdead48aaedb4ba671eea41f07eec864958e2326577ca0ac0b5b5ccba5
|
|
BLAKE2b-256 checksum How to use checksums |
9cf9a071252729e5ea6a830ab21b1bafb5956348869dde74b3b26cbf47050f25
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.8.18
|
Security for cfgable 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.