or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

audio-system.mdbackend-system.mdconfiguration.mdcore-controllers.mdextension-system.mdindex.mdmodels.md

configuration.mddocs/

0

# Configuration System

1

2

Mopidy's configuration system provides schema-based configuration management with validation, type safety, and support for multiple configuration sources. It enables both core functionality and extensions to define, validate, and access configuration settings in a consistent manner.

3

4

## Capabilities

5

6

### Configuration Loading and Management

7

8

Core functions for loading, parsing, and managing configuration from multiple sources.

9

10

```python { .api }

11

def load(files, ext_schemas, ext_defaults, overrides):

12

"""

13

Load configuration from multiple sources.

14

15

Parameters:

16

- files (list[str]): Configuration file paths

17

- ext_schemas (list[ConfigSchema]): Extension schemas

18

- ext_defaults (list[str]): Extension default configs

19

- overrides (list[tuple]): Command-line overrides

20

21

Returns:

22

- tuple[dict, dict]: (config, errors) - Parsed config and validation errors

23

"""

24

...

25

26

def format(config, ext_schemas, comments=None, display=True):

27

"""

28

Format configuration for display or output.

29

30

Parameters:

31

- config (dict): Configuration to format

32

- ext_schemas (list[ConfigSchema]): Extension schemas

33

- comments (dict, optional): Comments to include

34

- display (bool): Whether to format for display

35

36

Returns:

37

- str: Formatted configuration string

38

"""

39

...

40

41

def format_initial(extensions_data):

42

"""

43

Format initial configuration template with defaults.

44

45

Parameters:

46

- extensions_data (list[ExtensionData]): Extension data

47

48

Returns:

49

- str: Initial configuration template

50

"""

51

...

52

53

def read(config_file):

54

"""

55

Read configuration file content.

56

57

Parameters:

58

- config_file (str): Path to configuration file

59

60

Returns:

61

- str: Configuration file content

62

"""

63

...

64

```

65

66

Usage example:

67

```python

68

from mopidy import config

69

70

# Load configuration

71

config_data, errors = config.load(

72

files=["/etc/mopidy/mopidy.conf", "~/.config/mopidy/mopidy.conf"],

73

ext_schemas=[spotify_schema, local_schema],

74

ext_defaults=[spotify_defaults, local_defaults],

75

overrides=[("core", "cache_dir", "/tmp/mopidy")]

76

)

77

78

if errors:

79

print("Configuration errors:", errors)

80

```

81

82

### Configuration Schemas

83

84

Schema definition system for validating and organizing configuration sections.

85

86

```python { .api }

87

class ConfigSchema:

88

"""

89

Configuration schema for a section.

90

91

Parameters:

92

- name (str): Schema section name

93

"""

94

def __init__(self, name): ...

95

96

name: str # Section name

97

98

def __setitem__(self, key, value):

99

"""

100

Add configuration field to schema.

101

102

Parameters:

103

- key (str): Configuration key

104

- value (ConfigValue): Field validator

105

"""

106

...

107

108

def __getitem__(self, key):

109

"""Get configuration field validator."""

110

...

111

112

def deserialize(self, values):

113

"""

114

Deserialize configuration values.

115

116

Parameters:

117

- values (dict): Raw configuration values

118

119

Returns:

120

- tuple[dict, dict]: (parsed_values, errors)

121

"""

122

...

123

124

def serialize(self, values, display=False):

125

"""

126

Serialize configuration values.

127

128

Parameters:

129

- values (dict): Configuration values to serialize

130

- display (bool): Whether formatting for display

131

132

Returns:

133

- dict: Serialized values

134

"""

135

...

136

137

class MapConfigSchema(ConfigSchema):

138

"""

139

Schema for map-like configuration sections.

140

141

Parameters:

142

- name (str): Schema section name

143

- value_type (ConfigValue): Validator for all values

144

"""

145

def __init__(self, name, value_type): ...

146

```

147

148

Usage example:

149

