or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdindex.mdsources.mdtemplates.mdviews.md

templates.mddocs/

0

# Type Validation

1

2

Comprehensive template system for validating and converting configuration values with built-in templates for common types and support for custom validation logic. Templates provide type safety and automatic conversion between YAML representations and Python objects.

3

4

## Capabilities

5

6

### Base Template Class

7

8

The foundation template class that all validation templates inherit from, providing the core validation and conversion interface.

9

10

```python { .api }

11

class Template:

12

def __init__(self, default=REQUIRED):

13

"""

14

Create a template with optional default value.

15

16

Parameters:

17

- default: Default value to return when configuration value is missing.

18

Use REQUIRED (default) to raise exception for missing values.

19

"""

20

21

def value(self, view, template=None):

22

"""

23

Get validated value from a ConfigView.

24

25

Parameters:

26

- view (ConfigView): Configuration view to validate

27

- template (Template, optional): Parent template context

28

29

Returns:

30

Validated and converted value

31

32

Raises:

33

- NotFoundError: If value is missing and required

34

- ConfigValueError: If value is invalid

35

"""

36

37

def convert(self, value, view):

38

"""

39

Convert raw configuration value to target type.

40

41

Parameters:

42

- value: Raw value from configuration source

43

- view (ConfigView): Configuration view context

44

45

Returns:

46

Converted value

47

"""

48

49

def get_default_value(self, key_name='default'):

50

"""

51

Get the default value for this template.

52

53

Returns:

54

Default value or raises NotFoundError if required

55

"""

56

```

57

58

### Basic Type Templates

59

60

Templates for primitive types with automatic conversion and validation.

61

62

```python { .api }

63

class Integer(Template):

64

"""Template for integer values with float rounding."""

65

66

class Number(Template):

67

"""Template for numeric values (int or float)."""

68

69

class String(Template):

70

def __init__(self, default=REQUIRED, pattern=None, expand_vars=False):

71

"""

72

Template for string values with optional pattern matching and variable expansion.

73

74

Parameters:

75

- default: Default string value

76

- pattern (str, optional): Regular expression pattern to validate against

77

- expand_vars (bool): Whether to expand environment variables ($VAR, ${VAR})

78

"""

79

80

class TypeTemplate(Template):

81

def __init__(self, typ, default=REQUIRED):

82

"""

83

Template for validating Python type instances.

84

85

Parameters:

86

- typ (type): Python type to validate against

87

- default: Default value of the specified type

88

"""

89

```

90

91

### Choice and Option Templates

92

93

Templates for validating values against predefined choices or multiple possible templates.

94

95

```python { .api }

96

class Choice(Template):

97

def __init__(self, choices, default=REQUIRED):

98

"""

99

Template for values from predefined choices.

100

101

Parameters:

102

- choices: Sequence of valid values, dict mapping, or Enum class

103

- default: Default choice value

104

"""

105

106

class OneOf(Template):

107

def __init__(self, allowed, default=REQUIRED):

108

"""

109

Template accepting values matching any of multiple sub-templates.

110

111

Parameters:

112

- allowed: List of Template objects or convertible values

113

- default: Default value

114

"""

115

116

class Optional(Template):

117

def __init__(self, subtemplate, default=None, allow_missing=True):

118

"""

119

Template making sub-templates optional with null/missing value handling.

120

121

Parameters:

122

- subtemplate: Template to apply when value is present and not null

123

- default: Value to return for null/missing values

124

- allow_missing (bool): Whether to allow missing values

125

"""

126

```

127

128

### Container Templates

129

130

Templates for validating collections and nested data structures.

131

132

```python { .api }

133

class MappingTemplate(Template):

134

def __init__(self, mapping):

135

"""

136

Template for dictionary validation with typed values.

137

138

Parameters:

139

- mapping (dict): Dictionary specifying value templates for each key

140

"""

141

142

class Sequence(Template):

143

def __init__(self, subtemplate):

144

"""

145

Template for list validation with uniform item types.

146

147

Parameters:

148

- subtemplate: Template to apply to each list item

149

"""

150

151

class MappingValues(Template):

152

def __init__(self, subtemplate):

153

"""

154

Template for mappings with variable keys but typed values.

155

156

Parameters:

157

- subtemplate: Template to apply to all mapping values

158

"""

159

160

class StrSeq(Template):

161

def __init__(self, split=True, default=REQUIRED):

162

"""

163

Template for lists of strings with optional whitespace splitting.

164

165

Parameters:

166

- split (bool): Whether to split single strings on whitespace

167

- default: Default list value

168

"""

169

170

class Pairs(StrSeq):

171

def __init__(self, default_value=None):

172

"""

173

Template for ordered key-value pairs from various input formats.

174

175

Parameters:

176

- default_value: Default value for keys without explicit values

177

"""

178

```

