or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bytecode-caching.mdenvironment-templates.mderror-handling-debugging.mdextensions-custom-syntax.mdfilters-data-processing.mdindex.mdmeta-analysis.mdnative-types.mdsecurity-sandboxing.mdtemplate-loaders.mdtests-conditionals.md

extensions-custom-syntax.mddocs/

0

# Extensions and Custom Syntax

1

2

Extensible plugin system for adding custom template syntax, processing logic, and integration with external tools. Includes built-in extensions for internationalization, loop controls, expression statements, and debugging.

3

4

## Capabilities

5

6

### Extension Base Class

7

8

Base class for implementing custom template extensions with hooks for preprocessing, parsing, and code generation.

9

10

```python { .api }

11

class Extension:

12

def __init__(self, environment):

13

"""

14

Initialize extension.

15

16

Parameters:

17

environment: Jinja2 environment instance

18

"""

19

20

def bind(self, environment):

21

"""

22

Bind extension to different environment.

23

24

Parameters:

25

environment: New Jinja2 environment instance

26

27

Returns:

28

Extension: New extension instance bound to environment

29

"""

30

31

def preprocess(self, source, name, filename=None):

32

"""

33

Preprocess template source before parsing.

34

35

Parameters:

36

source: Template source code

37

name: Template name

38

filename: Template filename

39

40

Returns:

41

str: Preprocessed template source

42

"""

43

44

def filter_stream(self, stream):

45

"""

46

Filter token stream before parsing.

47

48

Parameters:

49

stream: Token stream iterator

50

51

Returns:

52

Iterator: Filtered token stream

53

"""

54

55

def parse(self, parser):

56

"""

57

Parse extension tags and return AST nodes.

58

59

Parameters:

60

parser: Jinja2 parser instance

61

62

Returns:

63

Node: AST node for extension functionality

64

"""

65

66

def attr(self, name, lineno=None):

67

"""

68

Create extension attribute node.

69

70

Parameters:

71

name: Attribute name

72

lineno: Line number for debugging

73

74

Returns:

75

Node: Attribute access AST node

76

"""

77

78

def call_method(self, name, args=None, kwargs=None, dyn_args=None, dyn_kwargs=None, lineno=None):

79

"""

80

Create extension method call node.

81

82

Parameters:

83

name: Method name

84

args: Method arguments

85

kwargs: Method keyword arguments

86

dyn_args: Dynamic arguments

87

dyn_kwargs: Dynamic keyword arguments

88

lineno: Line number for debugging

89

90

Returns:

91

Node: Method call AST node

92

"""

93

```

94

95

### Internationalization Extension

96

97

Built-in extension for internationalization and localization support using gettext-style translation functions.

98

99

```python { .api }

100

class InternationalizationExtension(Extension):

101

"""

102

Extension for internationalization support.

103

104

Adds:

105

- {% trans %}...{% endtrans %} blocks for translatable text

106

- {% pluralize %} for plural forms within trans blocks

107

- Automatic message extraction for translation tools

108

109

Usage:

110

env = Environment(extensions=['jinja2.ext.i18n'])

111

env.install_gettext_translations(translations)

112

"""

113

```

114

115

Usage example:

116

117

```python

118

from jinja2 import Environment

119

import gettext

120

121

# Setup translations

122

translations = gettext.translation('messages', 'locale', languages=['es'])

123

124

env = Environment(extensions=['jinja2.ext.i18n'])

125

env.install_gettext_translations(translations)

126

127

template_str = '''

128

{% trans %}Hello World!{% endtrans %}

129

{% trans count=items|length %}

130

There is {{ count }} item.

131

{% pluralize %}

132

There are {{ count }} items.

133

{% endtrans %}

134

'''

135

```

136

137

### Expression Statement Extension

138

139

Extension that adds the `{% do %}` tag for executing expressions without output.

140

141

```python { .api }

142

class ExprStmtExtension(Extension):

143

"""

144

Extension that adds {% do %} tag for expression statements.

145

146

Adds:

147

- {% do expression %} for executing expressions without output

148

- Useful for variable assignments and side effects

149

150

Usage:

151

env = Environment(extensions=['jinja2.ext.do'])

152

"""

153

```

154

155

Usage example:

156

157

```python

158

from jinja2 import Environment

159

160

env = Environment(extensions=['jinja2.ext.do'])

161

162

template_str = '''

163

{% set items = [] %}

164

{% do items.append('first') %}

165

{% do items.extend(['second', 'third']) %}

166

Items: {{ items | join(', ') }}

167

'''

168

```

169

170

### Loop Controls Extension

171

172

Extension that adds `{% break %}` and `{% continue %}` statements for loop control.

173

174

```python { .api }

175

class LoopControlsExtension(Extension):

176

"""

177

Extension that adds loop control statements.

178

179

Adds:

180

- {% break %} to exit loops early

181

- {% continue %} to skip to next loop iteration

182

183

Usage:

184

env = Environment(extensions=['jinja2.ext.loopcontrols'])

185

"""

186

```

187

188

Usage example:

189

190

