or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

arguments.mdcaching.mdconfiguration.mdcontrollers.mdextensions.mdfoundation.mdhooks.mdindex.mdinterface-handler.mdlogging.mdmail.mdoutput.mdplugins.mdtemplates.mdutilities.md

configuration.mddocs/

0

# Configuration Management

1

2

The configuration system provides comprehensive configuration file handling with support for multiple formats, default values, and hierarchical configuration merging. It integrates seamlessly with argument parsing for unified application configuration.

3

4

## Capabilities

5

6

### Configuration Handler Interface

7

8

Base interface for configuration management handlers that defines the contract for configuration operations.

9

10

```python { .api }

11

class ConfigHandler:

12

"""

13

Configuration handler interface for managing application configuration.

14

15

Provides methods for parsing configuration files, merging configuration

16

data, and accessing configuration values in a structured way.

17

"""

18

19

def parse_file(self, file_path: str) -> bool:

20

"""

21

Parse and load a configuration file.

22

23

Args:

24

file_path: Path to configuration file to parse

25

26

Returns:

27

True if file was successfully parsed, False otherwise

28

"""

29

30

def merge(self, dict_obj: Dict[str, Any]) -> None:

31

"""

32

Merge a dictionary into the configuration.

33

34

Args:

35

dict_obj: Dictionary to merge into configuration

36

"""

37

38

def get(self, section: str, key: str) -> Any:

39

"""

40

Get a configuration value.

41

42

Args:

43

section: Configuration section name

44

key: Configuration key name

45

46

Returns:

47

Configuration value

48

49

Raises:

50

KeyError: If section or key not found

51

"""

52

53

def get_section_dict(self, section: str) -> Dict[str, Any]:

54

"""

55

Get an entire configuration section as a dictionary.

56

57

Args:

58

section: Section name to retrieve

59

60

Returns:

61

Dictionary containing all key-value pairs in the section

62

63

Raises:

64

KeyError: If section not found

65

"""

66

67

def get_sections(self) -> List[str]:

68

"""

69

Get list of all configuration sections.

70

71

Returns:

72

List of section names

73

"""

74

75

def add_section(self, section: str) -> None:

76

"""

77

Add a new configuration section.

78

79

Args:

80

section: Section name to add

81

"""

82

83

def has_section(self, section: str) -> bool:

84

"""

85

Check if a configuration section exists.

86

87

Args:

88

section: Section name to check

89

90

Returns:

91

True if section exists, False otherwise

92

"""

93

94

def keys(self, section: str) -> List[str]:

95

"""

96

Get list of keys in a configuration section.

97

98

Args:

99

section: Section name

100

101

Returns:

102

List of key names in the section

103

104

Raises:

105

KeyError: If section not found

106

"""

107

108

def set(self, section: str, key: str, value: Any) -> None:

109

"""

110

Set a configuration value.

111

112

Args:

113

section: Configuration section name

114

key: Configuration key name

115

value: Value to set

116

"""

117

```

118

119

### Configuration Helper Functions

120

121

Utility functions for working with configuration defaults and initialization.

122

123

```python { .api }

124

def init_defaults(*sections: str) -> Dict[str, Any]:

125

"""

126

Create a standard dictionary for application configuration defaults.

127

128

Creates a nested dictionary structure with the specified sections.

129

This is commonly used for setting up application configuration defaults.

130

131

Args:

132

*sections: Section names to create in the defaults dictionary

133

134

Returns:

135

Dictionary with nested sections for configuration defaults

136

137

Example:

138

config = init_defaults('myapp', 'database', 'logging')

139

# Returns: {'myapp': {}, 'database': {}, 'logging': {}}

140

"""

141

```

142

143

## Usage Examples

144

145

### Basic Configuration Setup

146

147

```python

148

from cement import App, init_defaults

149

150

# Initialize configuration defaults

151

CONFIG = init_defaults('myapp')

152

CONFIG['myapp']['debug'] = False

153

CONFIG['myapp']['log_level'] = 'INFO'

154

CONFIG['myapp']['max_connections'] = 100

155

156

class MyApp(App):

157

class Meta:

158

label = 'myapp'

159

config_defaults = CONFIG

160

config_files = [

161

'/etc/myapp.conf',

162

'~/.myapp.conf',

163

'./myapp.conf'

164

]

165

166

with MyApp() as app:

167

app.setup()

168

169

# Access configuration values

170

debug = app.config.get('myapp', 'debug')

171

log_level = app.config.get('myapp', 'log_level')

172

max_conn = app.config.get('myapp', 'max_connections')

173

174

print(f"Debug: {debug}")

175

print(f"Log Level: {log_level}")

176

print(f"Max Connections: {max_conn}")

177

```

178

179

### Configuration File Formats

180

181

#### ConfigParser Format (.conf, .ini)

182

183

