0
# Configuration
1
2
Global configuration management with YAML-based settings, environment variable support, and plugin configuration integration. The configuration system provides flexible, hierarchical settings management for all aspects of beets functionality.
3
4
## Capabilities
5
6
### Global Configuration Object
7
8
The central configuration instance that manages all beets settings.
9
10
```python { .api }
11
config: IncludeLazyConfig # Global configuration object available as beets.config
12
13
class IncludeLazyConfig:
14
"""Configuration class with lazy loading and include support."""
15
16
def read(self, user: bool = True, defaults: bool = True) -> None:
17
"""
18
Read configuration from files.
19
20
Parameters:
21
- user: Whether to read user configuration file
22
- defaults: Whether to read default configuration
23
"""
24
25
def set_file(self, filename: str) -> None:
26
"""
27
Load additional configuration from file.
28
29
Parameters:
30
- filename: Path to YAML configuration file
31
"""
32
33
def set_args(self, args: argparse.Namespace) -> None:
34
"""
35
Set configuration from command-line arguments.
36
37
Parameters:
38
- args: Parsed command-line arguments
39
"""
40
41
def __getitem__(self, key: str) -> ConfigView:
42
"""
43
Get configuration section or value.
44
45
Parameters:
46
- key: Configuration key or section name
47
48
Returns:
49
ConfigView object for further access
50
"""
51
52
def user_config_path(self) -> str:
53
"""
54
Get path to user configuration file.
55
56
Returns:
57
Path to user's config.yaml file
58
"""
59
60
def config_dir(self) -> str:
61
"""
62
Get beets configuration directory path.
63
64
Returns:
65
Path to beets configuration directory
66
"""
67
```
68
69
### Configuration Views
70
71
Objects representing configuration sections and values with type conversion.
72
73
```python { .api }
74
class ConfigView:
75
"""View into configuration hierarchy with type conversion."""
76
77
def get(self, typ: Type = None) -> Any:
78
"""
79
Get configuration value with optional type conversion.
80
81
Parameters:
82
- typ: Type to convert value to (str, int, bool, list, dict)
83
84
Returns:
85
Configuration value converted to specified type
86
"""
87
88
def as_str(self) -> str:
89
"""
90
Get configuration value as string.
91
92
Returns:
93
String representation of configuration value
94
"""
95
96
def as_filename(self) -> str:
97
"""
98
Get configuration value as filename with path expansion.
99
100
Returns:
101
Expanded filename path
102
"""
103
104
def as_str_seq(self, split: bool = True) -> List[str]:
105
"""
106
Get configuration value as list of strings.
107
108
Parameters:
109
- split: Whether to split string values on whitespace/commas
110
111
Returns:
112
List of string values
113
"""
114
115
def __getitem__(self, key: str) -> 'ConfigView':
116
"""
117
Get nested configuration section.
118
119
Parameters:
120
- key: Nested key name
121
122
Returns:
123
ConfigView for nested section
124
"""
125
126
def items(self) -> Iterator[Tuple[str, 'ConfigView']]:
127
"""
128
Iterate over configuration key-value pairs.
129
130
Returns:
131
Iterator of (key, ConfigView) tuples
132
"""
133
134
def keys(self) -> Iterator[str]:
135
"""
136
Get all configuration keys in this section.
137
138
Returns:
139
Iterator over key names
140
"""
141
```
142
143
## Core Configuration Sections
144
145
### Library Configuration
146
147
Settings for database and music directory management.
148
149
```yaml
150
# Library database file path
151
library: ~/.config/beets/musiclibrary.db
152
153
# Root directory for music files
154
directory: ~/Music
155
156
# Path format templates
157
paths:
158
default: $albumartist/$album/$track $title
159
singleton: Non-Album/$artist - $title
160
comp: Compilations/$album/$track $title
161
albumtype:soundtrack: Soundtracks/$album/$track $title
162
albumtype:live: Live/$albumartist/$album/$track $title
163
```
164
165
```python { .api }
166
# Access library configuration
167
from beets import config
168
169
library_path = config['library'].as_filename()
170
music_dir = config['directory'].as_filename()
171
path_formats = config['paths'].get(dict)
172
```
173
174
### Import Configuration
175
176
Settings controlling the import process and metadata handling.
177
178
```yaml
179
import:
180
# Write tags to files after import
181
write: yes
182
183
# Copy files vs move files
184
copy: no
185
186
# Resume interrupted imports
187
resume: ask
188
189
# Skip unchanged directories
190
incremental: no
191
192
# Quiet fallback for timeouts
193
quiet_fallback: skip
194
195
# Default action for ambiguous matches
196
timid: no
197
198
# Enabled metadata sources
199
sources: [filesystem, musicbrainz, discogs]
200
201
# Search by specific IDs
202
search_ids: []
203
```
204
205
```python { .api }
206
# Access import configuration
207
from beets import config
208
209
write_tags = config['import']['write'].get(bool)
210
copy_files = config['import']['copy'].get(bool)
211
resume_mode = config['import']['resume'].get(str)
212
sources = config['import']['sources'].as_str_seq()
213
```
214
215
### UI Configuration
216
217
User interface settings including colors and terminal behavior.
218
219
```yaml
220
ui:
221
# Enable terminal colors
222
color: yes
223
224
# Terminal width override
225
terminal_width: 80
226
227
# Color scheme
228
colors:
229
text_success: [green]
230
text_warning: [yellow]
231
text_error: [red]
232
text_highlight: [bold, blue]
233
action_default: [bold, turquoise]
234
action: [turquoise]
235
```
236
237
```python { .api }
238
# Access UI configuration
239
from beets import config
240
241
color_enabled = config['ui']['color'].get(bool)
242
terminal_width = config['ui']['terminal_width'].get(int)
243
colors = config['ui']['colors'].get(dict)
244
```
245
246
### Plugin Configuration
247
248
Plugin loading and individual plugin settings.
249
250
```yaml
251
plugins:
252
- fetchart
253
- lyrics
254
- discogs
255
- replaygain
256
- web
257
258
# Plugin-specific configuration
259
fetchart:
260
auto: yes
261
sources: coverart lastfm amazon
262
minwidth: 300
263
264
lyrics:
265
auto: yes
266
sources: genius lyricwiki musixmatch
267
268
web:
269
host: 127.0.0.1
270
port: 8337
271
```
272
273
```python { .api }
274
# Access plugin configuration
275
from beets import config
276
277
enabled_plugins = config['plugins'].as_str_seq()
278
fetchart_auto = config['fetchart']['auto'].get(bool)
279
fetchart_sources = config['fetchart']['sources'].as_str_seq()
280
web_host = config['web']['host'].get(str)
281
web_port = config['web']['port'].get(int)
282
```
283
284
## Configuration File Management
285
286
### Configuration File Locations
287
288
```python { .api }
289
# Default configuration file locations
290
# Linux/macOS: ~/.config/beets/config.yaml
291
# Windows: %APPDATA%\beets\config.yaml
292
293
from beets import config
294
295
# Get configuration file path
296
config_path = config.user_config_path()
297
298
# Get configuration directory
299
config_dir = config.config_dir()
300
301
# Get default config values
302
default_config = config.default_config_path()
303
```
304
305
### Loading Configuration
306
307
```python
308
from beets import config
309
310
# Load default configuration
311
config.read()
312
313
# Load additional config file
314
config.set_file('/path/to/additional/config.yaml')
315
316
# Set values from command line
317
import argparse
318
parser = argparse.ArgumentParser()
319
args = parser.parse_args()
320
config.set_args(args)
321
```
322
323
### Include System
324
325
The configuration system supports including other YAML files.
326
327
```yaml
328
# Main config.yaml
329
include:
330
- paths.yaml
331
- plugins.yaml
332
- colors.yaml
333
334
library: ~/.config/beets/musiclibrary.db
335
directory: ~/Music
336
```
337
338
```yaml
339
# paths.yaml
340
paths:
341
default: $albumartist/$album/$track $title
342
classical: Classical/$composer/$album/$track $title
343
344
# plugins.yaml
345
plugins:
346
- fetchart
347
- lyrics
348
- discogs
349
350
fetchart:
351
auto: yes
352
sources: coverart lastfm
353
```
354
355
## Configuration Access Patterns
356
357
### Type-Safe Value Access
358
359
```python
360
from beets import config
361
362
# String values
363
library_path = config['library'].as_filename()
364
music_dir = config['directory'].as_filename()
365
366
# Boolean values
367
write_tags = config['import']['write'].get(bool)
368
color_enabled = config['ui']['color'].get(bool)
369
370
# Integer values
371
terminal_width = config['ui']['terminal_width'].get(int)
372
web_port = config['web']['port'].get(int)
373
374
# List values
375
plugins = config['plugins'].as_str_seq()
376
sources = config['import']['sources'].as_str_seq()
377
378
# Dictionary values
379
paths = config['paths'].get(dict)
380
colors = config['ui']['colors'].get(dict)
381
```
382
383
### Default Values and Fallbacks
384
385
```python
386
from beets import config
387
388
# Provide default values
389
timeout = config['import']['timeout'].get(int, 5)
390
max_width = config['ui']['max_width'].get(int, 80)
391
392
# Check if value exists
393
if 'api_key' in config['discogs']:
394
api_key = config['discogs']['api_key'].get(str)
395
else:
396
print("No Discogs API key configured")
397
398
# Conditional configuration
399
if config['import']['write'].get(bool):
400
# Enable tag writing
401
pass
402
```
403
404
### Plugin Configuration Access
405
406
```python
407
from beets import config
408
from beets.plugins import BeetsPlugin
409
410
class MyPlugin(BeetsPlugin):
411
def __init__(self, name):
412
super().__init__(name)
413
414
# Set plugin defaults
415
config[name].add({
416
'enabled': True,
417
'timeout': 10,
418
'sources': ['default'],
419
})
420
421
def get_config_value(self, key, default=None):
422
"""Get plugin-specific configuration value."""
423
return config[self.name][key].get(default)
424
425
def is_enabled(self):
426
"""Check if plugin is enabled."""
427
return self.get_config_value('enabled', True)
428
```
429
430
## Environment Variable Support
431
432
Configuration values can reference environment variables and support path expansion.
433
434
```yaml
435
# Environment variable expansion
436
library: $BEETS_LIBRARY_PATH
437
directory: $MUSIC_DIR
438
439
# Path expansion
440
library: ~/beets/library.db
441
directory: ~/Music
442
443
# Mixed expansion
444
directory: $HOME/Music/Library
445
```
446
447
```python
448
import os
449
from beets import config
450
451
# Set environment variables
452
os.environ['BEETS_LIBRARY_PATH'] = '/custom/path/library.db'
453
os.environ['MUSIC_DIR'] = '/mnt/music'
454
455
# Configuration will automatically expand these
456
library_path = config['library'].as_filename()
457
# Result: '/custom/path/library.db'
458
```
459
460
## Dynamic Configuration
461
462
### Runtime Configuration Changes
463
464
```python
465
from beets import config
466
467
# Modify configuration at runtime
468
config['import']['write'] = True
469
config['ui']['color'] = False
470
471
# Add new sections
472
config['mycustom'] = {
473
'setting1': 'value1',
474
'setting2': 42
475
}
476
477
# Plugin configuration
478
config['myplugin']['enabled'] = True
479
```
480
481
### Temporary Configuration Context
482
483
```python
484
from beets import config
485
import contextlib
486
487
@contextlib.contextmanager
488
def temp_config(**overrides):
489
"""Temporarily override configuration values."""
490
old_values = {}
491
492
for key, value in overrides.items():
493
old_values[key] = config[key].get()
494
config[key] = value
495
496
try:
497
yield
498
finally:
499
for key, old_value in old_values.items():
500
config[key] = old_value
501
502
# Usage
503
with temp_config(import_write=False, ui_color=True):
504
# Configuration temporarily modified
505
perform_operation()
506
# Configuration restored
507
```
508
509
## Configuration Validation
510
511
### Type Validation
512
513
```python
514
from beets import config
515
import confuse
516
517
def validate_config():
518
"""Validate configuration values."""
519
520
try:
521
# Validate required settings
522
library_path = config['library'].as_filename()
523
if not library_path:
524
raise ValueError("Library path is required")
525
526
# Validate numeric ranges
527
port = config['web']['port'].get(int)
528
if not 1024 <= port <= 65535:
529
raise ValueError(f"Invalid port number: {port}")
530
531
# Validate choices
532
log_level = config['log_level'].get(str, 'INFO')
533
if log_level not in ['DEBUG', 'INFO', 'WARNING', 'ERROR']:
534
raise ValueError(f"Invalid log level: {log_level}")
535
536
except confuse.ConfigError as e:
537
print(f"Configuration error: {e}")
538
raise
539
```
540
541
### Custom Validation
542
543
```python
544
from beets import config
545
from beets.plugins import BeetsPlugin
546
547
class ValidatedPlugin(BeetsPlugin):
548
def __init__(self, name):
549
super().__init__(name)
550
551
# Set defaults with validation
552
config[name].add({
553
'timeout': 10,
554
'retries': 3,
555
'sources': ['default']
556
})
557
558
self.validate_config()
559
560
def validate_config(self):
561
"""Validate plugin configuration."""
562
timeout = config[self.name]['timeout'].get(int)
563
if timeout <= 0:
564
raise ValueError(f"{self.name}: timeout must be positive")
565
566
retries = config[self.name]['retries'].get(int)
567
if retries < 0:
568
raise ValueError(f"{self.name}: retries cannot be negative")
569
570
sources = config[self.name]['sources'].as_str_seq()
571
if not sources:
572
raise ValueError(f"{self.name}: at least one source required")
573
```
574
575
## Error Handling
576
577
```python { .api }
578
class ConfigError(Exception):
579
"""Base exception for configuration errors."""
580
581
class ConfigTypeError(ConfigError):
582
"""Raised when configuration value has wrong type."""
583
584
class ConfigReadError(ConfigError):
585
"""Raised when configuration file cannot be read."""
586
```
587
588
### Configuration Error Examples
589
590
```python
591
from beets import config
592
import confuse
593
594
def safe_config_access():
595
"""Safely access configuration with error handling."""
596
597
try:
598
# Access configuration values
599
library_path = config['library'].as_filename()
600
plugins = config['plugins'].as_str_seq()
601
602
except confuse.NotFoundError:
603
print("Required configuration section not found")
604
605
except confuse.ConfigTypeError as e:
606
print(f"Configuration type error: {e}")
607
608
except confuse.ConfigReadError as e:
609
print(f"Cannot read configuration file: {e}")
610
```
611
612
This comprehensive configuration system provides flexible, type-safe access to all beets settings with support for environment variables, includes, validation, and runtime modification.