Freezes a Flask application into a set of static files.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Advanced URL generation system for handling dynamic routes, custom URL patterns, and endpoint discovery. Frozen-Flask uses URL generators to discover all URLs that should be converted to static files.
Methods for registering custom URL generator functions to handle dynamic routes and custom URL patterns.
def register_generator(self, function):
"""
Register a function as a URL generator.
The function should return an iterable of:
- URL strings: '/some/path/'
- (endpoint, values) tuples: ('product', {'id': 1})
- (endpoint, values, last_modified) tuples for incremental builds
- Values dictionaries (endpoint defaults to function name)
Parameters:
- function: Generator function returning URL patterns
Returns:
function: The function (allows use as decorator)
"""Default URL generators for common Flask patterns.
def static_files_urls(self):
"""
URL generator for static files for app and all blueprints.
Yields:
tuple: (endpoint, {'filename': relative_path}) for each static file
"""
def no_argument_rules_urls(self):
"""
URL generator for URL rules that take no arguments.
Yields:
tuple: (endpoint, {}) for each no-argument route
"""Internal methods for URL discovery and processing.
def _generate_all_urls(self):
"""
Run all generators and yield (url, endpoint, last_modified) tuples.
Internal method that processes all registered generators.
"""
def _static_rules_endpoints(self):
"""
Yield the 'static' URL rules for the app and all blueprints.
Internal method for identifying static file endpoints.
"""Simplest pattern - return URL strings directly:
@freezer.register_generator
def product_urls():
yield '/product/1/'
yield '/product/2/'
yield '/about/'Use Flask's url_for pattern with endpoint names and parameters:
@freezer.register_generator
def product_urls():
# (endpoint, values) tuples
yield 'product', {'id': 1}
yield 'product', {'id': 2}
yield 'page', {'name': 'about'}When the endpoint matches the generator function name:
@freezer.register_generator
def product(): # Function name becomes endpoint
# Just values dictionary
yield {'id': 1}
yield {'id': 2}
yield {'id': 3}Include last modified timestamps for smart rebuilding:
from datetime import datetime
@freezer.register_generator
def blog_posts():
posts = get_blog_posts() # Your data source
for post in posts:
yield 'blog_post', {'slug': post.slug}, post.updated_atfrom flask import Flask
from flask_frozen import Freezer
app = Flask(__name__)
freezer = Freezer(app)
@app.route('/product/<int:product_id>/')
def product(product_id):
return f'Product {product_id}'
@freezer.register_generator
def product_urls():
# Generate URLs for products 1-10
for i in range(1, 11):
yield 'product', {'product_id': i}
freezer.freeze()@app.route('/blog/<category>/<slug>/')
def blog_post(category, slug):
return f'Blog post: {category}/{slug}'
@freezer.register_generator
def blog_urls():
posts = [
('tech', 'python-tips'),
('tech', 'flask-guide'),
('news', 'company-update'),
]
for category, slug in posts:
yield 'blog_post', {'category': category, 'slug': slug}@freezer.register_generator
def user_profile_urls():
# Get data from database
users = User.query.filter_by(active=True).all()
for user in users:
yield 'user_profile', {'username': user.username}@freezer.register_generator
def mixed_urls():
# Direct URL strings
yield '/special-page/'
yield '/robots.txt'
# Endpoint and values
yield 'category', {'name': 'electronics'}
yield 'category', {'name': 'books'}
# Values only (endpoint = function name = 'mixed_urls')
# This won't work unless you have a route named 'mixed_urls'@freezer.register_generator
def conditional_urls():
# Only generate certain URLs in production
if app.config.get('ENV') == 'production':
yield '/admin-report/'
yield '/analytics/'
# Always generate these
yield '/sitemap.xml'
yield '/feed.xml'Static files are handled automatically when with_static_files=True (default):
# This automatically includes all static files
freezer = Freezer(app, with_static_files=True)
# To disable automatic static file inclusion
freezer = Freezer(app, with_static_files=False)
# To manually include static files
@freezer.register_generator
def my_static_files():
# Custom static file logic
yield 'static', {'filename': 'css/style.css'}
yield 'static', {'filename': 'js/app.js'}Routes without parameters are handled automatically when with_no_argument_rules=True (default):
@app.route('/')
def index():
return 'Home'
@app.route('/about/')
def about():
return 'About'
# These are automatically included - no generator needed
freezer = Freezer(app, with_no_argument_rules=True)Install with Tessl CLI
npx tessl i tessl/pypi-frozen-flask