```python

191

from jinja2 import Environment

192

193

env = Environment(extensions=['jinja2.ext.loopcontrols'])

194

195

template_str = '''

196

{% for item in items %}

197

{% if item is number and item < 0 %}

198

{% continue %}

199

{% endif %}

200

{% if item is string and item == 'STOP' %}

201

{% break %}

202

{% endif %}

203

Item: {{ item }}

204

{% endfor %}

205

'''

206

```

207

208

### Debug Extension

209

210

Extension that adds the `{% debug %}` tag for debugging template context and variables.

211

212

```python { .api }

213

class DebugExtension(Extension):

214

"""

215

Extension that adds {% debug %} tag for template debugging.

216

217

Adds:

218

- {% debug %} to print current template context

219

- Useful for development and troubleshooting

220

221

Usage:

222

env = Environment(extensions=['jinja2.ext.debug'])

223

"""

224

```

225

226

Usage example:

227

228

```python

229

from jinja2 import Environment

230

231

env = Environment(extensions=['jinja2.ext.debug'])

232

233

template_str = '''

234

User: {{ user.name }}

235

{% debug %}

236

Age: {{ user.age }}

237

'''

238

```

239

240

### Extension Loading

241

242

Extensions can be loaded by name or class when creating environments.

243

244

```python { .api }

245

# Load by string name

246

env = Environment(extensions=['jinja2.ext.i18n', 'jinja2.ext.do'])

247

248

# Load by class

249

from jinja2.ext import InternationalizationExtension, ExprStmtExtension

250

env = Environment(extensions=[InternationalizationExtension, ExprStmtExtension])

251

252

# Add after environment creation

253

env.add_extension('jinja2.ext.loopcontrols')

254

env.add_extension(DebugExtension)

255

```

256

257

## Custom Extension Development

258

259

### Basic Custom Extension

260

261

Example of creating a custom extension that adds a `{% cache %}` tag:

262

263

```python

264

from jinja2 import nodes

265

from jinja2.ext import Extension

266

267

class CacheExtension(Extension):

268

tags = {'cache'} # Tags handled by this extension

269

270

def parse(self, parser):

271

lineno = next(parser.stream).lineno

272

273

# Parse cache key

274

cache_key = parser.parse_expression()

275

276

# Parse optional timeout

277

timeout = None

278

if parser.stream.current.test('name:for'):

279

next(parser.stream) # consume 'for'

280

timeout = parser.parse_expression()

281

282

# Parse body

283

node = parser.parse_statements(['name:endcache'], drop_needle=True)

284

285

# Create cache node

286

return self.call_method('_cache_support',

287

[cache_key, timeout, nodes.List(node)],

288

lineno=lineno)

289

290

def _cache_support(self, cache_key, timeout, body):

291

"""Runtime cache support method."""

292

# Implementation would check cache, render if needed, store result

293

cache = getattr(self.environment, '_cache', {})

294

295

if cache_key in cache:

296

return cache[cache_key]

297

298

# Render body and cache result

299

result = ''.join(body)

300

cache[cache_key] = result

301

302

if not hasattr(self.environment, '_cache'):

303

self.environment._cache = cache

304

305

return result

306

307

# Usage

308

env = Environment(extensions=[CacheExtension])

309

template_str = '''

310

{% cache 'expensive_computation' for 300 %}

311

{{ expensive_function() }}

312

{% endcache %}

313

'''

314

```

315

316

### Advanced Extension Features

317

318

Extensions can modify parsing behavior, add global functions, and integrate with the compilation process:

319

320

```python

321

class AdvancedExtension(Extension):

322

def __init__(self, environment):

323

super().__init__(environment)

324

# Add global functions

325

environment.globals['custom_func'] = self.custom_function

326

327

def preprocess(self, source, name, filename=None):

328

# Modify source before parsing

329

return source.replace('[[', '{%').replace(']]', '%}')

330

331

def filter_stream(self, stream):

332

# Modify token stream

333

for token in stream:

334

if token.type == 'name' and token.value == 'old_keyword':

335

token = token._replace(value='new_keyword')

336

yield token

337

338

def custom_function(self, *args, **kwargs):

339

"""Custom global function available in templates."""

340

return f"Custom: {args} {kwargs}"

341

```

342

343

## Utility Functions

344

345

```python { .api }

346

def babel_extract(fileobj, keywords, comment_tags, options):

347

"""

348

Babel message extraction function for i18n extension.

349

350

Parameters:

351

fileobj: File-like object containing template source

352

keywords: Extraction keywords

353

comment_tags: Comment tags to extract

354

options: Extraction options

355

356

Returns:

357

Iterator: Extracted messages with line numbers and context

358

"""

359

```

360

361

## Types

362

363

```python { .api }

364

class ExtensionEnvironment:

365

"""

366

Extension execution environment providing access to parsing and compilation context.

367

368

Attributes:

369

environment: Jinja2 environment instance

370

parser: Current parser instance (during parsing)

371

compiler: Current compiler instance (during compilation)

372

"""

373

374

class ExtensionRegistry:

375

"""

376

Registry for managing loaded extensions and their capabilities.

377

378

Attributes:

379

extensions: Dictionary of loaded extension instances

380

tags: Set of all registered tag names

381

"""

382

```