or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

blueprints.mdcli.mdconfiguration.mdcontext-globals.mdcore-application.mdhelpers.mdindex.mdjson-support.mdrequest-response.mdrouting.mdsessions.mdsignals.mdtemplates.mdtesting.md

helpers.mddocs/

0

# Helpers and Utilities

1

2

Flask provides utility functions for common web development tasks including redirects, error handling, file operations, and message flashing.

3

4

## Capabilities

5

6

### HTTP Response Helpers

7

8

Functions for creating HTTP responses and handling redirects.

9

10

```python { .api }

11

def redirect(location: str, code: int = 302, Response: type | None = None) -> Response:

12

"""

13

Create a redirect response to a different location.

14

15

Args:

16

location: URL to redirect to

17

code: HTTP status code (301, 302, 303, 307, 308)

18

Response: Response class to use

19

20

Returns:

21

Redirect response object

22

"""

23

24

def abort(code: int | BaseResponse, *args, **kwargs) -> NoReturn:

25

"""

26

Abort the current request with an HTTP error.

27

28

Args:

29

code: HTTP status code or Response object

30

*args: Additional arguments for the exception

31

**kwargs: Additional keyword arguments

32

33

Raises:

34

HTTPException: With the specified status code

35

"""

36

37

def make_response(*args) -> Response:

38

"""

39

Convert arguments into a Response object.

40

41

Args:

42

*args: Arguments that would normally be returned from a view function

43

44

Returns:

45

Response object that can be modified before returning

46

"""

47

```

48

49

### File Operations

50

51

Functions for sending files and handling file downloads.

52

53

```python { .api }

54

def send_file(

55

path_or_file: os.PathLike | str | IO[bytes],

56

mimetype: str | None = None,

57

as_attachment: bool = False,

58

download_name: str | None = None,

59

conditional: bool = True,

60

etag: bool | str = True,

61

last_modified: datetime | int | float | None = None,

62

max_age: int | Callable[[str | None], int | None] | None = None

63

) -> Response:

64

"""

65

Send a file to the client.

66

67

Args:

68

path_or_file: Path to file or file-like object

69

mimetype: MIME type (auto-detected if None)

70

as_attachment: Send as attachment (triggers download)

71

download_name: Filename for download

72

conditional: Enable conditional responses (304 Not Modified)

73

etag: Enable ETag header (True, False, or custom ETag)

74

last_modified: Last modified timestamp

75

max_age: Cache max age in seconds

76

77

Returns:

78

Response with file contents

79

"""

80

81

def send_from_directory(

82

directory: str,

83

path: str,

84

**kwargs

85

) -> Response:

86

"""

87

Send a file from a directory safely.

88

89

Args:

90

directory: Directory containing the file

91

path: Relative path to file within directory

92

**kwargs: Additional arguments passed to send_file()

93

94

Returns:

95

Response with file contents

96

97

Raises:

98

NotFound: If file doesn't exist or path is unsafe

99

"""

100

```

101

102

### Message Flashing

103

104

Functions for displaying one-time messages to users.

105

106

```python { .api }

107

def flash(message: str, category: str = "message") -> None:

108

"""

109

Flash a message that will be displayed on the next request.

110

111

Args:

112

message: Message text to flash

113

category: Message category (e.g., 'error', 'info', 'warning')

114

"""

115

116

def get_flashed_messages(

117

with_categories: bool = False,

118

category_filter: list[str] = []

119

) -> list[str] | list[tuple[str, str]]:

120

"""

121

Get and remove all flashed messages.

122

123

Args:

124

with_categories: Return (category, message) tuples

125

category_filter: Only return messages from these categories

126

127

Returns:

128

List of messages or (category, message) tuples

129

"""

130

```

131

132

### Template Utilities

133

134

Functions for working with templates outside of normal rendering.

135

136

```python { .api }

137

def get_template_attribute(template_name: str, attribute: str) -> Any:

138

"""

139

Load a template and get one of its attributes.

140

141

Args:

142

template_name: Template filename

143

attribute: Attribute name to retrieve

144

145

Returns:

146

Template attribute value

147

148

Raises:

149

TemplateNotFound: If template doesn't exist

150

AttributeError: If attribute doesn't exist

151

"""

152

```

