hyperflask 0.4.2__tar.gz → 0.4.4__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.2 → hyperflask-0.4.4}/PKG-INFO +2 -2
- {hyperflask-0.4.2 → hyperflask-0.4.4}/pyproject.toml +2 -2
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/__init__.py +1 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/app.py +11 -25
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/cli/__init__.py +3 -7
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/cli/runner.py +27 -24
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/components/core.py +2 -0
- hyperflask-0.4.4/src/hyperflask/utils/freezer.py +56 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/README.md +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/__main__.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/actors.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/cli/reloader.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/cli/worker.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/components/__init__.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/components/alpine.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/components/jsx.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/components/webcomponent.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/factory.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/forms/__init__.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/forms/fields.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/forms/widgets.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/layouts/email.mjml +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/layouts/web.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/model.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/page_helpers.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/security.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/static/alpine-csp.js +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/static/alpine.js +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/static/app.css +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/static/app.js +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/static/htmx-exts.js +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/static/react.js +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/static/stimulus.js +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/static/translations.js +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Accordion.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/AccordionPanel.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Alert.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Avatar.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/AvatarGroup.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Badge.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Breadcrumbs.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/BreadcrumbsItem.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Button.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Card.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/CardActions.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/CardTitle.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/ChatBubble.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Checkbox.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/CollapsibleSubMenu.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Countdown.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Divider.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Drawer.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/DrawerContent.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/DrawerSide.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Dropdown.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/DropdownItem.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Fieldset.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/FieldsetLegend.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/FileInput.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Filter.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/FilterItem.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Footer.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/FooterLink.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/FooterNav.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Indicator.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Input.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/InputLabel.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Join.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Kbd.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Label.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/LabeledCheckbox.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/LabeledToggle.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Link.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/List.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/ListItem.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Loading.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Menu.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/MenuItem.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/MenuTitle.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Modal.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/ModalAction.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/ModalTitle.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Navbar.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Pagination.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/PaginationNext.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/PaginationPage.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/PaginationPrev.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Progress.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/README.md +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Radio.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Range.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Rating.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Select.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Stack.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Stat.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Stats.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Step.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Steps.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/SubMenu.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Swap.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Tab.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Table.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Tabs.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Textarea.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Toast.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Toggle.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/daisyui/Tooltip.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/flash.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/forms.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/icons.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/layout.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/modal.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/skeleton.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/ui/sse.html +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/utils/__init__.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/utils/html.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/utils/htmx.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/utils/markdown.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/utils/metadata.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/utils/page_actions.py +0 -0
- {hyperflask-0.4.2 → hyperflask-0.4.4}/src/hyperflask/utils/tokens.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyperflask
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
4
4
|
Summary: Full stack web framework
|
|
5
5
|
Author: Maxime Bouroumeau-Fuseau
|
|
6
6
|
Author-email: Maxime Bouroumeau-Fuseau <maxime.bouroumeau@gmail.com>
|
|
@@ -8,7 +8,7 @@ License-Expression: MIT
|
|
|
8
8
|
Requires-Dist: flask>=3.0.0,<4.0.0
|
|
9
9
|
Requires-Dist: flask-assets-pipeline~=0.7
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "hyperflask"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.4"
|
|
4
4
|
description = "Full stack web framework"
|
|
5
5
|
authors = [
|
|
6
6
|
{"name" = "Maxime Bouroumeau-Fuseau", email = "maxime.bouroumeau@gmail.com"}
|
|
@@ -12,7 +12,7 @@ dependencies = [
|
|
|
12
12
|
"flask>=3.0.0,<4.0.0",
|
|
13
13
|
"flask-assets-pipeline ~=0.7",
|
|
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",
|
|
@@ -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,7 @@ 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
34
|
from .components import register_components
|
|
35
35
|
from .model import Model, File as SQLFileType, UndefinedDatabase
|
|
36
36
|
from .actors import AppContextMiddleware, discover_broker, make_actor_decorator
|
|
@@ -41,7 +41,6 @@ from jinja_super_macros.registry import FileLoader
|
|
|
41
41
|
from jinja_wtforms.extractor import map_jinja_call_node_to_func
|
|
42
42
|
from sqlorm.sql_template import SQLTemplate
|
|
43
43
|
from periodiq import PeriodiqMiddleware
|
|
44
|
-
import dramatiq
|
|
45
44
|
import os
|
|
46
45
|
|
|
47
46
|
|
|
@@ -55,7 +54,7 @@ map_jinja_call_node_to_func(lazy_gettext, "lazy_gettext")
|
|
|
55
54
|
class Hyperflask(Flask):
|
|
56
55
|
config_class = Config
|
|
57
56
|
|
|
58
|
-
def __init__(self, *args, static_mode=
|
|
57
|
+
def __init__(self, *args, static_mode=StaticMode.DYNAMIC, instrument=False, layouts_folder="layouts",
|
|
59
58
|
emails_folder="emails", forms_folder="forms", assets_folder="assets", pages_folder="pages", migrations_folder="migrations",
|
|
60
59
|
config=None, config_filename="config.yml", database_uri=None, proxy_fix=True, **kwargs):
|
|
61
60
|
|
|
@@ -64,8 +63,12 @@ class Hyperflask(Flask):
|
|
|
64
63
|
self.wsgi_app = ProxyFix(self.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1)
|
|
65
64
|
|
|
66
65
|
self.config.update({
|
|
67
|
-
"FREEZER_DESTINATION":
|
|
66
|
+
"FREEZER_DESTINATION": "_site",
|
|
68
67
|
"FREEZER_STATIC_IGNORE": [],
|
|
68
|
+
"FREEZER_IGNORE_404_NOT_FOUND": True,
|
|
69
|
+
"FREEZER_IGNORE_MIMETYPE_WARNINGS": True,
|
|
70
|
+
"FREEZER_REDIRECT_POLICY": "ignore",
|
|
71
|
+
"FREEZER_DEFAULT_FILE_EXTENSION": "html",
|
|
69
72
|
"WTF_CSRF_CHECK_DEFAULT": False,
|
|
70
73
|
"OTEL_INSTRUMENT": instrument,
|
|
71
74
|
"DEBUG_TB_INTERCEPT_REDIRECTS": False,
|
|
@@ -114,8 +117,9 @@ class Hyperflask(Flask):
|
|
|
114
117
|
})
|
|
115
118
|
self.config.setdefault("HSTS_HEADER", "max-age=31556926; includeSubDomains") # 1 year
|
|
116
119
|
|
|
117
|
-
if
|
|
118
|
-
self.config['
|
|
120
|
+
if not self.debug and not self.testing and not self.config.get('MERCURE_HUB_URL'):
|
|
121
|
+
self.config['MERCURE_HUB_URL'] = "http://localhost:5300/.well-known/mercure"
|
|
122
|
+
self.config.setdefault('MERCURE_PUBLIC_HUB_URL', True)
|
|
119
123
|
|
|
120
124
|
#self.otel = Observability(self)
|
|
121
125
|
|
|
@@ -139,7 +143,7 @@ class Hyperflask(Flask):
|
|
|
139
143
|
])
|
|
140
144
|
|
|
141
145
|
DebugToolbarExtension(self)
|
|
142
|
-
self.freezer = Freezer(self, with_no_argument_rules=False)
|
|
146
|
+
self.freezer = Freezer(self, with_no_argument_rules=False, log_url_for=self.config.get('FREEZER_LOG_URL_FOR', False))
|
|
143
147
|
self.freezer.register_generator(lambda: freezer_url_generator(self))
|
|
144
148
|
self.csrf = CSRFProtect(self)
|
|
145
149
|
Htmx(self)
|
|
@@ -285,21 +289,3 @@ class HyperModuleView(ModuleView):
|
|
|
285
289
|
|
|
286
290
|
def _render_template(self):
|
|
287
291
|
return render_template(page.template)
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
def static(func):
|
|
291
|
-
pass
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
def dynamic(func=None, static_template=None):
|
|
295
|
-
def decorator(func):
|
|
296
|
-
pass
|
|
297
|
-
return decorator(func) if func else decorator
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
def freezer_url_generator(app):
|
|
301
|
-
"""URL generator for URL rules that take no arguments."""
|
|
302
|
-
for rule in app.url_map.iter_rules():
|
|
303
|
-
if not rule.arguments and 'GET' in rule.methods and not rule.endpoint.startswith('mercure'):
|
|
304
|
-
app.logger.info(rule.endpoint)
|
|
305
|
-
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()
|
|
@@ -55,38 +55,41 @@ def run_command(processes, host, port, concurrency, extend_procfile, init_db, de
|
|
|
55
55
|
print("Initializing database...")
|
|
56
56
|
Popen([sys.argv[0], "db", "init"]).wait()
|
|
57
57
|
|
|
58
|
-
_processes =
|
|
58
|
+
_processes = {}
|
|
59
|
+
procfile = None
|
|
59
60
|
config = load_config()
|
|
60
61
|
|
|
61
62
|
for filename in [f"Procfile.{config['ENV']}", "Procfile"]:
|
|
62
63
|
if os.path.exists(filename):
|
|
63
64
|
with open(filename) as f:
|
|
64
|
-
|
|
65
|
+
procfile = parse_procfile(f.read()).processes
|
|
65
66
|
break
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
68
|
+
_processes = {
|
|
69
|
+
"web": [sys.argv[0], "serve", "--host", host, "--port", "$PORT"],
|
|
70
|
+
"worker": [sys.argv[0], "worker"],
|
|
71
|
+
"scheduler": [sys.argv[0], "scheduler"]
|
|
72
|
+
}
|
|
73
|
+
if dev:
|
|
74
|
+
_processes["assets"] = [sys.argv[0], "assets", "dev"]
|
|
75
|
+
_processes["worker"].extend(["-p", "1", "-t", "1"])
|
|
76
|
+
else:
|
|
77
|
+
_processes["mercurehub"] = [sys.executable, "-m", "flask_mercure_sse.server", "--port", "$PORT"]
|
|
78
|
+
subscriber_secret_key = config.get("MERCURE_SUBSCRIBER_SECRET_KEY", config.get('SECRET_KEY'))
|
|
79
|
+
if subscriber_secret_key:
|
|
80
|
+
_processes["mercurehub"].extend(["--subscriber-secret", subscriber_secret_key])
|
|
78
81
|
else:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
82
|
+
print("Warning: No MERCURE_SUBSCRIBER_SECRET_KEY or SECRET_KEY set, Mercure subscriber will not be authenticated.")
|
|
83
|
+
publisher_secret_key = config.get("MERCURE_PUBLISHER_SECRET_KEY", config.get('SECRET_KEY'))
|
|
84
|
+
if publisher_secret_key:
|
|
85
|
+
_processes["mercurehub"].extend(["--publisher-secret", publisher_secret_key])
|
|
86
|
+
else:
|
|
87
|
+
print("Warning: No MERCURE_PUBLISHER_SECRET_KEY or SECRET_KEY set, cannot publish Mercure messages.")
|
|
88
|
+
|
|
89
|
+
if procfile and extend_procfile:
|
|
90
|
+
_processes.update(procfile)
|
|
91
|
+
elif procfile:
|
|
92
|
+
_processes = procfile
|
|
90
93
|
|
|
91
94
|
processes = {name: " ".join(_processes[name]) if isinstance(_processes[name], list) else _processes[name]
|
|
92
95
|
for name in _processes if not processes or name in processes}
|
|
@@ -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
|
|
@@ -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
|
|
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
|
|
File without changes
|
|
File without changes
|