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

templates.mddocs/

0

# Template System

1

2

The template system provides template rendering framework supporting multiple template engines including Jinja2 and Mustache. It enables consistent template-based output generation for applications.

3

4

## Capabilities

5

6

### Template Handler Interface

7

8

Base interface for template rendering functionality that defines the contract for template operations.

9

10

```python { .api }

11

class TemplateHandler:

12

"""

13

Template handler interface for rendering templates with data.

14

15

Provides methods for loading template files and rendering them

16

with data contexts to produce formatted output.

17

"""

18

19

def load(self, template_path: str) -> Any:

20

"""

21

Load a template from file path.

22

23

Args:

24

template_path: Path to template file to load

25

26

Returns:

27

Loaded template object

28

"""

29

30

def render(self, content: str, data: Dict[str, Any]) -> str:

31

"""

32

Render template content with data context.

33

34

Args:

35

content: Template content string or template object

36

data: Dictionary of data to render with template

37

38

Returns:

39

Rendered template output string

40

"""

41

```

42

43

## Usage Examples

44

45

### Basic Template Usage

46

47

```python

48

from cement import App, Controller, ex, init_defaults

49

50

CONFIG = init_defaults('myapp')

51

CONFIG['template.jinja2'] = {

52

'template_dirs': ['./templates']

53

}

54

55

class TemplateController(Controller):

56

class Meta:

57

label = 'template'

58

stacked_on = 'base'

59

stacked_type = 'nested'

60

61

@ex(help='generate report')

62

def report(self):

63

"""Generate report using template."""

64

report_data = {

65

'title': 'Monthly Report',

66

'date': '2023-01-15',

67

'items': [

68

{'name': 'Sales', 'value': 15000, 'change': '+5%'},

69

{'name': 'Expenses', 'value': 8000, 'change': '+2%'},

70

{'name': 'Profit', 'value': 7000, 'change': '+8%'}

71

],

72

'summary': 'Overall performance improved this month'

73

}

74

75

# Load and render template

76

template = self.app.template.load('report.html')

77

output = self.app.template.render(template, report_data)

78

print(output)

79

80

class BaseController(Controller):

81

class Meta:

82

label = 'base'

83

84

class MyApp(App):

85

class Meta:

86

label = 'myapp'

87

base_controller = 'base'

88

extensions = ['jinja2']

89

template_handler = 'jinja2'

90

config_defaults = CONFIG

91

handlers = [BaseController, TemplateController]

92

93

with MyApp() as app:

94

app.run()

95

96

# Usage:

97

# myapp template report

98

```

99

100

### Jinja2 Template Engine

101

102

```python

103

from cement import App, Controller, ex, init_defaults

104

105

CONFIG = init_defaults('myapp')

106

CONFIG['template.jinja2'] = {

107

'template_dirs': ['./templates', './shared_templates'],

108

'auto_reload': True,

109

'cache_size': 50

110

}

111

112

class EmailController(Controller):

113

class Meta:

114

label = 'email'

115

stacked_on = 'base'

116

stacked_type = 'nested'

117

118

@ex(

119

help='send welcome email',

120

arguments=[

121

(['--user'], {'help': 'username', 'required': True}),

122

(['--email'], {'help': 'email address', 'required': True})

123

]

124

)

125

def welcome(self):

126

"""Send welcome email using Jinja2 template."""

127

user_data = {

128

'username': self.app.pargs.user,

129

'email': self.app.pargs.email,

130

'company': 'MyCompany',

131

'support_email': 'support@mycompany.com',

132

'features': [

133

'Dashboard access',

134

'Real-time notifications',

135

'Advanced reporting',

136

'24/7 support'

137

]

138

}

139

140

# Render email template

141

template = self.app.template.load('welcome_email.html')

142

email_html = self.app.template.render(template, user_data)

143

144

print(f"Welcome email generated for {user_data['username']}")

145

print("=" * 50)

146

print(email_html)

147

148

class BaseController(Controller):

149

class Meta:

150

label = 'base'

151

152

class MyApp(App):

153

class Meta:

154

label = 'myapp'

155

base_controller = 'base'

156

extensions = ['jinja2']

157

template_handler = 'jinja2'

158

config_defaults = CONFIG

159

handlers = [BaseController, EmailController]

160

161

with MyApp() as app:

162

app.run()

163

164

# Example template: templates/welcome_email.html

165

"""

166

<!DOCTYPE html>

167

<html>

168

<head>

169

<title>Welcome to {{ company }}</title>

170

</head>

171

<body>

172

<h1>Welcome, {{ username }}!</h1>

173

174

<p>Thank you for joining {{ company }}. Your account ({{ email }}) is now active.</p>

175

176

<h2>Available Features:</h2>

177

<ul>

178

{% for feature in features %}

179

<li>{{ feature }}</li>

180

{% endfor %}

181

</ul>

182

183

<p>Need help? Contact us at {{ support_email }}</p>

184

185

<p>Best regards,<br>

186

The {{ company }} Team</p>

187

</body>

188

</html>

189

"""

190

191

# Usage:

192

# myapp email welcome --user johndoe --email john@example.com

193

```

