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

bytecode-caching.mddocs/

0

# Bytecode Caching

1

2

Performance optimization system that caches compiled template bytecode to filesystem or external storage systems like Memcached. Significantly improves template loading performance in production environments.

3

4

## Capabilities

5

6

### Bytecode Cache Base Class

7

8

Abstract base class for implementing bytecode caching strategies with pluggable storage backends.

9

10

```python { .api }

11

class BytecodeCache:

12

def load_bytecode(self, bucket):

13

"""

14

Load bytecode from cache into bucket.

15

16

Parameters:

17

bucket: Bucket instance to load bytecode into

18

"""

19

20

def dump_bytecode(self, bucket):

21

"""

22

Save bytecode from bucket to cache.

23

24

Parameters:

25

bucket: Bucket instance containing bytecode to save

26

"""

27

28

def clear(self):

29

"""

30

Clear entire cache.

31

"""

32

33

def get_cache_key(self, name, filename=None):

34

"""

35

Generate cache key for template.

36

37

Parameters:

38

name: Template name

39

filename: Template filename (optional)

40

41

Returns:

42

str: Cache key string

43

"""

44

45

def get_source_checksum(self, source):

46

"""

47

Generate checksum for template source.

48

49

Parameters:

50

source: Template source code

51

52

Returns:

53

str: Source checksum

54

"""

55

56

def get_bucket(self, environment, name, filename, source):

57

"""

58

Get cache bucket for template.

59

60

Parameters:

61

environment: Jinja2 environment instance

62

name: Template name

63

filename: Template filename

64

source: Template source code

65

66

Returns:

67

Bucket: Cache bucket instance

68

"""

69

70

def set_bucket(self, bucket):

71

"""

72

Store cache bucket.

73

74

Parameters:

75

bucket: Bucket instance to store

76

"""

77

```

78

79

### Filesystem Bytecode Cache

80

81

Filesystem-based bytecode caching for persistent local storage of compiled templates.

82

83

```python { .api }

84

class FileSystemBytecodeCache(BytecodeCache):

85

def __init__(self, directory=None, pattern='__jinja2_%s.cache'):

86

"""

87

Initialize filesystem bytecode cache.

88

89

Parameters:

90

directory: Cache directory path (default: system temp directory)

91

pattern: Filename pattern with %s placeholder for cache key

92

"""

93

```

94

95

Usage example:

96

97

```python

98

from jinja2 import Environment, FileSystemLoader, FileSystemBytecodeCache

99

import tempfile

100

import os

101

102

# Create cache directory

103

cache_dir = os.path.join(tempfile.gettempdir(), 'jinja2_cache')

104

os.makedirs(cache_dir, exist_ok=True)

105

106

# Setup environment with bytecode cache

107

env = Environment(

108

loader=FileSystemLoader('templates'),

109

bytecode_cache=FileSystemBytecodeCache(cache_dir)

110

)

111

112

# First load compiles and caches

113

template1 = env.get_template('page.html') # Slow: compile + cache

114

template2 = env.get_template('page.html') # Fast: load from cache

115

```

116

117

### Memcached Bytecode Cache

118

119

Memcached-based bytecode caching for distributed caching across multiple application instances.

120

121

```python { .api }

122

class MemcachedBytecodeCache(BytecodeCache):

123

def __init__(self, client, prefix='jinja2/bytecode/', timeout=None, ignore_memcache_errors=True):

124

"""

125

Initialize Memcached bytecode cache.

126

127

Parameters:

128

client: Memcached client instance

129

prefix: Key prefix for cache entries (default: 'jinja2/bytecode/')

130

timeout: Cache timeout in seconds (default: None for no expiration)

131

ignore_memcache_errors: Ignore Memcached errors (default: True)

132

"""

133

```

134

135

Usage example:

136

137

```python

138

from jinja2 import Environment, FileSystemLoader, MemcachedBytecodeCache

139

import memcache

140

141

# Setup Memcached client

142

mc = memcache.Client(['127.0.0.1:11211'])

143

144

# Setup environment with Memcached cache

145

env = Environment(

146

loader=FileSystemLoader('templates'),

147

bytecode_cache=MemcachedBytecodeCache(mc, timeout=3600) # 1 hour timeout

148

)

149

150

template = env.get_template('page.html')

151

```

152

153

### Cache Bucket

154

155

Cache storage unit that manages bytecode serialization and metadata.

156

157

```python { .api }

158

class Bucket:

159

def __init__(self, environment, key, checksum):

160

"""

161

Initialize cache bucket.

162

163

Parameters:

164

environment: Jinja2 environment instance

165

key: Cache key

166

checksum: Source checksum

167

"""

168

169

def load_bytecode(self, f):

170

"""

171

Load bytecode from file-like object.

172

173

Parameters:

174

f: File-like object to read from

175

"""

176

177

def write_bytecode(self, f):

178

"""

179

Write bytecode to file-like object.

180

181

Parameters:

182

f: File-like object to write to

183

"""

184

185

def bytecode_from_string(self, string):

186

"""

187

Load bytecode from byte string.

188

189

Parameters:

190

string: Bytecode as bytes

191

"""

192

193

def bytecode_to_string(self):

194

"""

195

Convert bytecode to byte string.

196

197

Returns:

198

bytes: Bytecode as bytes

199

"""

200

201

def reset(self):

202

"""

203

Clear bytecode from bucket.

204

"""

205

```

