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)
API to get the details of the characters in the Money heist TV show.

Project Heist Description: Project Heist is a RESTful API made using Python and Flask. This API is inspired by the popular Spanish TV show Money Heist

Rahul V 5 Dec 19, 2022
A simple web application built using python flask. It can be used to scan SMEVai accounts for broken pages.

smescan A simple web application built using python flask. It can be used to scan SMEVai accounts for broken pages. Development Process Step 0: Clone

Abu Hurayra 1 Jan 30, 2022
A simple example using Flask inside a container

This is a simple example of how create a container for a Python Flask Web Application using Docker.

Fazt Web 8 Aug 30, 2022
A multi-container docker application. Implemented and dockerized a web-based service leveraging Flask

Flask-based-web-service-with-Docker-compose A multi-container docker application. Implemented and dockerized a web-based service leveraging Flask. Des

Jayshree Rathi 1 Jan 15, 2022
Heroku Flask Setup

Heroku Flask Setup

Abhimanyu Haralukallu 0 Dec 07, 2021
Python3🐍 webApp to display your current playing music on OBS Studio.

Spotify Overlay A Overlay to display on Obs Studio or any related video/stream recorder, the current music that is playing on your Spotify. Installati

carlitos 0 Oct 17, 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
Paid roles for discord using Stripe, Python, Flask & Docker

Welcome to Paycord Paid roles for discord using Stripe, Python, Flask & Docker. Setup Production On stripe dashboard, go Developers ➡️ Webhooks ➡️ Add

Ward 12 Dec 28, 2022
This is a API/Website to see the attendance recorded in your college website along with how many days you can take days off OR to attend class!!

Bunker-Website This is a GUI version of the Bunker-API along with some visualization charts to see your attendance progress. Website Link Check out th

Mathana Mathav 11 Dec 27, 2022
A boilerplate Flask API for a Fullstack Project :rocket:

Flask Boilerplate to quickly get started with production grade flask application with some additional packages and configuration prebuilt.

Yasser Tahiri 32 Dec 24, 2022
Geometry Dash Song Bypass with Python Flask Server

Geometry Dash Song Bypass with Python Flask Server

pixelsuft‮ 1 Nov 16, 2021
Mixer -- Is a fixtures replacement. Supported Django, Flask, SqlAlchemy and custom python objects.

The Mixer is a helper to generate instances of Django or SQLAlchemy models. It's useful for testing and fixture replacement. Fast and convenient test-

Kirill Klenov 870 Jan 08, 2023
Another redis monitor by using flask, angular, socket.io

RedisPAPA we use redis info to monitor the redis usage. PAPA means a father who is monitoring the redis. accoding to the redis doc, it is be recommand

no13bus 393 Dec 30, 2022
A simple FastAPI web service + Vue.js based UI over a rclip-style clip embedding database.

Explore CLIP Embeddings in a rclip database A simple FastAPI web service + Vue.js based UI over a rclip-style clip embedding database. A live demo of

18 Oct 15, 2022
This repo contains the Flask API to expose model and get predictions.

Tea Leaf Quality Srilanka Chapter This repo contains the Flask API to expose model and get predictions. Expose Model As An API Model Trainig will happ

DuKe786 2 Nov 12, 2021
a flask zipkin extension based on py_zipkin.

flask-zipkin a flask zipkin extension based on py_zipkin. Installation pip install flask_zipkin usage you can simply use it as other flask extensions.

39 Jul 03, 2022
Browsable web APIs for Flask.

Flask API Browsable web APIs for Flask. Status: This project is in maintenance mode. The original author (Tom Christie) has shifted his focus to API S

Flask API 1.3k Jan 05, 2023
Harmony, a discord clone, allows users to chat with other users in real time via servers, channels, and direct messages

Harmony, a discord clone, allows users to chat with other users in real time via servers, channels, and direct messages

Seth Holland 3 Feb 03, 2022
Flask-template - A simple template for make an flask api

flask-template By GaGoU :3 a simple template for make an flask api notes: you ca

GaGoU 2 Feb 17, 2022
Set up a modern flask web server by running one command.

Build Flask App · Set up a modern flask web server by running one command. Installing / Getting started pip install build-flask-app Usage build-flask-

Kushagra Bainsla 5 Jul 16, 2022