194

195

### Mustache Template Engine

196

197

```python

198

from cement import App, Controller, ex, init_defaults

199

200

CONFIG = init_defaults('myapp')

201

CONFIG['template.mustache'] = {

202

'template_dirs': ['./mustache_templates']

203

}

204

205

class ConfigController(Controller):

206

class Meta:

207

label = 'config'

208

stacked_on = 'base'

209

stacked_type = 'nested'

210

211

@ex(help='generate configuration file')

212

def generate(self):

213

"""Generate configuration file using Mustache template."""

214

config_data = {

215

'app_name': 'MyApplication',

216

'version': '1.0.0',

217

'database': {

218

'host': 'localhost',

219

'port': 5432,

220

'name': 'myapp_db'

221

},

222

'features': [

223

{'name': 'authentication', 'enabled': True},

224

{'name': 'caching', 'enabled': True},

225

{'name': 'logging', 'enabled': True},

226

{'name': 'monitoring', 'enabled': False}

227

],

228

'debug_mode': False

229

}

230

231

# Render configuration template

232

template = self.app.template.load('app_config.mustache')

233

config_output = self.app.template.render(template, config_data)

234

235

print("Generated configuration:")

236

print("=" * 40)

237

print(config_output)

238

239

class BaseController(Controller):

240

class Meta:

241

label = 'base'

242

243

class MyApp(App):

244

class Meta:

245

label = 'myapp'

246

base_controller = 'base'

247

extensions = ['mustache']

248

template_handler = 'mustache'

249

config_defaults = CONFIG

250

handlers = [BaseController, ConfigController]

251

252

with MyApp() as app:

253

app.run()

254

255

# Example template: mustache_templates/app_config.mustache

256

"""

257

# {{ app_name }} Configuration

258

# Version: {{ version }}

259

260

[application]

261

name = {{ app_name }}

262

version = {{ version }}

263

debug = {{ debug_mode }}

264

265

[database]

266

host = {{ database.host }}

267

port = {{ database.port }}

268

name = {{ database.name }}

269

270

[features]

271

{{#features}}

272

{{name}} = {{enabled}}

273

{{/features}}

274

"""

275

276

# Usage:

277

# myapp config generate

278

```

279

280

### Template with Custom Filters

281

282

```python

283

from cement import App, Controller, ex, init_defaults

284

import datetime

285

286

CONFIG = init_defaults('myapp')

287

CONFIG['template.jinja2'] = {

288

'template_dirs': ['./templates']

289

}

290

291

def datetime_filter(timestamp, format='%Y-%m-%d %H:%M:%S'):

292

"""Custom Jinja2 filter for datetime formatting."""

293

if isinstance(timestamp, str):

294

dt = datetime.datetime.fromisoformat(timestamp.replace('Z', '+00:00'))

295

else:

296

dt = timestamp

297

return dt.strftime(format)

298

299

def currency_filter(amount, symbol='$'):

300

"""Custom Jinja2 filter for currency formatting."""

301

return f"{symbol}{amount:,.2f}"

302

303

class ReportController(Controller):

304

class Meta:

305

label = 'report'

306

stacked_on = 'base'

307

stacked_type = 'nested'

308

309

@ex(help='generate sales report')

310

def sales(self):

311

"""Generate sales report with custom filters."""

312

sales_data = {

313

'report_title': 'Q1 Sales Report',

314

'generated_at': '2023-01-15T10:30:00Z',

315

'total_sales': 125000.50,

316

'transactions': [

317

{

318

'date': '2023-01-10T14:30:00Z',

319

'customer': 'Acme Corp',

320

'amount': 15000.00,

321

'status': 'completed'

322

},

323

{

324

'date': '2023-01-12T09:15:00Z',

325

'customer': 'Beta LLC',

326

'amount': 8500.75,

327

'status': 'completed'

328

}

329

]

330

}

331

332

# Add custom filters to Jinja2 environment

333

self.app.template.env.filters['datetime'] = datetime_filter

334

self.app.template.env.filters['currency'] = currency_filter

335

336

# Render report

337

template = self.app.template.load('sales_report.html')

338

report_html = self.app.template.render(template, sales_data)

339

340

print(report_html)

341

342

class BaseController(Controller):

343

class Meta:

344

label = 'base'

345

346

class MyApp(App):

347

class Meta:

348

label = 'myapp'

349

base_controller = 'base'

350

extensions = ['jinja2']

351

template_handler = 'jinja2'

352

config_defaults = CONFIG

353

handlers = [BaseController, ReportController]

354

355

with MyApp() as app:

356

app.run()

357

358

# Example template using custom filters: templates/sales_report.html

359

"""

360

<h1>{{ report_title }}</h1>

361

<p>Generated: {{ generated_at | datetime('%B %d, %Y at %I:%M %p') }}</p>

362

363

<h2>Summary</h2>

364

<p>Total Sales: {{ total_sales | currency }}</p>

365

366

<h2>Transactions</h2>

367

<table>

368

<tr>

369

<th>Date</th>

370

<th>Customer</th>

371

<th>Amount</th>

372

<th>Status</th>

373

</tr>

374

{% for transaction in transactions %}

375

<tr>

376

<td>{{ transaction.date | datetime('%m/%d/%Y') }}</td>

377

<td>{{ transaction.customer }}</td>

378

<td>{{ transaction.amount | currency }}</td>

379

<td>{{ transaction.status | title }}</td>

380

</tr>

381

{% endfor %}

382

</table>

383

"""

384

385

# Usage:

386

# myapp report sales

387

```