153

154

### Context Streaming

155

156

Function for maintaining request context in generators and iterators.

157

158

```python { .api }

159

def stream_with_context(generator_or_function) -> Iterator:

160

"""

161

Stream with the current request context.

162

163

Args:

164

generator_or_function: Generator function or iterator

165

166

Returns:

167

Iterator that preserves request context

168

"""

169

```

170

171

## Usage Examples

172

173

### Redirects and URL Handling

174

175

```python

176

from flask import Flask, redirect, url_for, request

177

178

app = Flask(__name__)

179

180

@app.route('/')

181

def home():

182

return 'Home Page'

183

184

@app.route('/login')

185

def login():

186

return 'Login Page'

187

188

@app.route('/dashboard')

189

def dashboard():

190

# Redirect to login if not authenticated

191

if not session.get('logged_in'):

192

return redirect(url_for('login'))

193

return 'Dashboard'

194

195

@app.route('/old-page')

196

def old_page():

197

# Permanent redirect (301)

198

return redirect(url_for('home'), code=301)

199

200

@app.route('/external')

201

def external_redirect():

202

# Redirect to external URL

203

return redirect('https://www.example.com')

204

205

@app.route('/conditional-redirect')

206

def conditional_redirect():

207

next_page = request.args.get('next')

208

if next_page:

209

return redirect(next_page)

210

return redirect(url_for('home'))

211

```

212

213

### Error Handling with Abort

214

215

```python

216

from flask import Flask, abort, request, jsonify

217

218

app = Flask(__name__)

219

220

@app.route('/user/<int:user_id>')

221

def get_user(user_id):

222

# Validate user ID

223

if user_id <= 0:

224

abort(400, description="Invalid user ID")

225

226

# Simulate user lookup

227

if user_id > 1000:

228

abort(404, description="User not found")

229

230

# Simulate permission check

231

if user_id == 999:

232

abort(403, description="Access denied")

233

234

return {'id': user_id, 'name': f'User {user_id}'}

235

236

@app.route('/admin')

237

def admin_area():

238

# Check authentication

239

if not session.get('logged_in'):

240

abort(401) # Unauthorized

241

242

# Check admin privileges

243

if not session.get('is_admin'):

244

abort(403) # Forbidden

245

246

return 'Admin Area'

247

248

@app.route('/api/data', methods=['POST'])

249

def create_data():

250

if not request.is_json:

251

abort(400, description="Content-Type must be application/json")

252

253

data = request.get_json()

254

if not data or 'name' not in data:

255

abort(422, description="Missing required field: name")

256

257

return jsonify({'status': 'created', 'data': data}), 201

258

```

259

260

### Response Creation with make_response

261

262

```python

263

from flask import Flask, make_response, render_template, jsonify

264

265

app = Flask(__name__)

266

267

@app.route('/custom-headers')

268

def custom_headers():

269

# Create response with custom headers

270

response = make_response(render_template('index.html'))

271

response.headers['X-Custom-Header'] = 'Custom Value'

272

response.headers['Cache-Control'] = 'no-cache'

273

return response

274

275

@app.route('/api/data')

276

def api_data():

277

# Create JSON response with custom status and headers

278

data = {'message': 'Hello, World!'}

279

response = make_response(jsonify(data))

280

response.status_code = 200

281

response.headers['X-API-Version'] = '1.0'

282

return response

283

284

@app.route('/download-csv')

285

def download_csv():

286

csv_data = "name,email\nJohn,john@example.com\nJane,jane@example.com"

287

response = make_response(csv_data)

288

response.headers['Content-Type'] = 'text/csv'

289

response.headers['Content-Disposition'] = 'attachment; filename=users.csv'

290

return response

291

```

292

293

### File Downloads and Uploads

294

295

