YAML Configuration Manager
Yacman is a Python library designed for managing YAML configuration files. It provides a robust YAML configuration manager with features for merging multiple configuration layers, validation, and atomic updates. The library recently released version 1.0.0, which introduced significant changes to constructor patterns and enhanced multi-process locking mechanisms, and maintains a consistent release cadence with active development.
Common errors
-
AttributeError: module 'yacman' has no attribute 'FutureYAMLConfigManager'
cause Attempting to import `FutureYAMLConfigManager` from `yacman` in version 1.0.0 or later, where this class has been removed.fixRemove the `FutureYAMLConfigManager` import. In yacman v1.0.0, simply use `from yacman import YAMLConfigManager`. -
TypeError: YAMLConfigManager.__init__() got an unexpected keyword argument 'data' (or similar error when passing a dict to constructor)
cause Attempting to initialize `YAMLConfigManager` by directly passing data or a filepath to its constructor in v1.0.0+, which expects specific `from_x` class methods.fixUse the appropriate class method for initialization, e.g., `ym = YAMLConfigManager.from_dict(data)` for dictionary input or `ym = YAMLConfigManager.from_file('path/to/config.yaml')` for file input. -
RuntimeError: Attempted to write to a Yacman object that is not locked for writing.
cause Trying to call `write()` on a `YAMLConfigManager` object in v1.0.0+ without first acquiring a `write_lock` through its context manager.fixEnsure all write operations are performed within a `with write_lock(ym) as locked_ym:` block. For example, `with write_lock(ym) as locked_ym: locked_ym.rebase_and_write()`.
Warnings
- breaking In yacman v1.0.0, the constructors for `YAMLConfigManager` have changed. Instead of direct instantiation like `YAMLConfigManager(data)`, you should now use class methods like `YAMLConfigManager.from_dict(data)` or `YAMLConfigManager.from_file(filepath)` to make the source of the configuration clearer.
- breaking The locking mechanism in yacman v1.0.0 has been significantly refactored. The `with ym as locked_ym: locked_ym.write()` pattern from v0.x is no longer valid. Instead, explicit `read_lock` and `write_lock` context managers are required.
- deprecated The `FutureYAMLConfigManager` class and its use as `from yacman import FutureYAMLConfigManager as YAMLConfigManager` have been removed in v1.0.0. The standard `YAMLConfigManager` now incorporates those features.
- gotcha When writing to a configuration file in a multi-process environment with `yacman v1.0.0`, it is crucial to rebase your configuration before writing to ensure you incorporate any changes made by other processes since you last read the file. Not doing so can lead to data loss or inconsistencies.
Install
-
pip install yacman
Imports
- YAMLConfigManager
from yacman import FutureYAMLConfigManager as YAMLConfigManager
from yacman import YAMLConfigManager
- read_lock, write_lock
from yacman import read_lock, write_lock
Quickstart
import os
from yacman import YAMLConfigManager, write_lock, read_lock
# Example data
data = {"my_list": [1,2,3], "my_int": 8, "my_str": "hello world!", "my_dict": {"nested_val": 15}}
# Create a YAMLConfigManager from a dictionary
ym = YAMLConfigManager(data)
# Access data like a dictionary
print(f"my_list: {ym['my_list']}")
print(f"my_int: {ym['my_int']}")
print(f"nested_val: {ym['my_dict']['nested_val']}")
# Modify data
ym["new_var"] = 15
# To write changes to a file, use a write_lock context manager
# and explicitly rebase_and_write for multi-process safety.
# For a real scenario, you would create ym from a file path: ym = YAMLConfigManager(filepath='config.yaml')
# For this quickstart, we'll simulate writing to a dummy file.
config_file_path = "./temp_config.yaml"
with open(config_file_path, 'w') as f:
f.write(str(ym))
# Now, let's load it from the file and demonstrate writing safely
ym_from_file = YAMLConfigManager(filepath=config_file_path)
# Use a write-lock, and rebase before writing to ensure you capture any changes
# since you loaded the file (important in multi-process environments)
with write_lock(ym_from_file) as locked_ym:
locked_ym['another_key'] = 'another_value'
locked_ym.rebase_and_write()
print(f"Updated config from file: {ym_from_file.to_dict()}")
# Cleanup (optional)
os.remove(config_file_path)