or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdcore-freezing.mdindex.mdurl-generation.mdutilities.md

utilities.mddocs/

0

# Utility Functions

1

2

Helper functions for directory operations, relative URL generation, and file system utilities. These functions support the core freezing operations and provide additional functionality for working with static sites.

3

4

## Capabilities

5

6

### Directory Operations

7

8

Functions for traversing and processing directory structures.

9

10

```python { .api }

11

def walk_directory(root, ignore=()):

12

"""

13

Walk directory and yield slash-separated paths relative to root.

14

15

Used to implement URL generator for static files and file discovery.

16

17

Parameters:

18

- root: Directory path to walk (str or Path)

19

- ignore: List of fnmatch patterns to ignore

20

21

Yields:

22

str: Relative file paths with forward slashes

23

24

Ignore patterns:

25

- Patterns with slash are matched against full path

26

- Patterns without slash match individual path components

27

- Patterns ending with '/' match directories

28

"""

29

```

30

31

### URL Generation

32

33

Functions for generating relative URLs and handling URL transformations.

34

35

```python { .api }

36

def relative_url_for(endpoint, **values):

37

"""

38

Like Flask's url_for but returns relative URLs when possible.

39

40

Absolute URLs (with _external=True or different subdomain) are unchanged.

41

Relative URLs are converted based on current request context path.

42

URLs ending with '/' get 'index.html' appended for static compatibility.

43

44

Parameters:

45

- endpoint: Flask endpoint name

46

- **values: URL parameters (same as url_for)

47

48

Returns:

49

str: Relative URL or absolute URL if necessary

50

51

Note: Should only be used with Frozen-Flask, not in live Flask apps

52

"""

53

```

54

55

## Usage Examples

56

57

### Directory Walking

58

59

```python

60

from flask_frozen import walk_directory

61

from pathlib import Path

62

63

# Basic directory traversal

64

static_dir = Path('static')

65

for filepath in walk_directory(static_dir):

66

print(f"Found file: {filepath}")

67

# Output: css/style.css, js/app.js, images/logo.png, etc.

68

```

69

70

### Directory Walking with Ignore Patterns

71

72

```python

73

# Ignore specific files and directories

74

ignore_patterns = [

75

'*.pyc', # Ignore Python bytecode

76

'*.pyo', # Ignore optimized bytecode

77

'__pycache__/', # Ignore Python cache directories

78

'node_modules/', # Ignore Node.js dependencies

79

'*.scss', # Ignore SCSS source files

80

'src/*', # Ignore entire src directory

81

'.DS_Store', # Ignore macOS system files

82

]

83

84

for filepath in walk_directory('assets', ignore=ignore_patterns):

85

print(f"Will be included: {filepath}")

86

```

87

88

### Complex Ignore Patterns

89

90

```python

91

# Advanced ignore patterns

92

patterns = [

93

# Pattern matching examples:

94

'*.log', # Matches any .log file

95

'temp/', # Matches temp directory

96

'draft-*', # Matches files starting with 'draft-'

97

'*/cache/*', # Matches cache directories anywhere

98

'build/*.map', # Matches .map files in build directory

99

'.git*', # Matches .git, .gitignore, etc.

100

]

101

102

# Custom file filtering

103

def custom_file_filter(root_dir):

104

files = []

105

for filepath in walk_directory(root_dir, ignore=patterns):

106

# Additional custom filtering

107

if not filepath.startswith('_'): # Skip files starting with underscore

108

files.append(filepath)

109

return files

110

```

111

112

### Relative URL Generation

113

114

```python

115

from flask import Flask, request

116

from flask_frozen import relative_url_for

117

118

app = Flask(__name__)

119

120

@app.route('/blog/<slug>/')

121

def blog_post(slug):

122

return f'Blog post: {slug}'

123

124

# In a template or view context

125

with app.test_request_context('/blog/python-tips/'):

126

# From /blog/python-tips/ to /blog/flask-guide/

127

url = relative_url_for('blog_post', slug='flask-guide')

128

print(url) # Output: ../flask-guide/

129

130

# From /blog/python-tips/ to homepage

131

url = relative_url_for('index')

132

print(url) # Output: ../../

133

```

134

135

### URL Generation in Templates

136

137