388

389

### Template Inheritance

390

391

```python

392

from cement import App, Controller, ex, init_defaults

393

394

CONFIG = init_defaults('myapp')

395

CONFIG['template.jinja2'] = {

396

'template_dirs': ['./templates']

397

}

398

399

class PageController(Controller):

400

class Meta:

401

label = 'page'

402

stacked_on = 'base'

403

stacked_type = 'nested'

404

405

@ex(help='generate dashboard page')

406

def dashboard(self):

407

"""Generate dashboard page using template inheritance."""

408

dashboard_data = {

409

'page_title': 'Dashboard',

410

'user': {

411

'name': 'John Doe',

412

'role': 'Administrator'

413

},

414

'stats': [

415

{'label': 'Total Users', 'value': 1250, 'trend': 'up'},

416

{'label': 'Active Sessions', 'value': 89, 'trend': 'up'},

417

{'label': 'System Load', 'value': '65%', 'trend': 'stable'}

418

],

419

'recent_activity': [

420

'User johndoe logged in',

421

'New user registered: alice',

422

'System backup completed'

423

]

424

}

425

426

template = self.app.template.load('dashboard.html')

427

page_html = self.app.template.render(template, dashboard_data)

428

429

print(page_html)

430

431

class BaseController(Controller):

432

class Meta:

433

label = 'base'

434

435

class MyApp(App):

436

class Meta:

437

label = 'myapp'

438

base_controller = 'base'

439

extensions = ['jinja2']

440

template_handler = 'jinja2'

441

config_defaults = CONFIG

442

handlers = [BaseController, PageController]

443

444

with MyApp() as app:

445

app.run()

446

447

# Base template: templates/base.html

448

"""

449

<!DOCTYPE html>

450

<html>

451

<head>

452

<title>{% block title %}MyApp{% endblock %}</title>

453

<style>

454

body { font-family: Arial, sans-serif; margin: 20px; }

455

.header { background: #f0f0f0; padding: 10px; }

456

.content { margin: 20px 0; }

457

.footer { border-top: 1px solid #ccc; padding: 10px; }

458

</style>

459

</head>

460

<body>

461

<div class="header">

462

<h1>{% block header %}MyApp{% endblock %}</h1>

463

{% block nav %}

464

<nav>

465

<a href="/">Home</a> |

466

<a href="/dashboard">Dashboard</a> |

467

<a href="/settings">Settings</a>

468

</nav>

469

{% endblock %}

470

</div>

471

472

<div class="content">

473

{% block content %}{% endblock %}

474

</div>

475

476

<div class="footer">

477

{% block footer %}

478

<p>&copy; 2023 MyApp. All rights reserved.</p>

479

{% endblock %}

480

</div>

481

</body>

482

</html>

483

"""

484

485

# Dashboard template: templates/dashboard.html

486

"""

487

{% extends "base.html" %}

488

489

{% block title %}{{ page_title }} - MyApp{% endblock %}

490

491

{% block header %}{{ page_title }}{% endblock %}

492

493

{% block content %}

494

<p>Welcome back, {{ user.name }} ({{ user.role }})</p>

495

496

<h2>System Statistics</h2>

497

<div class="stats">

498

{% for stat in stats %}

499

<div class="stat-item">

500

<strong>{{ stat.label }}:</strong> {{ stat.value }}

501

<span class="trend-{{ stat.trend }}">{{ stat.trend }}</span>

502

</div>

503

{% endfor %}

504

</div>

505

506

<h2>Recent Activity</h2>

507

<ul>

508

{% for activity in recent_activity %}

509

<li>{{ activity }}</li>

510

{% endfor %}

511

</ul>

512

{% endblock %}

513

"""

514

515

# Usage:

516

# myapp page dashboard

517

```