or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

built-in-context.mdbuilt-in-functions.mdexternal-integration.mdindex.mdmodule-system.mdplugin-configuration.mdtemplate-environment.md

module-system.mddocs/

0

# Module System

1

2

Interface for defining custom variables, macros, and filters in Python modules. Provides the primary extension mechanism for adding functionality to the template environment.

3

4

## Capabilities

5

6

### Primary Module Hook

7

8

The main entry point for defining template functionality in Python modules.

9

10

```python { .api }

11

def define_env(env):

12

"""

13

Primary hook for module definition.

14

15

Args:

16

env: MacrosPlugin instance with access to variables, macros, filters

17

18

This function is called during plugin initialization and must be present

19

in the module for it to be loaded successfully.

20

"""

21

```

22

23

#### Usage Examples

24

25

Basic module definition:

26

```python

27

# main.py

28

def define_env(env):

29

"""Define variables, macros, and filters"""

30

31

# Add variables

32

env.variables['version'] = '1.0.0'

33

env.variables['author'] = 'John Doe'

34

35

# Define macro using decorator

36

@env.macro

37

def greeting(name):

38

return f"Hello, {name}!"

39

40

# Define filter using decorator

41

@env.filter

42

def uppercase(text):

43

return text.upper()

44

45

# Direct registration with custom name

46

def calculate_discount(price, percent):

47

return price * (1 - percent / 100)

48

49

env.macro(calculate_discount, 'discount')

50

```

51

52

Advanced module with debugging:

53

```python

54

def define_env(env):

55

"""Advanced module with debug capabilities"""

56

57

# Enable debug output

58

chatter = env.start_chatting('MY_MODULE')

59

chatter("Module loading started")

60

61

# Access configuration

62

if env.conf.get('site_name'):

63

env.variables['site_title'] = env.conf['site_name'].upper()

64

65

# Complex macro with error handling

66

@env.macro

67

def include_file(filename, start_line=0, end_line=None):

68

"""Include file content with optional line range"""

69

try:

70

full_path = os.path.join(env.project_dir, filename)

71

with open(full_path, 'r') as f:

72

lines = f.readlines()

73

return ''.join(lines[start_line:end_line])

74

except FileNotFoundError:

75

return f"File not found: {filename}"

76

77

chatter("Module loaded successfully")

78

```

79

80

### Page Processing Hooks

81

82

Optional hooks for pre and post-processing pages during rendering.

83

84

```python { .api }

85

def on_pre_page_macros(env):

86

"""

87

Called before macro rendering for each page.

88

89

Args:

90

env: MacrosPlugin instance with page context available

91

92

The env.page and env.markdown properties are available.

93

Can modify env.markdown to alter page content before template rendering.

94

"""

95

96

def on_post_page_macros(env):

97

"""

98

Called after macro rendering for each page.

99

100

Args:

101

env: MacrosPlugin instance with page context available

102

103

The env.page and env.markdown properties are available.

104

Can modify env.markdown to alter final page content.

105

"""

106

```

107

108

#### Usage Examples

109

110

Adding dynamic content:

111

```python

112

def on_pre_page_macros(env):

113

"""Add dynamic header before processing"""

114

header = f"\\n## Page: {env.page.title}\\nLast built: {{{{ now() }}}}\\n"

115

env.markdown = header + env.markdown

116

117

def on_post_page_macros(env):

118

"""Add footer after processing"""

119

footer = f"\\n\\n---\\n*Generated on {env.page.file.src_path}*"

120

env.markdown += footer

121

```

122

123

Conditional processing:

124

```python

125

def on_pre_page_macros(env):

126

"""Conditional page modifications"""

127

# Only process API docs

128

if env.page.file.src_path.startswith('api/'):

129

env.markdown = "{% include 'api_header.md' %}\\n" + env.markdown

130

131

# Add warnings for draft pages

132

if 'draft' in env.page.meta:

133

warning = "!!! warning\\n This page is a draft\\n\\n"

134

env.markdown = warning + env.markdown

135

```

136

137

### Build Hook

138

139

Optional hook called after the entire site build is complete.

140

141

```python { .api }

142

def on_post_build(env):

143

"""

144

Called after the complete site build.

145

146

Args:

147

env: MacrosPlugin instance

148

149

No page context available. Used for cleanup, file generation,

150

or other post-build operations.

151

"""

152

```

153

154

#### Usage Examples

155

156

Generate additional files:

157

```python

158

def on_post_build(env):

159

"""Generate sitemap or other files"""

160

import json

161

162

# Generate metadata file

163

metadata = {

164

'build_time': str(env.variables.get('now', 'unknown')),

165

'site_name': env.conf.get('site_name'),

166

'pages': len(env.variables.get('navigation', {}).get('pages', []))

167

}

168

169

output_path = os.path.join(env.project_dir, 'site', 'metadata.json')

170

with open(output_path, 'w') as f:

171

json.dump(metadata, f, indent=2)

172

```

173

174

Cleanup operations:

175

```python

176

def on_post_build(env):

177

"""Post-build cleanup"""

178

temp_dir = os.path.join(env.project_dir, 'temp_build_files')

179

if os.path.exists(temp_dir):

180

shutil.rmtree(temp_dir)

181

```

182

183

### Legacy Module Hook

184

185

Deprecated but still supported module definition interface.

186

187

```python { .api }

188

def declare_variables(variables, macro):

189

"""

190

Legacy hook for module definition (deprecated).

191

192

Args:

193

variables: Dictionary to add variables to

194

macro: Decorator function for registering macros

195

196

Prefer define_env() for new modules.

197

"""

198

```

199

200

#### Usage Example

201

202

```python

203

def declare_variables(variables, macro):

204

"""Legacy module definition (prefer define_env)"""

205

206

variables['legacy_var'] = 'value'

207

208

@macro

209

def legacy_function():

210

return "This uses the old API"

211

```

212

213

## Module Loading

214

215

### Local Modules

216

217

Modules are loaded from the project directory:

218

219

- **File module**: `main.py` in project root

220

- **Package module**: `main/` directory with `__init__.py`

221

- **Custom name**: Set `module_name` in configuration

222

223

### Pluglet Modules

224

225

Pre-installed modules distributed via PyPI:

226

227

```yaml

228

plugins:

229

- macros:

230

modules:

231

- package_name # Import as package_name

232

- source_name:import_name # Install source_name, import as import_name

233

```

234

235

The plugin will automatically install missing packages using pip.

236

237

### Module Discovery

238

239

The plugin looks for these functions in order:

240

1. `define_env(env)` - Primary hook (required)

241

2. `on_pre_page_macros(env)` - Optional pre-processing

242

3. `on_post_page_macros(env)` - Optional post-processing

243

4. `on_post_build(env)` - Optional build completion

244

245

At least `define_env` must be present for the module to load successfully.

246

247

## Error Handling

248

249

### Module Loading Errors

250

251

```python

252

# Module not found

253

raise ImportError("Macro plugin could not find custom 'module_name' module")

254

255

# No standard functions found

256

raise NameError("None of the standard functions was found in module")

257

258

# Function registration conflicts

259

raise KeyError("Registration error: macro 'name' already exists")

260

```

261

262

### Best Practices

263

264

1. **Always implement `define_env`** - Required for module loading

265

2. **Use descriptive names** - Clear macro and filter names

266

3. **Handle errors gracefully** - Return meaningful error messages

267

4. **Document your functions** - Include docstrings for better debugging

268

5. **Use env.start_chatting()** - For debug output when verbose mode is enabled

269

6. **Test with different configurations** - Ensure compatibility with various setups