206

207

## Custom Cache Implementation

208

209

### Redis Bytecode Cache Example

210

211

Example implementation of a custom Redis-based bytecode cache:

212

213

```python

214

import pickle

215

from jinja2.bccache import BytecodeCache, Bucket

216

217

class RedisBytecodeCache(BytecodeCache):

218

def __init__(self, redis_client, prefix='jinja2:', timeout=3600):

219

self.redis = redis_client

220

self.prefix = prefix

221

self.timeout = timeout

222

223

def load_bytecode(self, bucket):

224

key = self.prefix + bucket.key

225

data = self.redis.get(key)

226

if data is not None:

227

bucket.bytecode_from_string(data)

228

229

def dump_bytecode(self, bucket):

230

key = self.prefix + bucket.key

231

data = bucket.bytecode_to_string()

232

if data is not None:

233

self.redis.setex(key, self.timeout, data)

234

235

def clear(self):

236

keys = self.redis.keys(self.prefix + '*')

237

if keys:

238

self.redis.delete(*keys)

239

240

# Usage

241

import redis

242

r = redis.Redis()

243

env = Environment(

244

loader=FileSystemLoader('templates'),

245

bytecode_cache=RedisBytecodeCache(r)

246

)

247

```

248

249

### Database Bytecode Cache Example

250

251

Example implementation using a database for bytecode storage:

252

253

```python

254

import sqlite3

255

from jinja2.bccache import BytecodeCache

256

257

class SQLiteBytecodeCache(BytecodeCache):

258

def __init__(self, database_path):

259

self.db_path = database_path

260

self._init_database()

261

262

def _init_database(self):

263

conn = sqlite3.connect(self.db_path)

264

conn.execute('''

265

CREATE TABLE IF NOT EXISTS bytecode_cache (

266

key TEXT PRIMARY KEY,

267

bytecode BLOB,

268

checksum TEXT,

269

created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

270

)

271

''')

272

conn.commit()

273

conn.close()

274

275

def load_bytecode(self, bucket):

276

conn = sqlite3.connect(self.db_path)

277

cursor = conn.execute(

278

'SELECT bytecode FROM bytecode_cache WHERE key = ? AND checksum = ?',

279

(bucket.key, bucket.checksum)

280

)

281

row = cursor.fetchone()

282

conn.close()

283

284

if row:

285

bucket.bytecode_from_string(row[0])

286

287

def dump_bytecode(self, bucket):

288

data = bucket.bytecode_to_string()

289

if data is not None:

290

conn = sqlite3.connect(self.db_path)

291

conn.execute(

292

'INSERT OR REPLACE INTO bytecode_cache (key, bytecode, checksum) VALUES (?, ?, ?)',

293

(bucket.key, data, bucket.checksum)

294

)

295

conn.commit()

296

conn.close()

297

298

def clear(self):

299

conn = sqlite3.connect(self.db_path)

300

conn.execute('DELETE FROM bytecode_cache')

301

conn.commit()

302

conn.close()

303

```

304

305

## Performance Considerations

306

307

### Cache Effectiveness

308

309

Bytecode caching provides the most benefit when:

310

311

- Templates are reused frequently

312

- Template compilation is a bottleneck

313

- Templates contain complex logic or many includes/extends

314

- Running in production with stable templates

315

316

### Cache Invalidation

317

318

Caches automatically invalidate when:

319

320

- Template source files change (filesystem modification time)

321

- Template source content changes (checksum comparison)

322

- Environment configuration changes

323

- Jinja2 version changes

324

325

### Memory vs. Disk Trade-offs

326

327

```python

328

# In-memory cache for development

329

env = Environment(

330

loader=FileSystemLoader('templates'),

331

cache_size=100, # Keep 100 compiled templates in memory

332

auto_reload=True # Auto-reload on changes

333

)

334

335

# Disk cache for production

336

env = Environment(

337

loader=FileSystemLoader('templates'),

338

bytecode_cache=FileSystemBytecodeCache('/var/cache/jinja2'),

339

cache_size=0, # Disable memory cache

340

auto_reload=False # Disable auto-reload

341

)

342

```

343

344

## Types

345

346

```python { .api }

347

class CacheStatistics:

348

"""

349

Cache performance statistics for monitoring and optimization.

350

351

Attributes:

352

hits: Number of cache hits

353

misses: Number of cache misses

354

hit_ratio: Cache hit ratio (hits / (hits + misses))

355

size: Current cache size

356

max_size: Maximum cache size

357

"""

358

359

class CacheEntry:

360

"""

361

Individual cache entry with metadata.

362

363

Attributes:

364

key: Cache key

365

checksum: Source checksum

366

bytecode: Compiled bytecode

367

created_at: Creation timestamp

368

accessed_at: Last access timestamp

369

"""

370

```