179

180

### File Path Templates

181

182

Templates for validating and resolving file paths with platform-aware handling.

183

184

```python { .api }

185

class Filename(Template):

186

def __init__(self, default=REQUIRED, cwd=None, relative_to=None,

187

in_app_dir=False, in_source_dir=False):

188

"""

189

Template for filename validation with path resolution.

190

191

Parameters:

192

- default: Default filename

193

- cwd (str, optional): Working directory for relative paths

194

- relative_to (str, optional): Key name for sibling path resolution

195

- in_app_dir (bool): Resolve relative to application config directory

196

- in_source_dir (bool): Resolve relative to configuration file directory

197

"""

198

199

class Path(Filename):

200

"""Template for pathlib.Path objects with same resolution as Filename."""

201

```

202

203

### Utility Functions and Classes

204

205

Helper functions and classes for working with templates and validation.

206

207

```python { .api }

208

def as_template(value):

209

"""

210

Convert shorthand Python values to Template objects.

211

212

Parameters:

213

- value: Python type, value, or existing Template

214

215

Returns:

216

Template: Corresponding Template object

217

"""

218

219

class AttrDict(dict):

220

"""

221

Dictionary subclass with attribute-style access.

222

223

Enables dot notation: config.database.host instead of config['database']['host']

224

"""

225

def __getattr__(self, key): ...

226

def __setattr__(self, key, value): ...

227

```

228

229

## Usage Examples

230

231

### Basic Type Validation

232

233

```python

234

import confuse

235

236

config = confuse.Configuration('myapp')

237

238

# Simple type templates

239

port = config['port'].get(confuse.Integer())

240

timeout = config['timeout'].get(confuse.Number(30.0)) # Default: 30.0

241

name = config['app_name'].get(confuse.String())

242

243

# Type shorthand (automatically converted to templates)

244

port = config['port'].get(int) # Same as Integer()

245

timeout = config['timeout'].get(30.0) # Same as Number(30.0)

246

name = config['app_name'].get(str) # Same as String()

247

```

248

249

### String Templates with Patterns

250

251

```python

252

import confuse

253

254

config = confuse.Configuration('myapp')

255

256

# String with regex pattern validation

257

email_template = confuse.String(pattern=r'^[^@]+@[^@]+\.[^@]+$')

258

email = config['admin_email'].get(email_template)

259

260

# String with environment variable expansion

261

path_template = confuse.String(expand_vars=True)

262

data_path = config['data_path'].get(path_template) # Expands $HOME/data

263

```

264

265

### Choice Templates

266

267

```python

268

import confuse

269

from enum import Enum

270

271

config = confuse.Configuration('myapp')

272

273

# Choice from list

274

log_level = config['log_level'].get(confuse.Choice(['DEBUG', 'INFO', 'WARNING', 'ERROR']))

275

276

# Choice from dict (maps keys to values)

277

env_mapping = {'dev': 'development', 'prod': 'production'}

278

environment = config['env'].get(confuse.Choice(env_mapping))

279

280

# Choice from Enum

281

class LogLevel(Enum):

282

DEBUG = 'debug'

283

INFO = 'info'

284

WARNING = 'warning'

285

ERROR = 'error'

286

287

log_level = config['log_level'].get(confuse.Choice(LogLevel))

288

```

289

290

### Complex Data Structure Validation

291

292

```python

293

import confuse

294

295

config = confuse.Configuration('myapp')

296

297

# Dictionary template with typed values

298

database_template = {

299

'host': str,

300

'port': confuse.Integer(5432),

301

'username': str,

302

'password': str,

303

'ssl': bool,

304

'timeout': confuse.Number(30.0),

305

'options': confuse.StrSeq(),

306

}

307

308

# Get validated configuration as AttrDict

309

db_config = config['database'].get(database_template)

310

print(f"Connecting to {db_config.host}:{db_config.port}")

311

print(f"SSL enabled: {db_config.ssl}")

312

print(f"Options: {db_config.options}")

313

314

# List of dictionaries

315

server_template = confuse.Sequence({

316

'hostname': str,

317

'port': confuse.Integer(),

318

'enabled': bool,

319

'tags': confuse.StrSeq(),

320

})

321

322

servers = config['servers'].get(server_template)

323

for server in servers:

324

print(f"Server: {server.hostname}:{server.port} (enabled: {server.enabled})")

325

```

