A simple framework for building complex web applications.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Flask provides utility functions for common web development tasks including redirects, error handling, file operations, and message flashing.
Functions for creating HTTP responses and handling redirects.
def redirect(location: str, code: int = 302, Response: type | None = None) -> Response:
"""
Create a redirect response to a different location.
Args:
location: URL to redirect to
code: HTTP status code (301, 302, 303, 307, 308)
Response: Response class to use
Returns:
Redirect response object
"""
def abort(code: int | BaseResponse, *args, **kwargs) -> NoReturn:
"""
Abort the current request with an HTTP error.
Args:
code: HTTP status code or Response object
*args: Additional arguments for the exception
**kwargs: Additional keyword arguments
Raises:
HTTPException: With the specified status code
"""
def make_response(*args) -> Response:
"""
Convert arguments into a Response object.
Args:
*args: Arguments that would normally be returned from a view function
Returns:
Response object that can be modified before returning
"""Functions for sending files and handling file downloads.
def send_file(
path_or_file: os.PathLike | str | IO[bytes],
mimetype: str | None = None,
as_attachment: bool = False,
download_name: str | None = None,
conditional: bool = True,
etag: bool | str = True,
last_modified: datetime | int | float | None = None,
max_age: int | Callable[[str | None], int | None] | None = None
) -> Response:
"""
Send a file to the client.
Args:
path_or_file: Path to file or file-like object
mimetype: MIME type (auto-detected if None)
as_attachment: Send as attachment (triggers download)
download_name: Filename for download
conditional: Enable conditional responses (304 Not Modified)
etag: Enable ETag header (True, False, or custom ETag)
last_modified: Last modified timestamp
max_age: Cache max age in seconds
Returns:
Response with file contents
"""
def send_from_directory(
directory: str,
path: str,
**kwargs
) -> Response:
"""
Send a file from a directory safely.
Args:
directory: Directory containing the file
path: Relative path to file within directory
**kwargs: Additional arguments passed to send_file()
Returns:
Response with file contents
Raises:
NotFound: If file doesn't exist or path is unsafe
"""Functions for displaying one-time messages to users.
def flash(message: str, category: str = "message") -> None:
"""
Flash a message that will be displayed on the next request.
Args:
message: Message text to flash
category: Message category (e.g., 'error', 'info', 'warning')
"""
def get_flashed_messages(
with_categories: bool = False,
category_filter: list[str] = []
) -> list[str] | list[tuple[str, str]]:
"""
Get and remove all flashed messages.
Args:
with_categories: Return (category, message) tuples
category_filter: Only return messages from these categories
Returns:
List of messages or (category, message) tuples
"""Functions for working with templates outside of normal rendering.
def get_template_attribute(template_name: str, attribute: str) -> Any:
"""
Load a template and get one of its attributes.
Args:
template_name: Template filename
attribute: Attribute name to retrieve
Returns:
Template attribute value
Raises:
TemplateNotFound: If template doesn't exist
AttributeError: If attribute doesn't exist
"""Function for maintaining request context in generators and iterators.
def stream_with_context(generator_or_function) -> Iterator:
"""
Stream with the current request context.
Args:
generator_or_function: Generator function or iterator
Returns:
Iterator that preserves request context
"""from flask import Flask, redirect, url_for, request
app = Flask(__name__)
@app.route('/')
def home():
return 'Home Page'
@app.route('/login')
def login():
return 'Login Page'
@app.route('/dashboard')
def dashboard():
# Redirect to login if not authenticated
if not session.get('logged_in'):
return redirect(url_for('login'))
return 'Dashboard'
@app.route('/old-page')
def old_page():
# Permanent redirect (301)
return redirect(url_for('home'), code=301)
@app.route('/external')
def external_redirect():
# Redirect to external URL
return redirect('https://www.example.com')
@app.route('/conditional-redirect')
def conditional_redirect():
next_page = request.args.get('next')
if next_page:
return redirect(next_page)
return redirect(url_for('home'))from flask import Flask, abort, request, jsonify
app = Flask(__name__)
@app.route('/user/<int:user_id>')
def get_user(user_id):
# Validate user ID
if user_id <= 0:
abort(400, description="Invalid user ID")
# Simulate user lookup
if user_id > 1000:
abort(404, description="User not found")
# Simulate permission check
if user_id == 999:
abort(403, description="Access denied")
return {'id': user_id, 'name': f'User {user_id}'}
@app.route('/admin')
def admin_area():
# Check authentication
if not session.get('logged_in'):
abort(401) # Unauthorized
# Check admin privileges
if not session.get('is_admin'):
abort(403) # Forbidden
return 'Admin Area'
@app.route('/api/data', methods=['POST'])
def create_data():
if not request.is_json:
abort(400, description="Content-Type must be application/json")
data = request.get_json()
if not data or 'name' not in data:
abort(422, description="Missing required field: name")
return jsonify({'status': 'created', 'data': data}), 201from flask import Flask, make_response, render_template, jsonify
app = Flask(__name__)
@app.route('/custom-headers')
def custom_headers():
# Create response with custom headers
response = make_response(render_template('index.html'))
response.headers['X-Custom-Header'] = 'Custom Value'
response.headers['Cache-Control'] = 'no-cache'
return response
@app.route('/api/data')
def api_data():
# Create JSON response with custom status and headers
data = {'message': 'Hello, World!'}
response = make_response(jsonify(data))
response.status_code = 200
response.headers['X-API-Version'] = '1.0'
return response
@app.route('/download-csv')
def download_csv():
csv_data = "name,email\nJohn,john@example.com\nJane,jane@example.com"
response = make_response(csv_data)
response.headers['Content-Type'] = 'text/csv'
response.headers['Content-Disposition'] = 'attachment; filename=users.csv'
return responsefrom flask import Flask, send_file, send_from_directory, request, abort
import os
from werkzeug.utils import secure_filename
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max
@app.route('/download/<filename>')
def download_file(filename):
# Send file from uploads directory
try:
return send_from_directory(
app.config['UPLOAD_FOLDER'],
filename,
as_attachment=True
)
except FileNotFoundError:
abort(404)
@app.route('/view/<filename>')
def view_file(filename):
# View file in browser (not as download)
return send_from_directory(
app.config['UPLOAD_FOLDER'],
filename,
as_attachment=False
)
@app.route('/generate-report')
def generate_report():
# Generate and send a file
import tempfile
import csv
# Create temporary file
temp_file = tempfile.NamedTemporaryFile(
mode='w',
suffix='.csv',
delete=False
)
# Write CSV data
writer = csv.writer(temp_file)
writer.writerow(['Name', 'Email', 'Role'])
writer.writerow(['John Doe', 'john@example.com', 'Admin'])
writer.writerow(['Jane Smith', 'jane@example.com', 'User'])
temp_file.close()
return send_file(
temp_file.name,
as_attachment=True,
download_name='users.csv',
mimetype='text/csv'
)
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
abort(400, description="No file uploaded")
file = request.files['file']
if file.filename == '':
abort(400, description="No file selected")
if file:
filename = secure_filename(file.filename)
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(filepath)
return {
'status': 'uploaded',
'filename': filename,
'download_url': url_for('download_file', filename=filename)
}from flask import Flask, flash, get_flashed_messages, render_template, redirect, url_for, request
app = Flask(__name__)
app.secret_key = 'your-secret-key'
@app.route('/')
def home():
return render_template('home.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
if not username or not password:
flash('Username and password are required', 'error')
elif username == 'admin' and password == 'secret':
flash('Login successful!', 'success')
session['logged_in'] = True
return redirect(url_for('dashboard'))
else:
flash('Invalid credentials', 'error')
return render_template('login.html')
@app.route('/dashboard')
def dashboard():
if not session.get('logged_in'):
flash('Please log in to access the dashboard', 'warning')
return redirect(url_for('login'))
flash('Welcome to your dashboard!', 'info')
return render_template('dashboard.html')
@app.route('/profile', methods=['POST'])
def update_profile():
# Simulate profile update
name = request.form.get('name')
email = request.form.get('email')
if name and email:
flash('Profile updated successfully!', 'success')
else:
flash('Please fill in all fields', 'error')
return redirect(url_for('dashboard'))
@app.route('/messages')
def show_messages():
# Get messages with categories
messages = get_flashed_messages(with_categories=True)
return render_template('messages.html', messages=messages)
@app.route('/warnings')
def show_warnings():
# Get only warning messages
warnings = get_flashed_messages(category_filter=['warning', 'error'])
return render_template('warnings.html', warnings=warnings)Template for displaying messages (templates/base.html):
<!DOCTYPE html>
<html>
<head>
<title>Flask App</title>
<style>
.flash-message { padding: 10px; margin: 10px 0; border-radius: 4px; }
.flash-success { background-color: #d4edda; color: #155724; }
.flash-error { background-color: #f8d7da; color: #721c24; }
.flash-warning { background-color: #fff3cd; color: #856404; }
.flash-info { background-color: #d1ecf1; color: #0c5460; }
</style>
</head>
<body>
<!-- Display flashed messages -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="flash-message flash-{{ category }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</body>
</html>from flask import Flask, get_template_attribute, render_template
app = Flask(__name__)
@app.route('/macro-example')
def macro_example():
# Get a macro from a template
render_form = get_template_attribute('macros.html', 'render_form')
# Use the macro programmatically
form_html = render_form(
action='/submit',
method='POST',
fields=[
{'name': 'username', 'type': 'text', 'label': 'Username'},
{'name': 'email', 'type': 'email', 'label': 'Email'}
]
)
return f'<h1>Generated Form</h1>{form_html}'
@app.route('/template-vars')
def template_vars():
# Get variables from template
config_data = get_template_attribute('config.html', 'app_config')
return {'config': config_data}from flask import Flask, stream_with_context, request, g
import time
app = Flask(__name__)
@app.before_request
def before_request():
g.user_id = request.headers.get('X-User-ID', 'anonymous')
@app.route('/stream')
def stream_data():
def generate():
for i in range(10):
# Access request context variables
yield f"data: User {g.user_id}, Item {i}\n\n"
time.sleep(1)
return Response(
stream_with_context(generate()),
mimetype='text/plain'
)
@app.route('/sse')
def server_sent_events():
def event_stream():
count = 0
while count < 50:
# Use request context in generator
user_id = g.user_id
yield f"data: {{\"user\": \"{user_id}\", \"count\": {count}}}\n\n"
count += 1
time.sleep(2)
return Response(
stream_with_context(event_stream()),
mimetype='text/event-stream',
headers={
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
}
)from flask import Flask, send_file, request, abort
from datetime import datetime, timedelta
import mimetypes
import os
app = Flask(__name__)
@app.route('/file/<path:filename>')
def serve_file(filename):
file_path = os.path.join('files', filename)
if not os.path.exists(file_path):
abort(404)
# Get file info
stat = os.stat(file_path)
last_modified = datetime.fromtimestamp(stat.st_mtime)
return send_file(
file_path,
conditional=True,
last_modified=last_modified,
max_age=timedelta(hours=1).total_seconds()
)
@app.route('/image/<filename>')
def serve_image(filename):
image_path = os.path.join('images', filename)
if not os.path.exists(image_path):
abort(404)
# Auto-detect MIME type
mimetype, _ = mimetypes.guess_type(filename)
return send_file(
image_path,
mimetype=mimetype,
conditional=True,
max_age=timedelta(days=30).total_seconds()
)
@app.route('/cached-file/<filename>')
def cached_file(filename):
file_path = os.path.join('cache', filename)
# Custom max_age function
def get_max_age(filename):
if filename.endswith('.css') or filename.endswith('.js'):
return 86400 # 1 day
elif filename.endswith(('.jpg', '.png', '.gif')):
return 604800 # 1 week
return 3600 # 1 hour default
return send_file(
file_path,
max_age=get_max_age,
etag=True
)Install with Tessl CLI
npx tessl i tessl/pypi-flask