CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-flask

A simple framework for building complex web applications.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

helpers.mddocs/

Helpers and Utilities

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

Capabilities

HTTP Response Helpers

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
    """

File Operations

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
    """

Message Flashing

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
    """

Template Utilities

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
    """

Context Streaming

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
    """

Usage Examples

Redirects and URL Handling

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'))

Error Handling with Abort

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}), 201

Response Creation with make_response

from 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 response

File Downloads and Uploads

from 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)
        }

Message Flashing

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>

Template Attributes

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}

Streaming with Context

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'
        }
    )

Advanced File Handling

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

docs

blueprints.md

cli.md

configuration.md

context-globals.md

core-application.md

helpers.md

index.md

json-support.md

request-response.md

routing.md

sessions.md

signals.md

templates.md

testing.md

tile.json