When `FREEZER_RELATIVE_URLS` is enabled, templates automatically use `relative_url_for`:

138

139

```html

140

<!-- In Jinja2 template -->

141

<a href="{{ url_for('blog_post', slug='python-tips') }}">Python Tips</a>

142

<!-- Generates relative URL like: ../python-tips/ -->

143

144

<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">

145

<!-- Generates relative URL like: ../../static/css/style.css -->

146

```

147

148

### Custom Static File Discovery

149

150

```python

151

from flask_frozen import walk_directory

152

import os

153

154

def find_assets(asset_type):

155

"""Find assets of a specific type"""

156

extensions = {

157

'images': ['*.jpg', '*.png', '*.gif', '*.svg'],

158

'styles': ['*.css'],

159

'scripts': ['*.js'],

160

'fonts': ['*.woff', '*.woff2', '*.ttf', '*.eot'],

161

}

162

163

if asset_type not in extensions:

164

return []

165

166

# Ignore everything except the desired asset type

167

ignore_patterns = []

168

for other_type, exts in extensions.items():

169

if other_type != asset_type:

170

ignore_patterns.extend(exts)

171

172

assets = []

173

for filepath in walk_directory('static', ignore=ignore_patterns):

174

assets.append(filepath)

175

176

return assets

177

178

# Find all images

179

images = find_assets('images')

180

print(f"Found {len(images)} images")

181

```

182

183

### Building File Manifests

184

185

```python

186

from flask_frozen import walk_directory

187

import json

188

import hashlib

189

from pathlib import Path

190

191

def create_asset_manifest(static_dir):

192

"""Create a manifest of all static files with hashes"""

193

manifest = {}

194

195

for filepath in walk_directory(static_dir):

196

full_path = Path(static_dir) / filepath

197

198

# Calculate file hash for cache busting

199

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

200

file_hash = hashlib.md5(f.read()).hexdigest()[:8]

201

202

# Add to manifest

203

name, ext = filepath.rsplit('.', 1)

204

hashed_name = f"{name}.{file_hash}.{ext}"

205

206

manifest[filepath] = {

207

'hashed': hashed_name,

208

'size': full_path.stat().st_size,

209

'hash': file_hash,

210

}

211

212

return manifest

213

214

# Create and save manifest

215

manifest = create_asset_manifest('static')

216

with open('build/assets-manifest.json', 'w') as f:

217

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

218

```

219

220

### Directory Synchronization

221

222

```python

223

from flask_frozen import walk_directory

224

import shutil

225

from pathlib import Path

226

227

def sync_directories(source, target, ignore_patterns=None):

228

"""Sync directories with ignore patterns"""

229

if ignore_patterns is None:

230

ignore_patterns = []

231

232

source_path = Path(source)

233

target_path = Path(target)

234

target_path.mkdir(parents=True, exist_ok=True)

235

236

# Copy files that match criteria

237

for filepath in walk_directory(source, ignore=ignore_patterns):

238

src_file = source_path / filepath

239

dst_file = target_path / filepath

240

241

# Create directory if needed

242

dst_file.parent.mkdir(parents=True, exist_ok=True)

243

244

# Copy file

245

shutil.copy2(src_file, dst_file)

246

print(f"Copied: {filepath}")

247

248

# Example usage

249

sync_directories(

250

'assets',

251

'build/assets',

252

ignore_patterns=['*.scss', '*/src/*', '.DS_Store']

253

)

254

```

255

256

## Integration with Freezer

257

258

These utilities integrate seamlessly with the Freezer class:

259

260

```python

261

from flask import Flask

262

from flask_frozen import Freezer, walk_directory

263

264

app = Flask(__name__)

265

freezer = Freezer(app)

266

267

# Custom static file generator using walk_directory

268

@freezer.register_generator

269

def custom_assets():

270

asset_dirs = ['media', 'uploads', 'downloads']

271

for asset_dir in asset_dirs:

272

if Path(asset_dir).exists():

273

for filepath in walk_directory(asset_dir):

274

# Generate URL for each asset file

275

yield f'/{asset_dir}/{filepath}'

276

277

# Use relative URLs in frozen site

278

app.config['FREEZER_RELATIVE_URLS'] = True

279

280

freezer.freeze()

281

```