```python

150

from mopidy.config.schemas import ConfigSchema

151

from mopidy.config.types import String, Integer, Boolean, Secret

152

153

# Define schema for an extension

154

schema = ConfigSchema("spotify")

155

schema["username"] = String()

156

schema["password"] = Secret() # Hidden in output

157

schema["enabled"] = Boolean()

158

schema["timeout"] = Integer(minimum=1, maximum=300)

159

schema["playlists"] = List()

160

```

161

162

### Configuration Value Types

163

164

Strongly-typed configuration value validators with built-in validation and conversion.

165

166

```python { .api }

167

class ConfigValue:

168

"""Base class for configuration value types."""

169

170

def __init__(self, optional=False):

171

"""

172

Initialize config value.

173

174

Parameters:

175

- optional (bool): Whether value is optional

176

"""

177

...

178

179

def deserialize(self, value):

180

"""

181

Convert string value to Python type.

182

183

Parameters:

184

- value (str): Raw configuration value

185

186

Returns:

187

- tuple[Any, str]: (converted_value, error_message)

188

"""

189

...

190

191

def serialize(self, value, display=False):

192

"""

193

Convert Python value to string.

194

195

Parameters:

196

- value: Python value to serialize

197

- display (bool): Whether formatting for display

198

199

Returns:

200

- str: Serialized value

201

"""

202

...

203

204

class String(ConfigValue):

205

"""String configuration value."""

206

def __init__(self, optional=False, choices=None): ...

207

208

class Integer(ConfigValue):

209

"""

210

Integer configuration value.

211

212

Parameters:

213

- optional (bool): Whether value is optional

214

- minimum (int, optional): Minimum allowed value

215

- maximum (int, optional): Maximum allowed value

216

"""

217

def __init__(self, optional=False, minimum=None, maximum=None): ...

218

219

class Float(ConfigValue):

220

"""

221

Float configuration value.

222

223

Parameters:

224

- optional (bool): Whether value is optional

225

- minimum (float, optional): Minimum allowed value

226

- maximum (float, optional): Maximum allowed value

227

"""

228

def __init__(self, optional=False, minimum=None, maximum=None): ...

229

230

class Boolean(ConfigValue):

231

"""Boolean configuration value (true/false, yes/no, 1/0)."""

232

def __init__(self, optional=False): ...

233

234

class List(ConfigValue):

235

"""

236

List configuration value (comma-separated).

237

238

Parameters:

239

- optional (bool): Whether value is optional

240

- separator (str): List item separator (default: comma)

241

"""

242

def __init__(self, optional=False, separator=","): ...

243

244

class Pair(ConfigValue):

245

"""

246

Key-value pair configuration value.

247

248

Parameters:

249

- optional (bool): Whether value is optional

250

- separator (str): Key-value separator (default: pipe)

251

"""

252

def __init__(self, optional=False, separator="|"): ...

253

254

class Secret(ConfigValue):

255

"""Secret configuration value (hidden in output)."""

256

def __init__(self, optional=False): ...

257

258

class Path(ConfigValue):

259

"""File system path configuration value."""

260

def __init__(self, optional=False): ...

261

262

class Hostname(ConfigValue):

263

"""Network hostname configuration value."""

264

def __init__(self, optional=False): ...

265

266

class Port(ConfigValue):

267

"""

268

Network port configuration value.

269

270

Parameters:

271

- optional (bool): Whether value is optional

272

- choices (list[int], optional): Allowed port numbers

273

"""

274

def __init__(self, optional=False, choices=None): ...

275

276

class LogLevel(ConfigValue):

277

"""Logging level configuration value."""

278

def __init__(self, optional=False): ...

279

280

class LogColor(ConfigValue):

281

"""Log color configuration value."""

282

def __init__(self, optional=False): ...

283

```

284

285

Usage example:

286

