or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdimport-autotag.mdindex.mdlibrary-management.mdplugin-system.mdquery-system.mduser-interface.mdutilities-templates.md

configuration.mddocs/

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.