```ini

184

# /etc/myapp.conf

185

[myapp]

186

debug = false

187

log_level = INFO

188

max_connections = 100

189

190

[database]

191

host = localhost

192

port = 5432

193

name = myapp_db

194

user = myapp_user

195

password = secret123

196

197

[logging]

198

file = /var/log/myapp.log

199

rotate = true

200

max_size = 10MB

201

```

202

203

#### YAML Format (with yaml extension)

204

205

```yaml

206

# ~/.myapp.yaml

207

myapp:

208

debug: false

209

log_level: INFO

210

max_connections: 100

211

212

database:

213

host: localhost

214

port: 5432

215

name: myapp_db

216

user: myapp_user

217

password: secret123

218

219

logging:

220

file: /var/log/myapp.log

221

rotate: true

222

max_size: 10MB

223

```

224

225

### Multi-Section Configuration

226

227

```python

228

from cement import App, init_defaults

229

230

# Initialize with multiple sections

231

CONFIG = init_defaults('myapp', 'database', 'logging', 'cache')

232

233

# Set defaults for each section

234

CONFIG['myapp']['debug'] = False

235

CONFIG['myapp']['version'] = '1.0.0'

236

237

CONFIG['database']['host'] = 'localhost'

238

CONFIG['database']['port'] = 5432

239

CONFIG['database']['timeout'] = 30

240

241

CONFIG['logging']['level'] = 'INFO'

242

CONFIG['logging']['file'] = None

243

CONFIG['logging']['format'] = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'

244

245

CONFIG['cache']['enabled'] = True

246

CONFIG['cache']['ttl'] = 3600

247

CONFIG['cache']['max_size'] = 1000

248

249

class MyApp(App):

250

class Meta:

251

label = 'myapp'

252

config_defaults = CONFIG

253

config_files = ['./myapp.conf']

254

255

with MyApp() as app:

256

app.setup()

257

258

# Access different sections

259

db_config = app.config.get_section_dict('database')

260

print(f"Database config: {db_config}")

261

262

# Check if sections exist

263

if app.config.has_section('cache'):

264

cache_enabled = app.config.get('cache', 'enabled')

265

print(f"Cache enabled: {cache_enabled}")

266

267

# List all sections

268

sections = app.config.get_sections()

269

print(f"Available sections: {sections}")

270

```

271

272

### Dynamic Configuration Management

273

274

```python

275

from cement import App, Controller, ex, init_defaults

276

277

CONFIG = init_defaults('myapp')

278

279

class ConfigController(Controller):

280

class Meta:

281

label = 'config'

282

stacked_on = 'base'

283

stacked_type = 'nested'

284

285

@ex(

286

help='show configuration values',

287

arguments=[

288

(['--section'], {'help': 'show specific section only'})

289

]

290

)

291

def show(self):

292

"""Display current configuration."""

293

if self.app.pargs.section:

294

section = self.app.pargs.section

295

if self.app.config.has_section(section):

296

config_dict = self.app.config.get_section_dict(section)

297

print(f"[{section}]")

298

for key, value in config_dict.items():

299

print(f"{key} = {value}")

300

else:

301

print(f"Section '{section}' not found")

302

else:

303

# Show all sections

304

for section in self.app.config.get_sections():

305

print(f"[{section}]")

306

config_dict = self.app.config.get_section_dict(section)

307

for key, value in config_dict.items():

308

print(f"{key} = {value}")

309

print()

310

311

@ex(

312

help='set configuration value',

313

arguments=[

314

(['section'], {'help': 'configuration section'}),

315

(['key'], {'help': 'configuration key'}),

316

(['value'], {'help': 'configuration value'})

317

]

318

)

319

def set(self):

320

"""Set a configuration value."""

321

section = self.app.pargs.section

322

key = self.app.pargs.key

323

value = self.app.pargs.value

324

325

# Create section if it doesn't exist

326

if not self.app.config.has_section(section):

327

self.app.config.add_section(section)

328

329

self.app.config.set(section, key, value)

330

print(f"Set {section}.{key} = {value}")

331

332

@ex(

333

help='get configuration value',

334

arguments=[

335

(['section'], {'help': 'configuration section'}),

336

(['key'], {'help': 'configuration key'})

337

]

338

)

339

def get(self):

340

"""Get a configuration value."""

341

section = self.app.pargs.section

342

key = self.app.pargs.key

343

344

try:

345

value = self.app.config.get(section, key)

346

print(f"{section}.{key} = {value}")

347

except KeyError:

348

print(f"Configuration key '{section}.{key}' not found")

349

350

class BaseController(Controller):

351

class Meta:

352

label = 'base'

353

354

class MyApp(App):

355

class Meta:

356

label = 'myapp'

357

base_controller = 'base'

358

config_defaults = CONFIG

359

handlers = [

360

BaseController,

361

ConfigController

362

]

363

364

with MyApp() as app:

365

app.run()

366

367

# Usage:

368

# myapp config show

369

# myapp config show --section database

370

# myapp config set database host localhost

371

# myapp config get database host

372

```