```python

287

# Configure different value types

288

schema["server_host"] = Hostname()

289

schema["server_port"] = Port(choices=[8080, 8081, 8082])

290

schema["log_level"] = LogLevel()

291

schema["api_timeout"] = Integer(minimum=1, maximum=300)

292

schema["cache_dir"] = Path()

293

schema["enabled_formats"] = List()

294

schema["database_url"] = Secret() # Won't be shown in config output

295

```

296

297

### Deprecated Configuration Handling

298

299

Support for handling deprecated configuration options with warnings and migration.

300

301

```python { .api }

302

class Deprecated(ConfigValue):

303

"""Marks a configuration option as deprecated."""

304

def __init__(self, message=None): ...

305

306

class DeprecatedValue:

307

"""Wrapper for deprecated configuration values."""

308

def __init__(self, value, message): ...

309

```

310

311

Usage example:

312

```python

313

# Mark old configuration options as deprecated

314

schema["old_option"] = Deprecated("Use 'new_option' instead")

315

schema["legacy_setting"] = Deprecated()

316

```

317

318

### Configuration Proxy

319

320

Proxy object providing convenient access to nested configuration values.

321

322

```python { .api }

323

class Proxy:

324

"""

325

Configuration proxy for convenient access to nested values.

326

327

Parameters:

328

- data (dict): Configuration data to wrap

329

"""

330

def __init__(self, data): ...

331

332

def __getitem__(self, key): ...

333

def __iter__(self): ...

334

def __len__(self): ...

335

def __repr__(self): ...

336

```

337

338

Usage example:

339

```python

340

config_proxy = Proxy(config_data)

341

342

# Access nested configuration values

343

cache_dir = config_proxy["core"]["cache_dir"]

344

spotify_username = config_proxy["spotify"]["username"]

345

346

# Proxy maintains dict-like interface

347

for section_name in config_proxy:

348

section = config_proxy[section_name]

349

print(f"Section {section_name} has {len(section)} options")

350

```

351

352

### Core Configuration Schemas

353

354

Built-in configuration schemas for Mopidy's core functionality.

355

356

```python { .api }

357

# Core system configuration

358

_core_schema = ConfigSchema("core")

359

_core_schema["cache_dir"] = Path()

360

_core_schema["config_dir"] = Path()

361

_core_schema["data_dir"] = Path()

362

_core_schema["max_tracklist_length"] = Integer(minimum=1)

363

_core_schema["restore_state"] = Boolean(optional=True)

364

365

# Logging configuration

366

_logging_schema = ConfigSchema("logging")

367

_logging_schema["verbosity"] = Integer(minimum=-1, maximum=4)

368

_logging_schema["format"] = String()

369

_logging_schema["color"] = Boolean()

370

_logging_schema["config_file"] = Path(optional=True)

371

372

# Audio system configuration

373

_audio_schema = ConfigSchema("audio")

374

_audio_schema["mixer"] = String()

375

_audio_schema["mixer_volume"] = Integer(optional=True, minimum=0, maximum=100)

376

_audio_schema["output"] = String()

377

_audio_schema["buffer_time"] = Integer(optional=True, minimum=1)

378

379

# HTTP proxy configuration

380

_proxy_schema = ConfigSchema("proxy")

381

_proxy_schema["scheme"] = String(optional=True, choices=["http", "https", "socks4", "socks5"])

382

_proxy_schema["hostname"] = Hostname(optional=True)

383

_proxy_schema["port"] = Port(optional=True)

384

_proxy_schema["username"] = String(optional=True)

385

_proxy_schema["password"] = Secret(optional=True)

386

387

# Per-module log levels

388

_loglevels_schema = MapConfigSchema("loglevels", LogLevel())

389

390

# Per-module log colors

391

_logcolors_schema = MapConfigSchema("logcolors", LogColor())

392

```

393

394

### Configuration File Locations

395

396

Standard configuration file search paths and loading order:

397

398