326

327

### File Path Validation

328

329

```python

330

import confuse

331

332

config = confuse.Configuration('myapp')

333

334

# Basic filename template

335

config_file = config['config_file'].get(confuse.Filename())

336

337

# Filename relative to application config directory

338

log_file = config['log_file'].get(confuse.Filename(in_app_dir=True))

339

340

# Filename relative to configuration source file

341

data_file = config['data_file'].get(confuse.Filename(in_source_dir=True))

342

343

# Filename with custom working directory

344

output_file = config['output'].get(confuse.Filename(cwd='/tmp'))

345

346

# Filename relative to another configuration value

347

template = {

348

'base_dir': confuse.Filename(),

349

'data_file': confuse.Filename(relative_to='base_dir'),

350

}

351

paths = config.get(template)

352

print(f"Data file: {paths.data_file}") # Resolved relative to base_dir

353

```

354

355

### Optional and Default Values

356

357

```python

358

import confuse

359

360

config = confuse.Configuration('myapp')

361

362

# Optional template with default

363

debug_mode = config['debug'].get(confuse.Optional(bool, default=False))

364

365

# Template with REQUIRED (raises exception if missing)

366

api_key = config['api_key'].get(confuse.String()) # Must be present

367

368

# Template with default value

369

max_workers = config['max_workers'].get(confuse.Integer(4))

370

371

# Optional nested configuration

372

cache_template = confuse.Optional({

373

'enabled': bool,

374

'ttl': confuse.Integer(3600),

375

'backend': confuse.Choice(['memory', 'redis']),

376

})

377

cache_config = config['cache'].get(cache_template)

378

if cache_config:

379

print(f"Cache enabled: {cache_config.enabled}")

380

```

381

382

### Multiple Template Options

383

384

```python

385

import confuse

386

387

config = confuse.Configuration('myapp')

388

389

# Value can be boolean or string

390

import_mode = config['import_mode'].get(confuse.OneOf([bool, 'ask', 'skip']))

391

392

# Value can be filename or URL

393

source_template = confuse.OneOf([

394

confuse.Filename(),

395

confuse.String(pattern=r'^https?://'),

396

])

397

data_source = config['data_source'].get(source_template)

398

399

# Multiple validation options with different defaults

400

retry_template = confuse.OneOf([

401

confuse.Integer(), # Number of retries

402

bool, # True/False for default retry count

403

confuse.String(pattern=r'^(always|never)$'), # Special string values

404

])

405

retry_config = config['retry'].get(retry_template)

406

```

407

408

### String Sequences and Pairs

409

410

```python

411

import confuse

412

413

config = confuse.Configuration('myapp')

414

415

# List of strings (splits single string on whitespace)

416

plugins = config['plugins'].get(confuse.StrSeq())

417

# YAML: plugins: "plugin1 plugin2 plugin3" -> ['plugin1', 'plugin2', 'plugin3']

418

# YAML: plugins: [plugin1, plugin2, plugin3] -> ['plugin1', 'plugin2', 'plugin3']

419

420

# List of strings without splitting

421

tags = config['tags'].get(confuse.StrSeq(split=False))

422

# YAML: tags: "development staging" -> ['development staging']

423

424

# Key-value pairs

425

env_vars = config['environment'].get(confuse.Pairs())

426

# YAML:

427

# environment:

428

# - DATABASE_URL: postgres://localhost/db

429

# - [API_KEY, secret123]

430

# - DEBUG # Uses default_value

431

# Result: [('DATABASE_URL', 'postgres://localhost/db'), ('API_KEY', 'secret123'), ('DEBUG', None)]

432

433

# Pairs with default value

434

flags = config['flags'].get(confuse.Pairs(default_value=True))

435

# Result: [('DEBUG', True)] for YAML: flags: [DEBUG]

436

```

437

438

### Custom Template Creation

439

440

```python

441

import confuse

442

443

class EmailTemplate(confuse.Template):

444

def convert(self, value, view):

445

if not isinstance(value, str):

446

self.fail('must be a string', view, True)

447

448

if '@' not in value:

449

self.fail('must be a valid email address', view)

450

451

return value.lower() # Normalize to lowercase

452

453

config = confuse.Configuration('myapp')

454

admin_email = config['admin_email'].get(EmailTemplate())

455

```