hyperflask 0.4.3__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hyperflask-0.4.3 → hyperflask-0.5.0}/PKG-INFO +4 -3
- {hyperflask-0.4.3 → hyperflask-0.5.0}/pyproject.toml +4 -3
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/__init__.py +1 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/app.py +20 -26
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/cli/__init__.py +3 -7
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/components/core.py +2 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/components/jsx.py +2 -2
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/components/webcomponent.py +2 -2
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/layouts/web.html +1 -1
- hyperflask-0.5.0/src/hyperflask/utils/freezer.py +56 -0
- hyperflask-0.5.0/src/hyperflask/utils/image.py +26 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/README.md +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/__main__.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/actors.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/cli/reloader.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/cli/runner.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/cli/worker.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/components/__init__.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/components/alpine.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/factory.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/forms/__init__.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/forms/fields.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/forms/widgets.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/layouts/email.mjml +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/model.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/page_helpers.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/security.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/static/alpine-csp.js +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/static/alpine.js +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/static/app.css +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/static/app.js +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/static/htmx-exts.js +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/static/react.js +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/static/stimulus.js +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/static/translations.js +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Accordion.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/AccordionPanel.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Alert.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Avatar.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/AvatarGroup.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Badge.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Breadcrumbs.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/BreadcrumbsItem.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Button.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Card.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/CardActions.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/CardTitle.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/ChatBubble.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Checkbox.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/CollapsibleSubMenu.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Countdown.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Divider.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Drawer.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/DrawerContent.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/DrawerSide.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Dropdown.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/DropdownItem.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Fieldset.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/FieldsetLegend.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/FileInput.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Filter.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/FilterItem.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Footer.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/FooterLink.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/FooterNav.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Indicator.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Input.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/InputLabel.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Join.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Kbd.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Label.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/LabeledCheckbox.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/LabeledToggle.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Link.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/List.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/ListItem.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Loading.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Menu.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/MenuItem.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/MenuTitle.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Modal.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/ModalAction.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/ModalTitle.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Navbar.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Pagination.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/PaginationNext.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/PaginationPage.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/PaginationPrev.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Progress.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/README.md +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Radio.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Range.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Rating.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Select.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Stack.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Stat.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Stats.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Step.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Steps.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/SubMenu.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Swap.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Tab.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Table.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Tabs.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Textarea.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Toast.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Toggle.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/daisyui/Tooltip.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/flash.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/forms.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/icons.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/layout.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/modal.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/skeleton.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/ui/sse.html +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/utils/__init__.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/utils/html.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/utils/htmx.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/utils/markdown.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/utils/metadata.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/utils/page_actions.py +0 -0
- {hyperflask-0.4.3 → hyperflask-0.5.0}/src/hyperflask/utils/tokens.py +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyperflask
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Full stack web framework
|
|
5
5
|
Author: Maxime Bouroumeau-Fuseau
|
|
6
6
|
Author-email: Maxime Bouroumeau-Fuseau <maxime.bouroumeau@gmail.com>
|
|
7
7
|
License-Expression: MIT
|
|
8
8
|
Requires-Dist: flask>=3.0.0,<4.0.0
|
|
9
|
-
Requires-Dist: flask-assets-pipeline~=0.
|
|
9
|
+
Requires-Dist: flask-assets-pipeline~=0.8
|
|
10
10
|
Requires-Dist: flask-babel-hyper~=5.1
|
|
11
|
-
Requires-Dist: flask-collections~=0.
|
|
11
|
+
Requires-Dist: flask-collections~=0.3
|
|
12
12
|
Requires-Dist: flask-configurator~=0.1
|
|
13
13
|
Requires-Dist: flask-debugtoolbar~=0.16
|
|
14
14
|
Requires-Dist: flask-file-routes~=0.3
|
|
@@ -32,6 +32,7 @@ Requires-Dist: jinja-wtforms~=0.2
|
|
|
32
32
|
Requires-Dist: periodiq~=0.13
|
|
33
33
|
Requires-Dist: python-slugify~=8.0.4
|
|
34
34
|
Requires-Dist: watchdog>=6.0.0
|
|
35
|
+
Requires-Dist: pillow>=11.3.0
|
|
35
36
|
Requires-Python: >=3.10
|
|
36
37
|
Project-URL: Repository, https://github.com/hyperflask/hyperflask
|
|
37
38
|
Description-Content-Type: text/markdown
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "hyperflask"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.0"
|
|
4
4
|
description = "Full stack web framework"
|
|
5
5
|
authors = [
|
|
6
6
|
{"name" = "Maxime Bouroumeau-Fuseau", email = "maxime.bouroumeau@gmail.com"}
|
|
@@ -10,9 +10,9 @@ license = "MIT"
|
|
|
10
10
|
requires-python = ">=3.10"
|
|
11
11
|
dependencies = [
|
|
12
12
|
"flask>=3.0.0,<4.0.0",
|
|
13
|
-
"flask-assets-pipeline ~=0.
|
|
13
|
+
"flask-assets-pipeline ~=0.8",
|
|
14
14
|
"flask-babel-hyper ~=5.1",
|
|
15
|
-
"flask-collections ~=0.
|
|
15
|
+
"flask-collections ~=0.3",
|
|
16
16
|
"flask-configurator ~=0.1",
|
|
17
17
|
"flask-debugtoolbar ~=0.16",
|
|
18
18
|
"flask-file-routes ~=0.3",
|
|
@@ -37,6 +37,7 @@ dependencies = [
|
|
|
37
37
|
"periodiq ~=0.13",
|
|
38
38
|
"python-slugify ~=8.0.4",
|
|
39
39
|
"watchdog>=6.0.0",
|
|
40
|
+
"pillow>=11.3.0",
|
|
40
41
|
]
|
|
41
42
|
|
|
42
43
|
[tool.uv.sources]
|
|
@@ -20,7 +20,6 @@ from flask_suspense import Suspense, render_template, suspense_before_render_tem
|
|
|
20
20
|
#from flask_observability import Observability
|
|
21
21
|
# 3rd party extensions
|
|
22
22
|
from flask_wtf.csrf import CSRFProtect
|
|
23
|
-
from flask_frozen import Freezer
|
|
24
23
|
from htmx_flask import Htmx
|
|
25
24
|
from flask_mailman import Mail
|
|
26
25
|
from flask_debugtoolbar import DebugToolbarExtension
|
|
@@ -31,6 +30,8 @@ from .utils.htmx import htmx_oob, respond_with_flash_messages
|
|
|
31
30
|
from .utils.markdown import jinja_markdown, MarkdownExtension
|
|
32
31
|
from .utils.html import sanitize_html, nl2br
|
|
33
32
|
from .utils.metadata import metadata_tags
|
|
33
|
+
from .utils.freezer import StaticMode, Freezer, freezer_url_generator
|
|
34
|
+
from .utils.image import image_tag
|
|
34
35
|
from .components import register_components
|
|
35
36
|
from .model import Model, File as SQLFileType, UndefinedDatabase
|
|
36
37
|
from .actors import AppContextMiddleware, discover_broker, make_actor_decorator
|
|
@@ -41,7 +42,6 @@ from jinja_super_macros.registry import FileLoader
|
|
|
41
42
|
from jinja_wtforms.extractor import map_jinja_call_node_to_func
|
|
42
43
|
from sqlorm.sql_template import SQLTemplate
|
|
43
44
|
from periodiq import PeriodiqMiddleware
|
|
44
|
-
import dramatiq
|
|
45
45
|
import os
|
|
46
46
|
|
|
47
47
|
|
|
@@ -55,7 +55,7 @@ map_jinja_call_node_to_func(lazy_gettext, "lazy_gettext")
|
|
|
55
55
|
class Hyperflask(Flask):
|
|
56
56
|
config_class = Config
|
|
57
57
|
|
|
58
|
-
def __init__(self, *args, static_mode=
|
|
58
|
+
def __init__(self, *args, static_mode=StaticMode.DYNAMIC, instrument=False, layouts_folder="layouts",
|
|
59
59
|
emails_folder="emails", forms_folder="forms", assets_folder="assets", pages_folder="pages", migrations_folder="migrations",
|
|
60
60
|
config=None, config_filename="config.yml", database_uri=None, proxy_fix=True, **kwargs):
|
|
61
61
|
|
|
@@ -64,8 +64,12 @@ class Hyperflask(Flask):
|
|
|
64
64
|
self.wsgi_app = ProxyFix(self.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1)
|
|
65
65
|
|
|
66
66
|
self.config.update({
|
|
67
|
-
"FREEZER_DESTINATION":
|
|
67
|
+
"FREEZER_DESTINATION": "_site",
|
|
68
68
|
"FREEZER_STATIC_IGNORE": [],
|
|
69
|
+
"FREEZER_IGNORE_404_NOT_FOUND": True,
|
|
70
|
+
"FREEZER_IGNORE_MIMETYPE_WARNINGS": True,
|
|
71
|
+
"FREEZER_REDIRECT_POLICY": "ignore",
|
|
72
|
+
"FREEZER_DEFAULT_FILE_EXTENSION": "html",
|
|
69
73
|
"WTF_CSRF_CHECK_DEFAULT": False,
|
|
70
74
|
"OTEL_INSTRUMENT": instrument,
|
|
71
75
|
"DEBUG_TB_INTERCEPT_REDIRECTS": False,
|
|
@@ -92,7 +96,9 @@ class Hyperflask(Flask):
|
|
|
92
96
|
"CSP_FRAME_ANCESTORS": True,
|
|
93
97
|
"CSP_FRAME_ANCESTORS_SAFE_ENDPOINTS": [],
|
|
94
98
|
"REFERRER_POLICY": "strict-origin-when-cross-origin",
|
|
95
|
-
"HSTS_HEADER": False
|
|
99
|
+
"HSTS_HEADER": False,
|
|
100
|
+
"IMAGES_DEFAULT_LOADING": "lazy",
|
|
101
|
+
"IMAGES_DEFAULT_DECODING": "async",
|
|
96
102
|
})
|
|
97
103
|
if config:
|
|
98
104
|
self.config.update(config)
|
|
@@ -123,8 +129,13 @@ class Hyperflask(Flask):
|
|
|
123
129
|
self.jinja_env.add_extension(LayoutExtension)
|
|
124
130
|
self.jinja_env.add_extension(WtformExtension)
|
|
125
131
|
self.jinja_env.add_extension(MarkdownExtension)
|
|
126
|
-
self.jinja_env.filters.update(markdown=jinja_markdown,
|
|
127
|
-
|
|
132
|
+
self.jinja_env.filters.update(markdown=jinja_markdown,
|
|
133
|
+
sanitize=sanitize_html,
|
|
134
|
+
nl2br=nl2br)
|
|
135
|
+
self.jinja_env.globals.update(page_action_url=page_action_url,
|
|
136
|
+
app=self,
|
|
137
|
+
csp_nonce=csp_nonce,
|
|
138
|
+
metadata_tags=metadata_tags)
|
|
128
139
|
self.jinja_env.form_base_cls = Form
|
|
129
140
|
self.jinja_env.default_layout = self.config["LAYOUT"]
|
|
130
141
|
self.forms = self.jinja_env.forms
|
|
@@ -140,7 +151,7 @@ class Hyperflask(Flask):
|
|
|
140
151
|
])
|
|
141
152
|
|
|
142
153
|
DebugToolbarExtension(self)
|
|
143
|
-
self.freezer = Freezer(self, with_no_argument_rules=False)
|
|
154
|
+
self.freezer = Freezer(self, with_no_argument_rules=False, log_url_for=self.config.get('FREEZER_LOG_URL_FOR', False))
|
|
144
155
|
self.freezer.register_generator(lambda: freezer_url_generator(self))
|
|
145
156
|
self.csrf = CSRFProtect(self)
|
|
146
157
|
Htmx(self)
|
|
@@ -194,6 +205,7 @@ class Hyperflask(Flask):
|
|
|
194
205
|
if hasattr(file_routes, "loader"):
|
|
195
206
|
self.forms.register_from_loader(file_routes.loader, "pages")
|
|
196
207
|
self.macros.create_from_func(htmx_oob, "HtmxOob", receive_caller=True, caller_alias="html")
|
|
208
|
+
self.macros.create_from_func(image_tag, "Image")
|
|
197
209
|
|
|
198
210
|
self.components_loader, _ = register_components(self)
|
|
199
211
|
if self.components_loader:
|
|
@@ -286,21 +298,3 @@ class HyperModuleView(ModuleView):
|
|
|
286
298
|
|
|
287
299
|
def _render_template(self):
|
|
288
300
|
return render_template(page.template)
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
def static(func):
|
|
292
|
-
pass
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
def dynamic(func=None, static_template=None):
|
|
296
|
-
def decorator(func):
|
|
297
|
-
pass
|
|
298
|
-
return decorator(func) if func else decorator
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
def freezer_url_generator(app):
|
|
302
|
-
"""URL generator for URL rules that take no arguments."""
|
|
303
|
-
for rule in app.url_map.iter_rules():
|
|
304
|
-
if not rule.arguments and 'GET' in rule.methods and not rule.endpoint.startswith('mercure'):
|
|
305
|
-
app.logger.info(rule.endpoint)
|
|
306
|
-
yield rule.endpoint, {}
|
|
@@ -4,6 +4,7 @@ from flask_assets_pipeline import cli as assets_cli
|
|
|
4
4
|
import click
|
|
5
5
|
from ..factory import create_app
|
|
6
6
|
from ..security import generate_csp_policy
|
|
7
|
+
from ..utils.freezer import StaticMode
|
|
7
8
|
from .runner import serve_command, run_command, dev_command
|
|
8
9
|
from .worker import worker_command, scheduler_command
|
|
9
10
|
|
|
@@ -31,16 +32,12 @@ def init_command():
|
|
|
31
32
|
pass
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
@cli.command("freeze")
|
|
35
|
-
def freeze_command():
|
|
36
|
-
current_app.freezer.freeze()
|
|
37
|
-
|
|
38
|
-
|
|
39
35
|
@cli.command("build")
|
|
40
36
|
@click.pass_context
|
|
41
37
|
def build_command(ctx):
|
|
42
38
|
ctx.invoke(assets_cli.build)
|
|
43
|
-
|
|
39
|
+
if StaticMode(current_app.config['STATIC_MODE']) != StaticMode.DYNAMIC:
|
|
40
|
+
current_app.freezer.freeze()
|
|
44
41
|
|
|
45
42
|
|
|
46
43
|
@cli.command("csp-header")
|
|
@@ -48,6 +45,5 @@ def csp_header_command():
|
|
|
48
45
|
click.echo(generate_csp_policy())
|
|
49
46
|
|
|
50
47
|
|
|
51
|
-
|
|
52
48
|
def main():
|
|
53
49
|
cli.main()
|
|
@@ -4,6 +4,7 @@ from flask.views import http_method_funcs
|
|
|
4
4
|
from flask_file_routes import page
|
|
5
5
|
from flask_suspense import render_template
|
|
6
6
|
from jinjapy import extract_frontmatter
|
|
7
|
+
from ..utils.freezer import dynamic
|
|
7
8
|
import importlib
|
|
8
9
|
import re
|
|
9
10
|
import os
|
|
@@ -43,6 +44,7 @@ class ComponentAdapter(BaseComponentAdapter):
|
|
|
43
44
|
if methods:
|
|
44
45
|
app.add_url_rule(url, self.name, view_func=self.view_func, methods=methods)
|
|
45
46
|
|
|
47
|
+
@dynamic
|
|
46
48
|
def view_func(self):
|
|
47
49
|
props = {}
|
|
48
50
|
page.template = self.template
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from .core import BaseComponentAdapter
|
|
2
2
|
from markupsafe import Markup
|
|
3
3
|
from flask import current_app
|
|
4
|
-
from flask_assets_pipeline import
|
|
4
|
+
from flask_assets_pipeline import BundleEntrypoint
|
|
5
5
|
import json
|
|
6
6
|
import html
|
|
7
7
|
|
|
@@ -13,7 +13,7 @@ class JsxComponentAdapter(BaseComponentAdapter):
|
|
|
13
13
|
app.assets.state.bundles["@components"] = []
|
|
14
14
|
app.assets.include("@components")
|
|
15
15
|
app.assets.state.bundles["@components"].append(
|
|
16
|
-
|
|
16
|
+
BundleEntrypoint.create(self.template, from_package="jinja"))
|
|
17
17
|
app.assets.include(self.include_js)
|
|
18
18
|
|
|
19
19
|
def render(self, caller, *args, **kwargs):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from .core import BaseComponentAdapter
|
|
2
2
|
from jinja_super_macros import html_tag
|
|
3
|
-
from flask_assets_pipeline import
|
|
3
|
+
from flask_assets_pipeline import BundleEntrypoint
|
|
4
4
|
from markupsafe import Markup
|
|
5
5
|
import os
|
|
6
6
|
|
|
@@ -17,7 +17,7 @@ class WebComponentAdapter(BaseComponentAdapter):
|
|
|
17
17
|
app.assets.state.bundles["@components"] = []
|
|
18
18
|
app.assets.include("@components")
|
|
19
19
|
app.assets.state.bundles["@components"].append(
|
|
20
|
-
|
|
20
|
+
BundleEntrypoint.create(os.path.abspath(tpl.filename), self.template))
|
|
21
21
|
|
|
22
22
|
def render(self, caller, *args, **kwargs):
|
|
23
23
|
tag_name = self.name.replace("_", "-")
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from flask_frozen import Freezer as FlaskFreezer
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class StaticMode(Enum):
|
|
7
|
+
STATIC = "static"
|
|
8
|
+
HYBRID = "hybrid"
|
|
9
|
+
DYNAMIC = "dynamic"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Freezer(FlaskFreezer):
|
|
13
|
+
@property
|
|
14
|
+
def root(self):
|
|
15
|
+
return Path(self.app.config['FREEZER_DESTINATION'])
|
|
16
|
+
|
|
17
|
+
def _check_endpoints(self, seen_endpoints):
|
|
18
|
+
if StaticMode(self.app.config['STATIC_MODE']) != StaticMode.STATIC:
|
|
19
|
+
return
|
|
20
|
+
super()._check_endpoints(seen_endpoints)
|
|
21
|
+
|
|
22
|
+
def urlpath_to_filepath(self, path):
|
|
23
|
+
"""Convert URL path like /admin/ to file path like admin/index.html."""
|
|
24
|
+
if path.endswith('/'):
|
|
25
|
+
path += 'index.html'
|
|
26
|
+
# Remove the initial slash that should always be there
|
|
27
|
+
assert path.startswith('/')
|
|
28
|
+
if self.app.config.get('FREEZER_DEFAULT_FILE_EXTENSION') and '.' not in path.split('/')[-1]:
|
|
29
|
+
path += f".{self.app.config['FREEZER_DEFAULT_FILE_EXTENSION']}"
|
|
30
|
+
return path[1:]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def static(func=None, values=None):
|
|
34
|
+
if func is None:
|
|
35
|
+
return lambda f: static(f, values=values)
|
|
36
|
+
func.__freezer__ = True
|
|
37
|
+
func.__freezer_values__ = values
|
|
38
|
+
return func
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def dynamic(func):
|
|
42
|
+
func.__freezer__ = False
|
|
43
|
+
return func
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def freezer_url_generator(app):
|
|
47
|
+
"""URL generator for URL rules that take no arguments."""
|
|
48
|
+
for rule in app.url_map.iter_rules():
|
|
49
|
+
if rule.arguments or 'GET' not in rule.methods:
|
|
50
|
+
continue
|
|
51
|
+
if rule.endpoint.startswith('mercure_hub'):
|
|
52
|
+
continue
|
|
53
|
+
if rule.endpoint in app.view_functions and not getattr(app.view_functions[rule.endpoint], '__freezer__', True):
|
|
54
|
+
continue
|
|
55
|
+
values = getattr(app.view_functions.get(rule.endpoint), '__freezer_values__', None) or {}
|
|
56
|
+
yield rule.endpoint, values
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from flask import current_app
|
|
2
|
+
from jinja_super_macros import html_tag
|
|
3
|
+
from flask_assets_pipeline import image_attrs
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def image_tag(src, priority=False, preload=False, placeholder=True, loading=None, decoding=None, **attrs):
|
|
7
|
+
if not loading:
|
|
8
|
+
loading = current_app.config["IMAGES_DEFAULT_LOADING"]
|
|
9
|
+
if not decoding:
|
|
10
|
+
decoding = current_app.config["IMAGES_DEFAULT_DECODING"]
|
|
11
|
+
if priority:
|
|
12
|
+
preload = True
|
|
13
|
+
attrs.setdefault("fetchpriority", "high")
|
|
14
|
+
if preload:
|
|
15
|
+
current_app.assets.include([(src, {"modifier": "preload", "content_type": "image"})])
|
|
16
|
+
if loading == "lazy":
|
|
17
|
+
loading = "eager"
|
|
18
|
+
_attrs = image_attrs(src)
|
|
19
|
+
if not placeholder and "style" in _attrs:
|
|
20
|
+
del _attrs["style"]
|
|
21
|
+
if loading:
|
|
22
|
+
_attrs["loading"] = loading
|
|
23
|
+
if decoding:
|
|
24
|
+
_attrs["decoding"] = decoding
|
|
25
|
+
_attrs.update(attrs)
|
|
26
|
+
return html_tag("img", **_attrs)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|