```python { .api }

399

# Standard configuration locations (in search order):

400

# 1. /etc/mopidy/mopidy.conf

401

# 2. /etc/mopidy/conf.d/*.conf

402

# 3. $XDG_CONFIG_HOME/mopidy/mopidy.conf (defaults to ~/.config/mopidy/mopidy.conf)

403

# 4. $XDG_CONFIG_HOME/mopidy/conf.d/*.conf

404

# 5. Command-line overrides

405

406

# Configuration can also be loaded from directories:

407

config_data, errors = config.load(

408

files=[

409

"/etc/mopidy/mopidy.conf",

410

"/etc/mopidy/conf.d/", # Will load all .conf files

411

"~/.config/mopidy/mopidy.conf"

412

],

413

ext_schemas=schemas,

414

ext_defaults=defaults,

415

overrides=[]

416

)

417

```

418

419

### Configuration Validation and Error Handling

420

421

Comprehensive validation with detailed error reporting:

422

423

```python { .api }

424

# Configuration loading returns both config and errors

425

config_data, errors = config.load(files, schemas, defaults, overrides)

426

427

# Errors are organized by section

428

if errors:

429

for section_name, section_errors in errors.items():

430

print(f"Errors in [{section_name}]:")

431

for field, error_msg in section_errors.items():

432

print(f" {field}: {error_msg}")

433

434

# Example error output:

435

# Errors in [spotify]:

436

# username: Required field is missing

437

# timeout: Value must be between 1 and 300

438

```

439

440

### Environment Integration

441

442

Integration with environment variables and system paths:

443

444

```python { .api }

445

import os

446

from pathlib import Path

447

448

# Environment variable support in configuration

449

config_template = """

450

[core]

451

cache_dir = ${XDG_CACHE_HOME}/mopidy

452

data_dir = ${XDG_DATA_HOME}/mopidy

453

454

[myext]

455

api_key = ${MYEXT_API_KEY}

456

"""

457

458

# Path expansion and validation

459

path_config = Path()

460

expanded_path = path_config.deserialize("~/music") # Expands to full path

461

```

462

463

## Configuration Best Practices

464

465

### Extension Configuration Design

466

467

```python

468

from mopidy.config.schemas import ConfigSchema

469

from mopidy.config.types import String, Integer, Boolean, Secret, List

470

471

class MyExtension(Extension):

472

def get_config_schema(self):

473

schema = super().get_config_schema()

474

475

# Required settings

476

schema["api_key"] = Secret() # Never shown in output

477

schema["endpoint"] = String()

478

479

# Optional settings with defaults

480

schema["timeout"] = Integer(minimum=1, maximum=300)

481

schema["max_results"] = Integer(minimum=1, maximum=1000)

482

schema["enabled"] = Boolean()

483

484

# List and choice settings

485

schema["supported_formats"] = List()

486

schema["quality"] = String(choices=["low", "medium", "high"])

487

488

return schema

489

490

def get_default_config(self):

491

return """\

492

[myext]

493

enabled = true

494

api_key =

495

endpoint = https://api.example.com

496

timeout = 30

497

max_results = 100

498

supported_formats = mp3, flac, ogg

499

quality = medium

500

"""

501

```

502

503

### Configuration Access in Extensions

504

505

```python

506

class MyBackend(Backend):

507

def __init__(self, config, audio):

508

super().__init__(config, audio)

509

510

# Access extension configuration

511

ext_config = config["myext"]

512

self.api_key = ext_config["api_key"]

513

self.endpoint = ext_config["endpoint"]

514

self.timeout = ext_config["timeout"]

515

516

# Validate required settings

517

if not self.api_key:

518

raise ExtensionError("MyExt requires api_key configuration")

519

```

520

521

### Dynamic Configuration Updates

522

523

```python

524

# Configuration can be reloaded at runtime

525

def reload_config():

526

new_config, errors = config.load(

527

files=config_files,

528

ext_schemas=schemas,

529

ext_defaults=defaults,

530

overrides=[]

531

)

532

533

if not errors:

534

# Update components with new configuration

535

update_backends(new_config)

536

update_frontends(new_config)

537

```