```python

296

from flask import Flask, send_file, send_from_directory, request, abort

297

import os

298

from werkzeug.utils import secure_filename

299

300

app = Flask(__name__)

301

app.config['UPLOAD_FOLDER'] = 'uploads'

302

app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max

303

304

@app.route('/download/<filename>')

305

def download_file(filename):

306

# Send file from uploads directory

307

try:

308

return send_from_directory(

309

app.config['UPLOAD_FOLDER'],

310

filename,

311

as_attachment=True

312

)

313

except FileNotFoundError:

314

abort(404)

315

316

@app.route('/view/<filename>')

317

def view_file(filename):

318

# View file in browser (not as download)

319

return send_from_directory(

320

app.config['UPLOAD_FOLDER'],

321

filename,

322

as_attachment=False

323

)

324

325

@app.route('/generate-report')

326

def generate_report():

327

# Generate and send a file

328

import tempfile

329

import csv

330

331

# Create temporary file

332

temp_file = tempfile.NamedTemporaryFile(

333

mode='w',

334

suffix='.csv',

335

delete=False

336

)

337

338

# Write CSV data

339

writer = csv.writer(temp_file)

340

writer.writerow(['Name', 'Email', 'Role'])

341

writer.writerow(['John Doe', 'john@example.com', 'Admin'])

342

writer.writerow(['Jane Smith', 'jane@example.com', 'User'])

343

temp_file.close()

344

345

return send_file(

346

temp_file.name,

347

as_attachment=True,

348

download_name='users.csv',

349

mimetype='text/csv'

350

)

351

352

@app.route('/upload', methods=['POST'])

353

def upload_file():

354

if 'file' not in request.files:

355

abort(400, description="No file uploaded")

356

357

file = request.files['file']

358

if file.filename == '':

359

abort(400, description="No file selected")

360

361

if file:

362

filename = secure_filename(file.filename)

363

filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)

364

file.save(filepath)

365

366

return {

367

'status': 'uploaded',

368

'filename': filename,

369

'download_url': url_for('download_file', filename=filename)

370

}

371

```

372

373

### Message Flashing

374

375

```python

376

from flask import Flask, flash, get_flashed_messages, render_template, redirect, url_for, request

377

378

app = Flask(__name__)

379

app.secret_key = 'your-secret-key'

380

381

@app.route('/')

382

def home():

383

return render_template('home.html')

384

385

@app.route('/login', methods=['GET', 'POST'])

386

def login():

387

if request.method == 'POST':

388

username = request.form.get('username')

389

password = request.form.get('password')

390

391

if not username or not password:

392

flash('Username and password are required', 'error')

393

elif username == 'admin' and password == 'secret':

394

flash('Login successful!', 'success')

395

session['logged_in'] = True

396

return redirect(url_for('dashboard'))

397

else:

398

flash('Invalid credentials', 'error')

399

400

return render_template('login.html')

401

402

@app.route('/dashboard')

403

def dashboard():

404

if not session.get('logged_in'):

405

flash('Please log in to access the dashboard', 'warning')

406

return redirect(url_for('login'))

407

408

flash('Welcome to your dashboard!', 'info')

409

return render_template('dashboard.html')

410

411

@app.route('/profile', methods=['POST'])

412

def update_profile():

413

# Simulate profile update

414

name = request.form.get('name')

415

email = request.form.get('email')

416

417

if name and email:

418

flash('Profile updated successfully!', 'success')

419

else:

420

flash('Please fill in all fields', 'error')

421

422

return redirect(url_for('dashboard'))

423

424

@app.route('/messages')

425

def show_messages():

426

# Get messages with categories

427

messages = get_flashed_messages(with_categories=True)

428

return render_template('messages.html', messages=messages)

429

430

@app.route('/warnings')

431

def show_warnings():

432

# Get only warning messages

433

warnings = get_flashed_messages(category_filter=['warning', 'error'])

434

return render_template('warnings.html', warnings=warnings)

435

```

436

437

Template for displaying messages (`templates/base.html`):

438

```html

439

<!DOCTYPE html>

440

<html>

441

<head>

442

<title>Flask App</title>

443

<style>

444

.flash-message { padding: 10px; margin: 10px 0; border-radius: 4px; }

445

.flash-success { background-color: #d4edda; color: #155724; }

446

.flash-error { background-color: #f8d7da; color: #721c24; }

447

.flash-warning { background-color: #fff3cd; color: #856404; }

448

.flash-info { background-color: #d1ecf1; color: #0c5460; }

449

</style>

450

</head>

451

<body>

452

<!-- Display flashed messages -->

453

{% with messages = get_flashed_messages(with_categories=true) %}

454

{% if messages %}

455

{% for category, message in messages %}

456

<div class="flash-message flash-{{ category }}">

457

{{ message }}

458

</div>

459

{% endfor %}

460

{% endif %}

461

{% endwith %}

462

463

{% block content %}{% endblock %}

464

</body>

465

</html>

466

```