373

374

### Configuration with Environment Variables

375

376

```python

377

import os

378

from cement import App, init_defaults

379

380

CONFIG = init_defaults('myapp')

381

382

# Set defaults that can be overridden by environment variables

383

CONFIG['myapp']['debug'] = os.getenv('MYAPP_DEBUG', 'false').lower() == 'true'

384

CONFIG['myapp']['log_level'] = os.getenv('MYAPP_LOG_LEVEL', 'INFO')

385

CONFIG['myapp']['database_url'] = os.getenv('DATABASE_URL', 'sqlite:///app.db')

386

387

class MyApp(App):

388

class Meta:

389

label = 'myapp'

390

config_defaults = CONFIG

391

392

def setup(self):

393

super().setup()

394

395

# Override with environment variables after config file loading

396

env_overrides = {}

397

398

if 'MYAPP_DEBUG' in os.environ:

399

env_overrides['debug'] = os.getenv('MYAPP_DEBUG').lower() == 'true'

400

401

if 'MYAPP_LOG_LEVEL' in os.environ:

402

env_overrides['log_level'] = os.getenv('MYAPP_LOG_LEVEL')

403

404

if 'DATABASE_URL' in os.environ:

405

env_overrides['database_url'] = os.getenv('DATABASE_URL')

406

407

# Merge environment overrides

408

if env_overrides:

409

self.config.merge({'myapp': env_overrides})

410

411

with MyApp() as app:

412

app.setup()

413

414

debug = app.config.get('myapp', 'debug')

415

log_level = app.config.get('myapp', 'log_level')

416

db_url = app.config.get('myapp', 'database_url')

417

418

print(f"Configuration loaded:")

419

print(f" Debug: {debug}")

420

print(f" Log Level: {log_level}")

421

print(f" Database URL: {db_url}")

422

```

423

424

### Configuration Validation

425

426

```python

427

from cement import App, init_defaults

428

429

CONFIG = init_defaults('myapp', 'database')

430

CONFIG['myapp']['name'] = 'MyApplication'

431

CONFIG['myapp']['version'] = '1.0.0'

432

CONFIG['database']['host'] = 'localhost'

433

CONFIG['database']['port'] = 5432

434

435

class MyApp(App):

436

class Meta:

437

label = 'myapp'

438

config_defaults = CONFIG

439

config_files = ['./myapp.conf']

440

441

def validate_config(self):

442

"""Validate configuration after loading."""

443

# Check required configuration values

444

required_keys = [

445

('myapp', 'name'),

446

('myapp', 'version'),

447

('database', 'host'),

448

('database', 'port')

449

]

450

451

for section, key in required_keys:

452

try:

453

value = self.config.get(section, key)

454

if value is None or value == '':

455

raise ValueError(f"Required configuration {section}.{key} is missing or empty")

456

except KeyError:

457

raise ValueError(f"Required configuration {section}.{key} is missing")

458

459

# Validate data types and ranges

460

port = self.config.get('database', 'port')

461

if not isinstance(port, int) or port < 1 or port > 65535:

462

raise ValueError(f"Database port must be an integer between 1 and 65535, got: {port}")

463

464

print("Configuration validation passed")

465

466

def setup(self):

467

super().setup()

468

self.validate_config()

469

470

with MyApp() as app:

471

app.setup()

472

app.run()

473

```

474

475

### Hierarchical Configuration Loading

476

477

```python

478

from cement import App, init_defaults

479

import os

480

481

CONFIG = init_defaults('myapp')

482

CONFIG['myapp']['environment'] = 'development'

483

484

class MyApp(App):

485

class Meta:

486

label = 'myapp'

487

config_defaults = CONFIG

488

489

def setup(self):

490

super().setup()

491

492

# Load configuration files in priority order

493

config_files = [

494

'/etc/myapp/config.conf', # System-wide config

495

'/etc/myapp/myapp.conf', # System-wide app config

496

os.path.expanduser('~/.myapp.conf'), # User config

497

'./myapp.conf', # Local config

498

]

499

500

# Add environment-specific config

501

env = self.config.get('myapp', 'environment')

502

env_config = f'./config/{env}.conf'

503

config_files.append(env_config)

504

505

# Load each config file (later files override earlier ones)

506

for config_file in config_files:

507

if os.path.exists(config_file):

508

print(f"Loading config: {config_file}")

509

self.config.parse_file(config_file)

510

511

with MyApp() as app:

512

app.setup()

513

514

# Final configuration reflects the hierarchy

515

environment = app.config.get('myapp', 'environment')

516

print(f"Running in {environment} environment")

517

518

app.run()

519

```