Freezes a Flask application into a set of static files.

Overview

Frozen-Flask

https://img.shields.io/pypi/v/Frozen-Flask.svg?maxAge=2592000

Freezes a Flask application into a set of static files. The result can be hosted without any server-side software other than a traditional web server.

See documentation: https://pythonhosted.org/Frozen-Flask/

Build Status

https://github.com/Frozen-Flask/Frozen-Flask/workflows/CI/badge.svg?branch=master

Contributing

  • Fork the upstream repository and clone your fork
  • Create a feature branch for the thing you want to work on
  • Create a virtual environment and activate it
  • Run pip install -e . to install dependencies
  • Use tox or python -m flask_frozen.tests to run tests
  • Do your changes, make sure tests pass
  • Send a Pull Request to the upstream repository

License

Frozen-Flask uses a BSD 3-clause license. See LICENSE.

Comments
  • Ignore certain endpoints

    Ignore certain endpoints

    Ok, I think I have a real "issue" this time. :)

    I am running my app through Frozen Flask and the app has basic CRUD operations. The problem that I'm encountering is that the freeze process is following the delete endpoint. This has the unfortunate side-effect of actually deleting all the page content in my app. Thus, the next time I run the freeze method, there is a lot less frozen stuff.

    I didn't see any method in the documentation for getting freeze to ignore certain endpoints. Is this possible or desired?

    opened by mblayman 18
  • Add .freeze_yield() that freezes the app and yields URLs and paths

    Add .freeze_yield() that freezes the app and yields URLs and paths

    This change enables the user of Frozen-Flask to iterate over the URLs beeing frozen and visualize the progress (i.e. by printing the URLs to the stdout or using some kind of progressbar).

    opened by hroncok 12
  • Compatibility with Python 3.9

    Compatibility with Python 3.9

    I'm getting following warnings:

    /Users/honza/.local/share/virtualenvs/python.cz-s2NxYiyq/lib/python3.7/site-packages/flask_frozen/__init__.py:29
      /Users/honza/.local/share/virtualenvs/python.cz-s2NxYiyq/lib/python3.7/site-packages/flask_frozen/__init__.py:29:
      DeprecationWarning: Using or importing the ABCs from 'collections' instead
      of from 'collections.abc' is deprecated since Python 3.3,and in 3.9 it will stop working
        from collections import Mapping, namedtuple
    
    tests/views_test.py::test_get_involved_cs_renders_ordinary_issue
      /Users/honza/.local/share/virtualenvs/python.cz-s2NxYiyq/lib/python3.7/site-packages/ics/icalendar.py:59:
      DeprecationWarning: Using or importing the ABCs from 'collections' instead
      of from 'collections.abc' is deprecated since Python 3.3,and in 3.9 it will stop working
        elif isinstance(imports, collections.Iterable):
    
    opened by honzajavorek 10
  • Add an ignored files config to prevent freezing from overwriting/removing files

    Add an ignored files config to prevent freezing from overwriting/removing files

    I am using Frozen-Flask to create my blog which I publish through Github Pages. The problem is that freezing removes all of the files in the .git directory of the blog's github repo which kills the repository. I could build to a different destination and then copy over all of the files to my github repo, but that is a tedious and error prone process. Instead, it would be nice to have a config setting that would allow you to specify files and directories to ignore during the freezing process (something akin to the .gitignore file).

    The changes I've made in this pull request introduce a new config setting FREEZER_IGNORED_FILES to fix this issue. The ignored files setting takes a list of file and directory names (relative to the destination directory) and expands those into a list of ignored file paths.

    So, for example, if you wanted to ignore all files within the .git directory of a Git repo and a CNAME file within the top level of the destination directory, you could add the following to your script:

    FREEZER_IGNORED_FILES = ['.git', 'CNAME']
    
    opened by croach 10
  • Project maintenance

    Project maintenance

    Hi all,

    Having moved on to other things, I’m not interested in spending time on Frozen-Flask anymore. It has been effectively abandoned for some time. Still, there are a few open issues and pull requests and people occasionally file/submit new ones. The project needs a maintainer to live on, but it won’t be me.

    I’ve you’d like to do this, comment here and I’ll give you access on github and PyPI. (Please include your PyPI username in the comment.)

    CC people who have contributed pull requests: @tswast, @smbsimon, @MykolaBilyi, @mblayman, @aventurella, @singingwolfboy, @sodastsai, @mivade, @max-k, @HeyImAlex, @homeworkprod, @croach, @grayj, @vaus, @equalsraf, @benvinegar, @jokull, @amit-bansil, @rduplain.

    opened by SimonSapin 9
  • Add FREEZER_STATIC_IGNORE config option.

    Add FREEZER_STATIC_IGNORE config option.

    Allows you to stop certain static files (anything served by send_static_file) from being built with your project based on a list of fnmatch style patterns. Had to add a main.js static file to the test app and change the test_all_urls_method to work with the built_app context manager.

    opened by heyimalex 9
  • Add file extension to files without extensions

    Add file extension to files without extensions

    Assume you have a site that looks something like this...

    @app.route('/')
    def index():
        #...
    
    @app.route('/archive')
    def archive():
        #...
    
    @app.route('/archive/<int:year>')
    def archive_year(year):
        #...
    

    This should generate urls such as below:

    • /
    • /archive
    • /archive/2013

    The way I've handled these URLs in the past is to have my URLs mapped to the filenames shown below using the web server (Nginx):

    • / => /index.html
    • /archive => /archive.html
    • /archive/2013 => /archive/2013.html

    I don't see a way to generate the filenames the way I've shown with Frozen Flask. For example, the "archive" page will always be created as the filename /archive. I can't change the URL from /archive to /archive/ or /archive.html without breaking existing links. I also can't change the web server to just look for /archive at /archive/index.html because Frozen-Flask can't actually generate the application I've shown above (since it will create the archive file, and then be unable to create the archive directory).

    I am thinking on working on a patch that would add a new configuration item, something like FREEZER_FORCE_HTML_EXTENSION. This would take any file that wouldn't ordinarily have a .html extension for the generated file and give it one (if the response was actually an HTML content type). Thus, when /archive is generated, the view renders it as text/html, and therefore gives it an html file extension when generated.

    Before putting effort into this, I wanted to see if this is a feature that would be accepted if I created it. Additionally, I am wondering if you had any input or tips on its development, specifically on writing the tests. It seems all of the tests work on the assumption that the files will always be generated with the same names, where as this feature would obviously not hold to that assumption.

    opened by markhildreth 8
  • Add `Freezer.error_handler_spec` for saving errors

    Add `Freezer.error_handler_spec` for saving errors

    I needed to be able to generate a 404 page when freezing my Flask application, so I figured I'd add a generic way to make Frozen-Flask freeze any HTTP error page. The code works, and the unit test suite has been updated as well, but there is currently not documentation. I decided to mirror Flask.error_handler_spec as closely as possible, but I'm not certain that was the right decision, since it means that we have to use a nested dictionary due to blueprints providing their own exception handlers. I'm open to suggestions for other ways to implement this that make sense.

    opened by singingwolfboy 8
  • save html with wrong guessed mimetype as folder with index.html

    save html with wrong guessed mimetype as folder with index.html

    These patches rewrite the destination paths for html content with the wrong guessed mimetype to be stored as index.html. For example for a path /site/content/ the content wound be stored in /site/content/index.html. The commit adds a new option FREEZER_REWRITE_HTML_AS_FOLDER (default False) that enables this behaviour.

    This trick works well for web servers that accept paths with or without the trailing slash as being the equivalent. This is the case for github's static pages (for example http://equalsraf.github.com/ was generated from http://ruiabreu.org/). However this does not work for Freezer.run().

    opened by equalsraf 8
  • Not clear how to write URL generators based on documentation

    Not clear how to write URL generators based on documentation

    I've read the documentation found at https://pythonhosted.org/Frozen-Flask/#url-generators and to be fair I'm just confused by it.

    I've tried a multitude of approaches, but nothing worked.

    Here's my current code:

    @app.route('/category/<category_slug>')
    def articles(category_slug):
        data = []
        for article in ARTICLES:
            if article.metadata['category'] == category_slug:
                data.append(article)
        return render_template('category.html', articles=data)
    
    
    @freezer.register_generator
    def articles_generator():
        for article in ARTICLES:
            yield {'/articles/' + article.metadata['slug'], article}
    
    
    @app.route('/articles/<slug>')
    def article(slug):
        for article in ARTICLES:
            if article.metadata['slug'] == slug:
                return render_template('article.html', article=article, thumb=article.metadata['thumb'])
        return page_not_found(404)
    
    @freezer.register_generator
    def article_generator():
        yield {'article', article.metadata['slug']}
    

    the error I get is as follows:

    MissingURLGeneratorWarning: Nothing frozen for endpoints articles, article. Did you forget a URL generator?
      return set(page.url for page in self.freeze_yield())
    

    Any clarifications would be greatly appreciated.

    opened by Zenahr 7
  • Support unquoting URLs that contain multi-byte unicode characters

    Support unquoting URLs that contain multi-byte unicode characters

    The Python 2.7 urllib.unquote implementation does not handle decoding non-ASCII characters; instead use werkzeug's encoding-aware implementation.

    Fixes #103

    opened by jayaddison 7
  • New feature: pretty relative urls

    New feature: pretty relative urls

    Hey Frozen-Flask team! I was going through my old issues and decided to have another shot at a feature request I made here 4 years ago. I'm too deep into JS now, so I actually don't know if kids new to programming these days still build websites with Python and then host them on static servers like I used to, but if they do, now they can have pretty URLs without the ugly /index.html just like I wanted to.


    Why it's necessary to first append the /index.html and then remove it (i.e. why the approach I said I tried in the original issue didn't work): if the index.html isn't there, relpath resolves a path to the directory itself, which obviously doesn't include the trailing slash. But after that it isn't anymore possible to disambiguate if the resolved URL is a directory ../example, or a file ../example. So we need to keep it, resolve the relpath, and then again strip query+fragment, check for index.html, remove it and then put everything back together again.

    Fixes #90

    opened by mvolfik 0
  • docs: fix simple typo, unmodifies -> unmodified

    docs: fix simple typo, unmodifies -> unmodified

    There is a small typo in flask_frozen/init.py.

    Should read unmodified rather than unmodifies.

    Semi-automated pull request generated by https://github.com/timgates42/meticulous/blob/master/docs/NOTE.md

    opened by timgates42 0
  • Question: What is the best way to have run multiple threads/processes?

    Question: What is the best way to have run multiple threads/processes?

    the whole process of freezing ~2k urls takes upto 20 mins. Is there a way to run the freeze script with multiple threads/processes to speed up the static site generation?

    I have implemented something here, and appreciate any feedback for improvements, thanks :) reference: https://github.com/vedupraity/ancientknowledgewebserver/blob/master/freeze.py

    opened by vedupraity 2
  • Question about URL generators

    Question about URL generators

    So, I am making a blog and I am trying to freeze it with Frozen-Flask. I have the following URL generator in my code:

    @app.route('/blog/<path:path>.html')
    def page(path):
        page = pages.get_or_404(path)
        return render_template('page.html', page=page)
    

    How can I make Frozen-Flask register the URL generator?

    opened by ghost 1
  • How to remove trailing slash?

    How to remove trailing slash?

    Hi,

    I made a site with this (https://util123.com/) but i need now remove the last slash.

    Can anyone help me?

    The main project is Kaktos (https://github.com/paulocoutinhox/kaktos).

    Thanks for any help.

    opened by paulocoutinhox 2
  • During build: string concatenation in url_for() fails when data comes from render_template()

    During build: string concatenation in url_for() fails when data comes from render_template()

    When running Flask normally, everything described below works absolutely fine.

    When running a build in Frozen-Flask however, I run into the issue where my dynamically built route string won't allow me to concatenate a variable (containing a string) with a string for use in a url_for() function within Jinja2. But only when the variable data is originating from Python such as render_template().

    routes.py

    @app.route('/some-route/')
    def some_route():
        return render_template('my_template.html', foo='bar')
    

    base.html

    {% import "includes.html" as includes %}
    {{ includes.my_macro(foo) }}
    

    includes.html

    # The following does NOT work
    {% macro my_macro(foo) %}
        <a href="{{ url_for('index_' ~ foo) }}">Link text</a>
    {% endmacro %}
    

    Although the above runs fine in Flask, when I do a build with Frozen-Flask I get the following error:

    werkzeug.routing.BuildError: Could not build url for endpoint 'index_'. Did you mean...
    

    As you can see, the value of foo (or the string value bar) is missing. It should have been index_bar.

    So I tried this instead:

    # This also does NOT work
    {% macro my_macro(foo) %}
        {% set route = 'index_' ~ foo %}
        <a href="{{ url_for(route) }}">Link text</a>
    {% endmacro %}
    

    The above produces the exact same error.

    So I tried this to try to better understand the problem:

    # This works correctly
    {% macro my_macro(foo) %}
        {% set route = 'index_' ~ 'bar' %}
        <a href="{{ url_for(route) }}">Link text</a>
    {% endmacro %}
    

    So I further tried this:

    # This also works correctly
    {% macro my_macro(foo) %}
        {% set foo2 = 'bar' %}
        {% set route = 'index_' ~ foo2 %}
        <a href="{{ url_for(route) }}">Link text</a>
    {% endmacro %}
    

    So basically, I can create a dynamic route string for use by url_for() but only when the variable data doesn't come from the Flask routes file (such as my routes.py), only if the variable is created within Jinja2.

    opened by LokiWijnen 2
Releases(v0.15)
This is a repository for a playlist of videos where I teach building RESTful API with Flask and Flask extensions.

Build And Deploy A REST API with Flask This is code for a series of videos in which we look at the various concepts involved when building a REST API

Ssali Jonathan 10 Nov 24, 2022
Flask Application Structure with MongoDB

This application aims to serve as a template for APIs that intend to use mongoengine and flask-restx

Tiago Franco 5 Jun 25, 2022
Flask Web DRY full-stack framework by Problem Fighter

In the name of God, the Most Gracious, the Most Merciful. PF-Flask-Web Documentation Install and update using pip: pip install -U PF-Flask-Web Please

Problem Fighter 2 Jan 20, 2022
flask extension for integration with the awesome pydantic package

Flask-Pydantic Flask extension for integration of the awesome pydantic package with Flask. Installation python3 -m pip install Flask-Pydantic Basics v

249 Jan 06, 2023
Brandnew-flask is a CLI tool used to generate a powerful and mordern flask-app that supports the production environment.

Brandnew-flask is still in the initial stage and needs to be updated and improved continuously. Everyone is welcome to maintain and improve this CLI.

brandonye 4 Jul 17, 2022
A nice anonymous messaging api (Uses Flask's restful api)

anonymous-message-api A nice anonymous message api (Uses Flask's restful api) How it works: 1. The user send a put request to your api server: Require

6 Nov 07, 2021
An extension to add support of Plugin in Flask.

An extension to add support of Plugin in Flask.

Doge Gui 31 May 19, 2022
Boilerplate code for basic flask web apps

Flask Boilerplate This repository contains boilerplate code to start a project instantly It's mainly for projects which you plan to ship in less than

Abhishek 6 Sep 27, 2021
Freezes a Flask application into a set of static files.

Frozen-Flask Freezes a Flask application into a set of static files. The result can be hosted without any server-side software other than a traditiona

Frozen Flask 737 Dec 19, 2022
This is a Flask web app which predicts fare of Flight ticket

Flight Fare Prediction: Table of Content Demo Overview Motivation Installation Deployement on Heroku Directory Tree Bug / Feature Request Future scope

Ayshwarya 1 Jan 24, 2022
Are-You-OK is a Flask-based, responsive Web App to monitor whether the Internet Service you care about is still working.

Are-You-OK Are-You-OK is a Flask-based, responsive Web App to monitor whether the Internet Service you care about is still working. Demo-Preview Get S

Tim Qiu 1 Oct 28, 2021
Simple flask api. Countdown to next train for each station in the subway system.

Simple flask api. Countdown to next train for each station in the subway system.

Kalyani Subbiah 0 Apr 17, 2022
Adds GraphQL support to your Flask application.

Flask-GraphQL Adds GraphQL support to your Flask application. Usage Just use the GraphQLView view from flask_graphql from flask import Flask from flas

GraphQL Python 1.3k Jan 03, 2023
Neo4j Movies Example application with Flask backend using the neo4j-python-driver

Neo4j Movies Application: Quick Start This example application demonstrates how easy it is to get started with Neo4j in Python. It is a very simple we

Neo4j Examples 309 Dec 24, 2022
Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application.

Flask-Bcrypt Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application. Due to the recent increased prevelance of

Max Countryman 310 Dec 14, 2022
SQLAlchemy database migrations for Flask applications using Alembic

Flask-Migrate Flask-Migrate is an extension that handles SQLAlchemy database migrations for Flask applications using Alembic. The database operations

Miguel Grinberg 2.2k Dec 28, 2022
Flask-Diamond is a batteries-included Flask framework.

Flask-Diamond Flask-Diamond is a batteries-included Python Flask framework, sortof like Django but radically decomposable. Flask-Diamond offers some o

Diamond Methods 173 Dec 22, 2022
An flask app for fake image detector

fake_img_detector This is a ml based project: frameworks used:- Flask Google collab #Description: Here you can Upload two different looking image with

shivam kumar 7 Jun 29, 2022
A template for Flask APIs.

FlaskAPITempate A template for a Flask API. Why tho? I just wanted an easy way to create a Flask API. How to setup First, use the template. You can do

TechStudent10 1 Dec 28, 2021
A Cyberland server written in Python with Flask.

Cyberland What is Cyberland Cyberland is a textboard that offers no frontend. Most of the time, the user makes their own front end. The protocol, as f

Maxime Bouillot 9 Nov 26, 2022