467

468

### Template Attributes

469

470

```python

471

from flask import Flask, get_template_attribute, render_template

472

473

app = Flask(__name__)

474

475

@app.route('/macro-example')

476

def macro_example():

477

# Get a macro from a template

478

render_form = get_template_attribute('macros.html', 'render_form')

479

480

# Use the macro programmatically

481

form_html = render_form(

482

action='/submit',

483

method='POST',

484

fields=[

485

{'name': 'username', 'type': 'text', 'label': 'Username'},

486

{'name': 'email', 'type': 'email', 'label': 'Email'}

487

]

488

)

489

490

return f'<h1>Generated Form</h1>{form_html}'

491

492

@app.route('/template-vars')

493

def template_vars():

494

# Get variables from template

495

config_data = get_template_attribute('config.html', 'app_config')

496

return {'config': config_data}

497

```

498

499

### Streaming with Context

500

501

```python

502

from flask import Flask, stream_with_context, request, g

503

import time

504

505

app = Flask(__name__)

506

507

@app.before_request

508

def before_request():

509

g.user_id = request.headers.get('X-User-ID', 'anonymous')

510

511

@app.route('/stream')

512

def stream_data():

513

def generate():

514

for i in range(10):

515

# Access request context variables

516

yield f"data: User {g.user_id}, Item {i}\n\n"

517

time.sleep(1)

518

519

return Response(

520

stream_with_context(generate()),

521

mimetype='text/plain'

522

)

523

524

@app.route('/sse')

525

def server_sent_events():

526

def event_stream():

527

count = 0

528

while count < 50:

529

# Use request context in generator

530

user_id = g.user_id

531

yield f"data: {{\"user\": \"{user_id}\", \"count\": {count}}}\n\n"

532

count += 1

533

time.sleep(2)

534

535

return Response(

536

stream_with_context(event_stream()),

537

mimetype='text/event-stream',

538

headers={

539

'Cache-Control': 'no-cache',

540

'Connection': 'keep-alive'

541

}

542

)

543

```

544

545

### Advanced File Handling

546

547

```python

548

from flask import Flask, send_file, request, abort

549

from datetime import datetime, timedelta

550

import mimetypes

551

import os

552

553

app = Flask(__name__)

554

555

@app.route('/file/<path:filename>')

556

def serve_file(filename):

557

file_path = os.path.join('files', filename)

558

559

if not os.path.exists(file_path):

560

abort(404)

561

562

# Get file info

563

stat = os.stat(file_path)

564

last_modified = datetime.fromtimestamp(stat.st_mtime)

565

566

return send_file(

567

file_path,

568

conditional=True,

569

last_modified=last_modified,

570

max_age=timedelta(hours=1).total_seconds()

571

)

572

573

@app.route('/image/<filename>')

574

def serve_image(filename):

575

image_path = os.path.join('images', filename)

576

577

if not os.path.exists(image_path):

578

abort(404)

579

580

# Auto-detect MIME type

581

mimetype, _ = mimetypes.guess_type(filename)

582

583

return send_file(

584

image_path,

585

mimetype=mimetype,

586

conditional=True,

587

max_age=timedelta(days=30).total_seconds()

588

)

589

590

@app.route('/cached-file/<filename>')

591

def cached_file(filename):

592

file_path = os.path.join('cache', filename)

593

594

# Custom max_age function

595

def get_max_age(filename):

596

if filename.endswith('.css') or filename.endswith('.js'):

597

return 86400 # 1 day

598

elif filename.endswith(('.jpg', '.png', '.gif')):

599

return 604800 # 1 week

600

return 3600 # 1 hour default

601

602

return send_file(

603

file_path,

604

max_age=get_max_age,

605

etag=True

606

)

607

```