0
# YACS
1
2
YACS (Yet Another Configuration System) is a lightweight Python library for defining and managing system configurations in scientific experimentation and machine learning research. It provides a simple, YAML-based serialization format for reproducible experimental configurations with support for command line overrides and both local variable and global singleton usage patterns.
3
4
## Package Information
5
6
- **Package Name**: yacs
7
- **Language**: Python
8
- **Installation**: `pip install yacs`
9
- **Dependencies**: PyYAML
10
11
## Core Imports
12
13
```python
14
from yacs.config import CfgNode as CN
15
```
16
17
Alternative import for backward compatibility:
18
19
```python
20
from yacs.config import load_cfg
21
```
22
23
## Basic Usage
24
25
```python
26
from yacs.config import CfgNode as CN
27
28
# Create a configuration node
29
cfg = CN()
30
31
# Set configuration values
32
cfg.SYSTEM = CN()
33
cfg.SYSTEM.NUM_GPUS = 8
34
cfg.SYSTEM.NUM_WORKERS = 4
35
36
cfg.TRAIN = CN()
37
cfg.TRAIN.HYPERPARAMETER_1 = 0.1
38
cfg.TRAIN.SCALES = (2, 4, 8, 16)
39
40
# Merge from YAML file
41
cfg.merge_from_file("experiment.yaml")
42
43
# Merge from command line arguments
44
opts = ["SYSTEM.NUM_GPUS", 2, "TRAIN.SCALES", "(1, 2, 4)"]
45
cfg.merge_from_list(opts)
46
47
# Freeze configuration to prevent modifications
48
cfg.freeze()
49
50
# Access values using attribute or dictionary syntax
51
print(f"Using {cfg.SYSTEM.NUM_GPUS} GPUs")
52
print(f"Training scales: {cfg.TRAIN.SCALES}")
53
54
# Clone configuration for variations
55
cfg2 = cfg.clone()
56
cfg2.defrost()
57
cfg2.TRAIN.HYPERPARAMETER_1 = 0.2
58
cfg2.freeze()
59
```
60
61
## Architecture
62
63
YACS uses a single main class `CfgNode` that extends Python's built-in `dict` with additional configuration management capabilities:
64
65
- **Attribute Access**: Access configuration values using both dictionary keys and object attributes
66
- **Immutability**: Freeze/defrost configurations to control modification
67
- **Hierarchical Structure**: Nested configurations using recursive CfgNode instances
68
- **Type Validation**: Ensures configuration values are of valid types
69
- **Serialization**: YAML-based serialization for human-readable configuration files
70
71
## Capabilities
72
73
### Configuration Creation and Management
74
75
Create and manage hierarchical configuration structures with support for nested values and type validation.
76
77
```python { .api }
78
class CfgNode(dict):
79
"""
80
Configuration node that extends dict with additional configuration management capabilities.
81
82
Class Constants:
83
- IMMUTABLE: "__immutable__" - Key for storing immutability state
84
- DEPRECATED_KEYS: "__deprecated_keys__" - Key for storing deprecated keys set
85
- RENAMED_KEYS: "__renamed_keys__" - Key for storing renamed keys mapping
86
- NEW_ALLOWED: "__new_allowed__" - Key for storing new key allowance flag
87
"""
88
89
def __init__(self, init_dict=None, key_list=None, new_allowed=False):
90
"""
91
Create a configuration node.
92
93
Parameters:
94
- init_dict (dict, optional): Initial dictionary to populate the CfgNode
95
- key_list (list[str], optional): List of names indexing this CfgNode from root
96
- new_allowed (bool): Whether adding new keys is allowed when merging
97
"""
98
```
99
100
### Configuration Merging
101
102
Merge configurations from various sources including YAML files, Python files, other CfgNode objects, and command line arguments.
103
104
```python { .api }
105
def merge_from_file(self, cfg_filename):
106
"""
107
Load a YAML or Python config file and merge it into this CfgNode.
108
109
Parameters:
110
- cfg_filename (str): Path to config file (.yaml, .yml, or .py)
111
"""
112
113
def merge_from_other_cfg(self, cfg_other):
114
"""
115
Merge another CfgNode into this CfgNode.
116
117
Parameters:
118
- cfg_other (CfgNode): Configuration to merge
119
"""
120
121
def merge_from_list(self, cfg_list):
122
"""
123
Merge config from key-value pairs list (e.g., from command line).
124
125
Parameters:
126
- cfg_list (list): Alternating keys and values, e.g., ['FOO.BAR', 0.5, 'BAZ', 'value']
127
"""
128
```
129
130
### State Management
131
132
Control configuration mutability and create independent copies.
133
134
```python { .api }
135
def freeze(self):
136
"""Make this CfgNode and all children immutable."""
137
138
def defrost(self):
139
"""Make this CfgNode and all children mutable."""
140
141
def is_frozen(self):
142
"""
143
Check if configuration is frozen.
144
145
Returns:
146
bool: True if frozen, False if mutable
147
"""
148
149
def clone(self):
150
"""
151
Create a deep copy of this CfgNode.
152
153
Returns:
154
CfgNode: Independent copy of the configuration
155
"""
156
```
157
158
### Serialization
159
160
Convert configurations to and from YAML format for storage and human readability.
161
162
```python { .api }
163
def dump(self, **kwargs):
164
"""
165
Serialize configuration to YAML string.
166
167
Parameters:
168
**kwargs: Additional arguments passed to yaml.safe_dump()
169
170
Returns:
171
str: YAML representation of the configuration
172
"""
173
174
@classmethod
175
def load_cfg(cls, cfg_file_obj_or_str):
176
"""
177
Load configuration from file object or YAML string.
178
179
Parameters:
180
- cfg_file_obj_or_str (str or file): YAML string, file object, or Python source file
181
- For strings: parsed as YAML
182
- For file objects: loaded based on extension (.yaml/.yml/.py)
183
- For .py files: must export 'cfg' attribute as dict or CfgNode
184
185
Returns:
186
CfgNode: Loaded configuration
187
"""
188
```
189
190
### Deprecated and Renamed Key Management
191
192
Handle configuration evolution by managing deprecated and renamed keys.
193
194
```python { .api }
195
def register_deprecated_key(self, key):
196
"""
197
Register a key as deprecated. Deprecated keys are ignored during merging with a warning.
198
199
Parameters:
200
- key (str): Fully-qualified key to deprecate (e.g., 'SECTION.SUBSECTION.KEY')
201
"""
202
203
def register_renamed_key(self, old_name, new_name, message=None):
204
"""
205
Register a key as renamed. Raises error when old key is used.
206
207
Parameters:
208
- old_name (str): Old fully-qualified key name
209
- new_name (str): New fully-qualified key name
210
- message (str, optional): Additional message for the user
211
"""
212
213
def key_is_deprecated(self, full_key):
214
"""
215
Check if a key is deprecated.
216
217
Parameters:
218
- full_key (str): Fully-qualified key to check
219
220
Returns:
221
bool: True if key is deprecated
222
"""
223
224
def key_is_renamed(self, full_key):
225
"""
226
Check if a key has been renamed.
227
228
Parameters:
229
- full_key (str): Fully-qualified key to check
230
231
Returns:
232
bool: True if key has been renamed
233
"""
234
235
def raise_key_rename_error(self, full_key):
236
"""
237
Raise a KeyError for a renamed key with helpful migration message.
238
239
Parameters:
240
- full_key (str): The old key name that was used
241
242
Raises:
243
KeyError: With message indicating the old and new key names
244
"""
245
```
246
247
### Magic Methods and Attribute Access
248
249
Support for Python magic methods enabling dict-like and attribute-like access patterns.
250
251
```python { .api }
252
def __getattr__(self, name):
253
"""
254
Enable attribute-style access to configuration values.
255
256
Parameters:
257
- name (str): Attribute name to access
258
259
Returns:
260
Any: Value stored at the key
261
262
Raises:
263
AttributeError: If key does not exist
264
"""
265
266
def __setattr__(self, name, value):
267
"""
268
Enable attribute-style assignment of configuration values.
269
270
Parameters:
271
- name (str): Attribute name to set
272
- value (Any): Value to assign (must be valid YACS type)
273
274
Raises:
275
AttributeError: If CfgNode is frozen or name conflicts with internal state
276
"""
277
278
def __str__(self):
279
"""
280
Return human-readable string representation of the configuration.
281
282
Returns:
283
str: Formatted configuration tree
284
"""
285
286
def __repr__(self):
287
"""
288
Return detailed string representation for debugging.
289
290
Returns:
291
str: Debug representation showing class name and dict contents
292
"""
293
```
294
295
### New Key Control
296
297
Control whether new keys can be added during configuration merging.
298
299
```python { .api }
300
def is_new_allowed(self):
301
"""
302
Check if new keys are allowed.
303
304
Returns:
305
bool: True if new keys can be added during merging
306
"""
307
308
def set_new_allowed(self, is_new_allowed):
309
"""
310
Set whether new keys are allowed recursively.
311
312
Parameters:
313
- is_new_allowed (bool): Whether to allow new keys
314
"""
315
```
316
317
### Internal Methods
318
319
Advanced methods for internal configuration processing and tree creation.
320
321
```python { .api }
322
@classmethod
323
def _create_config_tree_from_dict(cls, dic, key_list):
324
"""
325
Create a configuration tree from a dictionary, converting nested dicts to CfgNodes.
326
327
Parameters:
328
- dic (dict): Dictionary to convert
329
- key_list (list[str]): List of keys for error reporting
330
331
Returns:
332
dict: Dictionary with nested dicts converted to CfgNodes
333
"""
334
335
@classmethod
336
def _decode_cfg_value(cls, value):
337
"""
338
Decode a raw config value into a Python object.
339
340
Parameters:
341
- value (Any): Raw value from YAML/command line (dict, str, or other)
342
343
Returns:
344
Any: Decoded Python object (CfgNode for dicts, evaluated literals for strings)
345
"""
346
347
def _immutable(self, is_immutable):
348
"""
349
Recursively set immutability state for this CfgNode and all children.
350
351
Parameters:
352
- is_immutable (bool): Whether to make the configuration immutable
353
"""
354
```
355
356
## Module Functions
357
358
### Configuration Loading
359
360
```python { .api }
361
def load_cfg(cfg_file_obj_or_str):
362
"""
363
Load configuration from file object or YAML string (backward compatibility alias).
364
365
Parameters:
366
- cfg_file_obj_or_str (str or file): YAML string, file object, or Python source file
367
368
Returns:
369
CfgNode: Loaded configuration
370
"""
371
```
372
373
## Configuration File Formats
374
375
### YAML Files
376
377
YACS supports YAML configuration files with nested structure:
378
379
```yaml
380
SYSTEM:
381
NUM_GPUS: 2
382
NUM_WORKERS: 4
383
TRAIN:
384
HYPERPARAMETER_1: 0.1
385
SCALES: [2, 4, 8, 16]
386
MODEL:
387
TYPE: "resnet50"
388
```
389
390
### Python Files
391
392
Python configuration files must export a `cfg` variable of type `dict` or `CfgNode`:
393
394
```python
395
from yacs.config import CfgNode as CN
396
397
cfg = CN()
398
cfg.TRAIN = CN()
399
cfg.TRAIN.HYPERPARAMETER_1 = 0.9
400
cfg.MODEL = CN()
401
cfg.MODEL.TYPE = "modified_model"
402
```
403
404
## Command Line Integration
405
406
YACS makes it easy to override configuration values from command line arguments:
407
408
```python
409
import argparse
410
from yacs.config import CfgNode as CN
411
412
def get_cfg_defaults():
413
cfg = CN()
414
cfg.SYSTEM = CN()
415
cfg.SYSTEM.NUM_GPUS = 8
416
cfg.TRAIN = CN()
417
cfg.TRAIN.LEARNING_RATE = 0.001
418
return cfg
419
420
if __name__ == "__main__":
421
cfg = get_cfg_defaults()
422
cfg.merge_from_file("config.yaml")
423
424
# Parse command line overrides
425
parser = argparse.ArgumentParser()
426
parser.add_argument("--opts", nargs=argparse.REMAINDER,
427
help="Modify config options using the command-line")
428
args = parser.parse_args()
429
430
if args.opts:
431
cfg.merge_from_list(args.opts)
432
433
cfg.freeze()
434
```
435
436
Usage: `python script.py --opts SYSTEM.NUM_GPUS 4 TRAIN.LEARNING_RATE 0.01`
437
438
## Type System
439
440
YACS validates configuration values against a set of allowed types:
441
442
- `str` - String values (including `unicode` in Python 2)
443
- `int` - Integer numbers
444
- `float` - Floating point numbers
445
- `bool` - Boolean values
446
- `list` - Lists of valid types
447
- `tuple` - Tuples of valid types
448
- `NoneType` - None values
449
- `CfgNode` - Nested configuration nodes
450
451
Nested dictionaries are automatically converted to CfgNode objects. Invalid types raise AssertionError during assignment or merging.
452
453
### Supported File Extensions
454
455
YACS supports loading configurations from files with these extensions:
456
457
- **YAML files**: `.yaml`, `.yml`, or no extension (treated as YAML)
458
- **Python files**: `.py` (must export a `cfg` variable)
459
460
## Error Handling
461
462
YACS provides clear error messages for common configuration issues:
463
464
- **KeyError**: Raised when trying to merge non-existent keys
465
- **ValueError**: Raised when type mismatches occur during merging
466
- **AttributeError**: Raised when trying to modify frozen configurations
467
- **AssertionError**: Raised for invalid types or malformed operations
468
469
Deprecated keys generate warnings but don't raise errors, while renamed keys raise KeyError with helpful migration messages.