hyperflask 0.1.5__tar.gz → 0.2.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.1.5/README.md → hyperflask-0.2.0/PKG-INFO +44 -35
- hyperflask-0.1.5/PKG-INFO → hyperflask-0.2.0/README.md +7 -80
- hyperflask-0.2.0/pyproject.toml +60 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/__init__.py +4 -3
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/app.py +45 -35
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/cli.py +0 -1
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/components/__init__.py +17 -8
- hyperflask-0.2.0/src/hyperflask/components/alpine.py +14 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/components/core.py +18 -5
- hyperflask-0.2.0/src/hyperflask/components/jsx.py +41 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/components/webcomponent.py +7 -6
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/factory.py +13 -87
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/forms/__init__.py +9 -2
- hyperflask-0.2.0/src/hyperflask/forms/fields.py +40 -0
- hyperflask-0.2.0/src/hyperflask/forms/widgets.py +36 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/layouts/email.mjml +1 -1
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/layouts/web.html +6 -1
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/reactivity.py +20 -14
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/static/app.css +8 -0
- hyperflask-0.2.0/src/hyperflask/static/app.js +46 -0
- hyperflask-0.2.0/src/hyperflask/static/react.js +15 -0
- hyperflask-0.2.0/src/hyperflask/static/reactive.js +39 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Accordion.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/AccordionPanel.html +17 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Alert.html +36 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Avatar.html +16 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/AvatarGroup.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Badge.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Breadcrumbs.html +12 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/BreadcrumbsItem.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Button.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Card.html +22 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/CardActions.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/CardTitle.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/ChatBubble.html +30 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Checkbox.html +3 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/CollapsibleSubMenu.html +21 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Countdown.html +9 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Divider.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Drawer.html +10 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/DrawerContent.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/DrawerSide.html +11 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Dropdown.html +17 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/DropdownItem.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Fieldset.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/FieldsetLegend.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/FileInput.html +3 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Filter.html +10 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/FilterItem.html +3 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Footer.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/FooterLink.html +6 -0
- {hyperflask-0.1.5/hyperflask/ui/components/layout → hyperflask-0.2.0/src/hyperflask/ui/daisyui}/FooterNav.html +3 -2
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Indicator.html +12 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Input.html +3 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/InputLabel.html +12 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Join.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Kbd.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Label.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/LabeledCheckbox.html +10 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/LabeledToggle.html +10 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Link.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/List.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/ListItem.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Loading.html +4 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Menu.html +12 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/MenuItem.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/MenuTitle.html +6 -0
- {hyperflask-0.1.5/hyperflask/ui/components/actions → hyperflask-0.2.0/src/hyperflask/ui/daisyui}/Modal.html +3 -3
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/ModalAction.html +12 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/ModalTitle.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Navbar.html +36 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Pagination.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/PaginationNext.html +5 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/PaginationPage.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/PaginationPrev.html +5 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Progress.html +4 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Radio.html +3 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Range.html +3 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Rating.html +23 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Select.html +12 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Stack.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Stat.html +14 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Stats.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Step.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Steps.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/SubMenu.html +16 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Swap.html +10 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Tab.html +3 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Table.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Tabs.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Textarea.html +6 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Toast.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Toggle.html +3 -0
- hyperflask-0.2.0/src/hyperflask/ui/daisyui/Tooltip.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/flash.html +8 -0
- hyperflask-0.2.0/src/hyperflask/ui/forms.html +35 -0
- hyperflask-0.2.0/src/hyperflask/ui/sse.html +6 -0
- hyperflask-0.2.0/src/hyperflask/utils/__init__.py +0 -0
- hyperflask-0.2.0/src/hyperflask/utils/html.py +13 -0
- hyperflask-0.2.0/src/hyperflask/utils/htmx.py +27 -0
- hyperflask-0.2.0/src/hyperflask/utils/markdown.py +32 -0
- hyperflask-0.2.0/src/hyperflask/utils/models.py +5 -0
- hyperflask-0.2.0/src/hyperflask/utils/s3.py +4 -0
- hyperflask-0.1.5/LICENSE +0 -19
- hyperflask-0.1.5/hyperflask/api.py +0 -57
- hyperflask-0.1.5/hyperflask/components/alpine.py +0 -16
- hyperflask-0.1.5/hyperflask/forms/fields.py +0 -17
- hyperflask-0.1.5/hyperflask/forms/widgets.py +0 -19
- hyperflask-0.1.5/hyperflask/resources.py +0 -149
- hyperflask-0.1.5/hyperflask/static/app.js +0 -5
- hyperflask-0.1.5/hyperflask/static/htmx.js +0 -5
- hyperflask-0.1.5/hyperflask/static/reactive.js +0 -5
- hyperflask-0.1.5/hyperflask/ui/components/actions/Button.html +0 -6
- hyperflask-0.1.5/hyperflask/ui/components/actions/Dropdown.html +0 -16
- hyperflask-0.1.5/hyperflask/ui/components/actions/DropdownItem.html +0 -8
- hyperflask-0.1.5/hyperflask/ui/components/actions/LinkButton.html +0 -6
- hyperflask-0.1.5/hyperflask/ui/components/actions/ModalAction.html +0 -12
- hyperflask-0.1.5/hyperflask/ui/components/actions/ModalTitle.html +0 -6
- hyperflask-0.1.5/hyperflask/ui/components/data-display/Accordion.html +0 -8
- hyperflask-0.1.5/hyperflask/ui/components/data-display/AccordionPanel.html +0 -18
- hyperflask-0.1.5/hyperflask/ui/components/data-input/Checkbox.html +0 -4
- hyperflask-0.1.5/hyperflask/ui/components/data-input/FileInput.html +0 -4
- hyperflask-0.1.5/hyperflask/ui/components/data-input/FormControl.html +0 -15
- hyperflask-0.1.5/hyperflask/ui/components/data-input/Input.html +0 -4
- hyperflask-0.1.5/hyperflask/ui/components/data-input/LabeledCheckbox.html +0 -11
- hyperflask-0.1.5/hyperflask/ui/components/data-input/LabeledTextInput.html +0 -11
- hyperflask-0.1.5/hyperflask/ui/components/data-input/Radiobox.html +0 -4
- hyperflask-0.1.5/hyperflask/ui/components/data-input/Range.html +0 -4
- hyperflask-0.1.5/hyperflask/ui/components/data-input/Rating.html +0 -20
- hyperflask-0.1.5/hyperflask/ui/components/data-input/Select.html +0 -11
- hyperflask-0.1.5/hyperflask/ui/components/data-input/Textarea.html +0 -6
- hyperflask-0.1.5/hyperflask/ui/components/data-input/Toggle.html +0 -4
- hyperflask-0.1.5/hyperflask/ui/components/feedback/Loading.html +0 -4
- hyperflask-0.1.5/hyperflask/ui/components/feedback/Toast.html +0 -8
- hyperflask-0.1.5/hyperflask/ui/components/layout/Footer.html +0 -8
- hyperflask-0.1.5/hyperflask/ui/components/layout/FooterLink.html +0 -6
- hyperflask-0.1.5/hyperflask/ui/components/layout/Indicator.html +0 -11
- hyperflask-0.1.5/hyperflask/ui/components/navigation/Link.html +0 -6
- hyperflask-0.1.5/hyperflask/ui/components/navigation/Navbar.html +0 -21
- hyperflask-0.1.5/hyperflask/ui/forms.html +0 -16
- hyperflask-0.1.5/hyperflask/utils/__init__.py +0 -5
- hyperflask-0.1.5/hyperflask/utils/htmx.py +0 -24
- hyperflask-0.1.5/pyproject.toml +0 -53
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/__main__.py +0 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/page_helpers.py +0 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/static/alpine.js +0 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/static/stimulus.js +0 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/static/translations.js +0 -0
- {hyperflask-0.1.5/hyperflask/ui/components → hyperflask-0.2.0/src/hyperflask/ui/daisyui}/README.md +0 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/ui/icons.html +0 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/ui/modal.html +0 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/utils/page_actions.py +0 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/utils/request.py +0 -0
- {hyperflask-0.1.5 → hyperflask-0.2.0/src}/hyperflask/utils/tokens.py +0 -0
|
@@ -1,20 +1,51 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hyperflask
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Full stack web framework
|
|
5
|
+
Author: Maxime Bouroumeau-Fuseau
|
|
6
|
+
Author-email: Maxime Bouroumeau-Fuseau <maxime.bouroumeau@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Requires-Dist: flask>=3.0.0,<4.0.0
|
|
9
|
+
Requires-Dist: flask-assets-pipeline~=0.6
|
|
10
|
+
Requires-Dist: flask-babel-hyper~=5.1
|
|
11
|
+
Requires-Dist: flask-collections~=0.2
|
|
12
|
+
Requires-Dist: flask-configurator~=0.1
|
|
13
|
+
Requires-Dist: flask-debugtoolbar~=0.15
|
|
14
|
+
Requires-Dist: flask-dramatiq~=0.6
|
|
15
|
+
Requires-Dist: flask-file-routes~=0.2
|
|
16
|
+
Requires-Dist: flask-files~=0.2
|
|
17
|
+
Requires-Dist: flask-geo~=0.1
|
|
18
|
+
Requires-Dist: flask-mailman-templates~=0.1
|
|
19
|
+
Requires-Dist: flask-mercure-sse~=0.2
|
|
20
|
+
Requires-Dist: flask-sqlorm~=0.2
|
|
21
|
+
Requires-Dist: flask-super-macros~=0.1
|
|
22
|
+
Requires-Dist: flask-talisman~=1.1
|
|
23
|
+
Requires-Dist: flask-wtf~=1.2
|
|
24
|
+
Requires-Dist: frozen-flask~=1.0
|
|
25
|
+
Requires-Dist: gunicorn~=22.0
|
|
26
|
+
Requires-Dist: honcho~=1.1
|
|
27
|
+
Requires-Dist: html-sanitizer~=2.4
|
|
28
|
+
Requires-Dist: htmx-flask~=0.1
|
|
29
|
+
Requires-Dist: jinja2-fragments~=1.3
|
|
30
|
+
Requires-Dist: jinja-layout~=0.4
|
|
31
|
+
Requires-Dist: jinja-wtforms~=0.2
|
|
32
|
+
Requires-Dist: periodiq~=0.12
|
|
33
|
+
Requires-Dist: python-slugify~=8.0.4
|
|
34
|
+
Requires-Python: >=3.10
|
|
35
|
+
Project-URL: Repository, https://github.com/hyperflask/hyperflask
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
1
38
|
<div><img src="https://raw.githubusercontent.com/hyperflask/hyperflask/main/assets/banner.svg" width="100%"></div>
|
|
2
39
|
<hr>
|
|
3
40
|
<div align="center">
|
|
4
41
|
|
|
5
42
|
**Full stack Python web framework to build websites and web apps with as little boilerplate as possible**
|
|
6
43
|
|
|
7
|
-
**⚠️ This is a work in progress project which is not functionnal yet ⚠️**
|
|
8
|
-
|
|
9
|
-
 
|
|
10
|
-
|
|
11
44
|
[hyperflask.dev](https://hyperflask.dev) • [Get started](https://hyperflask.dev/getting-started) • [Docs](https://hyperflask.dev/guides) • [Example apps](https://github.com/hyperflask/examples)
|
|
12
45
|
|
|
13
46
|
</div>
|
|
14
47
|
|
|
15
|
-
A [Flask](https://flask.palletsprojects.com)-based (very) opiniated
|
|
16
|
-
|
|
17
|
-
**This project is part of the [Hyperflask Stack](https://hyperflask.dev).**
|
|
48
|
+
A [Flask](https://flask.palletsprojects.com)-based (very) opiniated full-stack web framework where all the tech choices have been made. Hyperflask combines multiple Flask extensions and frontend libraries into a seamless experience.
|
|
18
49
|
|
|
19
50
|
Features and technologies:
|
|
20
51
|
|
|
@@ -24,52 +55,32 @@ Features and technologies:
|
|
|
24
55
|
- SQL focused ORM with [sqlorm](https://github.com/hyperflask/sqlorm), optimized for [sqlite](https://www.sqlite.org/)
|
|
25
56
|
- Modern asset pipeline using [esbuild](https://esbuild.github.io/) and [tailwindcss](https://tailwindcss.com/)
|
|
26
57
|
- Deep integration with [htmx](https://htmx.org/)
|
|
27
|
-
- Easily create reusable backend and frontend components
|
|
28
|
-
- Build frontend components using Web Components, [Alpine.js](https://alpinejs.dev/), [
|
|
58
|
+
- Easily create reusable backend and frontend components
|
|
59
|
+
- Build frontend components using Web Components, [Alpine.js](https://alpinejs.dev/), [React](https://react.dev) and more. Mix technologies at will.
|
|
29
60
|
- Component library based on [daisyUI](https://daisyui.com/) with icons from [Bootstrap Icons](https://icons.getbootstrap.com/)
|
|
30
|
-
- Seamless reactivity between frontend and backend
|
|
31
61
|
- Authentication and user management with social logins and MFA
|
|
32
62
|
- Static content collections to easily create blogs and manage static content
|
|
33
63
|
- File management with built-in image manipulation and S3 integration
|
|
34
64
|
- Template based emails with [mjml](https://mjml.io) support
|
|
35
|
-
- Background tasks using [dramatiq](https://dramatiq.io/)
|
|
65
|
+
- Background tasks using [dramatiq](https://dramatiq.io/) with sqlite as the default broker
|
|
36
66
|
- Push support for realtime pages using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
|
|
37
67
|
- I18n using [gettext](https://www.gnu.org/software/gettext/)
|
|
38
|
-
- Easily create REST APIs and automatically generate documentation
|
|
39
68
|
- Static, hybrid or dynamic modes for content serving
|
|
40
|
-
- Observable with [OpenTelemetry](https://opentelemetry.io/)
|
|
41
69
|
|
|
42
70
|
[Hyperflask-Start](https://github.com/hyperflask/hyperflask-start) should be used to create new projects:
|
|
43
71
|
|
|
44
72
|
- Dev environment based on [Development Containers](https://containers.dev/)
|
|
45
73
|
- Optimized for VScode with breakpoint debugging for frontend and backend
|
|
46
74
|
- [Mailpit](https://github.com/axllent/mailpit) for email testing
|
|
47
|
-
- Deployments using [
|
|
75
|
+
- Deployments using [docker-web-deploy](https://github.com/hyperflask/docker-web-deploy)
|
|
48
76
|
|
|
49
77
|
## Project status
|
|
50
78
|
|
|
51
79
|
**Hyperflask is being actively developed and is not yet ready to be used.**
|
|
52
80
|
|
|
53
|
-
Checkout the list of all the projects developed as part of the Hyperflask
|
|
54
|
-
|
|
55
|
-
Status overview:
|
|
81
|
+
Checkout the list of all the projects developed as part of the Hyperflask stack and their current development status on the [Hyperflask Github organization homepage](https://github.com/hyperflask).
|
|
56
82
|
|
|
57
|
-
|
|
58
|
-
| --- | --- |
|
|
59
|
-
| Core experience (start project, dev, deploy) | 🚧 |
|
|
60
|
-
| File based routing with mix code page format | ✅ |
|
|
61
|
-
| ORM | ✅ |
|
|
62
|
-
| Assets pipeline | ✅ |
|
|
63
|
-
| Component system + component library | 🚧 (component system almost done, need to create macros for daisyui) |
|
|
64
|
-
| SSE push | ✅ |
|
|
65
|
-
| Collections | 🚧 (finalizing) |
|
|
66
|
-
| Upload files | 🚧 (missing S3 improvements) |
|
|
67
|
-
| Emails | 🚧 |
|
|
68
|
-
| User management and auth | 🚧 |
|
|
69
|
-
| Static site generation | ❌ |
|
|
70
|
-
| I18n | 🚧 (finalizing) |
|
|
71
|
-
| PWA | ❌ |
|
|
72
|
-
| Runner | ✅ |
|
|
83
|
+
[Project status and roadmap](https://hyperflask.dev/roadmap)
|
|
73
84
|
|
|
74
85
|
## Flask extensions
|
|
75
86
|
|
|
@@ -79,7 +90,6 @@ A good part of these extensions is developed as part of the Hyperflask project.
|
|
|
79
90
|
|
|
80
91
|
| Name | Description |
|
|
81
92
|
| --- | --- |
|
|
82
|
-
| [Flask-Apispec-Hyper](https://github.com/hyperflask/flask-apispec-hyper) | [Flask-Apispec](https://github.com/jmcarp/flask-apispec) fork with updates and fixes
|
|
83
93
|
| [Flask-Assets-Pipeline](https://github.com/hyperflask/flask-assets-pipeline) | Modern asset pipeline using [esbuild](https://esbuild.github.io/)
|
|
84
94
|
| [Flask-Babel-Hyper](https://github.com/hyperflask/flask-babel-hyper) | [Flask-Babel](https://github.com/python-babel/flask-babel) fork with additional utilities
|
|
85
95
|
| [Flask-Collections](https://github.com/hyperflask/flask-collections) | Manage collections of static content
|
|
@@ -95,7 +105,6 @@ A good part of these extensions is developed as part of the Hyperflask project.
|
|
|
95
105
|
| [Flask-Mailman](https://github.com/waynerv/flask-mailman) | Send emails |
|
|
96
106
|
| [Flask-Mailman-Templates](https://github.com/hyperflask/flask-mailman-templates) | Email templates for [Flask-Mailman](https://github.com/waynerv/flask-mailman)
|
|
97
107
|
| [Flask-Mercure-SSE](https://github.com/hyperflask/flask-mercure-sse) | Push events via server-sent events using the [Mercure](https://mercure.rocks) protocol
|
|
98
|
-
| [Flask-Observability](https://github.com/hyperflask/flask-observability) | Observable Flask apps with [OpenTelemetry](https://opentelemetry.io/), logging and more
|
|
99
108
|
| [Flask-SQLORM](https://github.com/hyperflask/flask-sqlorm) | Flask integration of [sqlorm](https://github.com/hyperflask/sqlorm)
|
|
100
109
|
| [Flask-Super-Macros](https://github.com/hyperflask/flask-super-macros) | Better macro management for Jinja
|
|
101
110
|
| [Flask-Talisman](https://github.com/wntrblm/flask-talisman) | HTTP security headers for Flask
|
|
@@ -1,64 +1,14 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: hyperflask
|
|
3
|
-
Version: 0.1.5
|
|
4
|
-
Summary: Full stack web framework
|
|
5
|
-
Home-page: https://github.com/hyperflask/hyperflask
|
|
6
|
-
License: MIT
|
|
7
|
-
Author: Maxime Bouroumeau-Fuseau
|
|
8
|
-
Author-email: maxime.bouroumeau@gmail.com
|
|
9
|
-
Requires-Python: >=3.10,<4.0
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
-
Requires-Dist: flask (>=3.0,<4.0)
|
|
16
|
-
Requires-Dist: flask-apispec-hyper (>=0.12,<0.13)
|
|
17
|
-
Requires-Dist: flask-assets-pipeline (>=0.1,<0.2)
|
|
18
|
-
Requires-Dist: flask-babel-hyper (>=5.0,<6.0)
|
|
19
|
-
Requires-Dist: flask-collections (>=0.1,<0.2)
|
|
20
|
-
Requires-Dist: flask-configurator (>=0.1,<0.2)
|
|
21
|
-
Requires-Dist: flask-debugtoolbar (>=0.15,<0.16)
|
|
22
|
-
Requires-Dist: flask-dramatiq (>=0.6,<0.7)
|
|
23
|
-
Requires-Dist: flask-file-routes (>=0.1,<0.2)
|
|
24
|
-
Requires-Dist: flask-files (>=0.1,<0.2)
|
|
25
|
-
Requires-Dist: flask-geo (>=0.1,<0.2)
|
|
26
|
-
Requires-Dist: flask-mailman-templates (>=0.1,<0.2)
|
|
27
|
-
Requires-Dist: flask-mercure-sse (>=0.1,<0.2)
|
|
28
|
-
Requires-Dist: flask-sqlorm (>=0.1,<0.2)
|
|
29
|
-
Requires-Dist: flask-super-macros (>=0.1,<0.2)
|
|
30
|
-
Requires-Dist: flask-talisman (>=1.1,<2.0)
|
|
31
|
-
Requires-Dist: flask-wtf (>=1.2,<2.0)
|
|
32
|
-
Requires-Dist: frozen-flask (>=1.0,<2.0)
|
|
33
|
-
Requires-Dist: gunicorn (>=22.0,<23.0)
|
|
34
|
-
Requires-Dist: honcho (>=1.1,<2.0)
|
|
35
|
-
Requires-Dist: htmx-flask (>=0.1,<0.2)
|
|
36
|
-
Requires-Dist: jinja-layout (>=0.4,<0.5)
|
|
37
|
-
Requires-Dist: jinja-wtforms (>=0.1,<0.2)
|
|
38
|
-
Requires-Dist: jinja2-fragments (>=1.3,<2.0)
|
|
39
|
-
Requires-Dist: periodiq (>=0.12,<0.13)
|
|
40
|
-
Requires-Dist: python-slugify (>=8.0.4,<9.0.0)
|
|
41
|
-
Requires-Dist: redis (>=5.0,<6.0)
|
|
42
|
-
Project-URL: Repository, https://github.com/hyperflask/hyperflask
|
|
43
|
-
Description-Content-Type: text/markdown
|
|
44
|
-
|
|
45
1
|
<div><img src="https://raw.githubusercontent.com/hyperflask/hyperflask/main/assets/banner.svg" width="100%"></div>
|
|
46
2
|
<hr>
|
|
47
3
|
<div align="center">
|
|
48
4
|
|
|
49
5
|
**Full stack Python web framework to build websites and web apps with as little boilerplate as possible**
|
|
50
6
|
|
|
51
|
-
**⚠️ This is a work in progress project which is not functionnal yet ⚠️**
|
|
52
|
-
|
|
53
|
-
 
|
|
54
|
-
|
|
55
7
|
[hyperflask.dev](https://hyperflask.dev) • [Get started](https://hyperflask.dev/getting-started) • [Docs](https://hyperflask.dev/guides) • [Example apps](https://github.com/hyperflask/examples)
|
|
56
8
|
|
|
57
9
|
</div>
|
|
58
10
|
|
|
59
|
-
A [Flask](https://flask.palletsprojects.com)-based (very) opiniated
|
|
60
|
-
|
|
61
|
-
**This project is part of the [Hyperflask Stack](https://hyperflask.dev).**
|
|
11
|
+
A [Flask](https://flask.palletsprojects.com)-based (very) opiniated full-stack web framework where all the tech choices have been made. Hyperflask combines multiple Flask extensions and frontend libraries into a seamless experience.
|
|
62
12
|
|
|
63
13
|
Features and technologies:
|
|
64
14
|
|
|
@@ -68,52 +18,32 @@ Features and technologies:
|
|
|
68
18
|
- SQL focused ORM with [sqlorm](https://github.com/hyperflask/sqlorm), optimized for [sqlite](https://www.sqlite.org/)
|
|
69
19
|
- Modern asset pipeline using [esbuild](https://esbuild.github.io/) and [tailwindcss](https://tailwindcss.com/)
|
|
70
20
|
- Deep integration with [htmx](https://htmx.org/)
|
|
71
|
-
- Easily create reusable backend and frontend components
|
|
72
|
-
- Build frontend components using Web Components, [Alpine.js](https://alpinejs.dev/), [
|
|
21
|
+
- Easily create reusable backend and frontend components
|
|
22
|
+
- Build frontend components using Web Components, [Alpine.js](https://alpinejs.dev/), [React](https://react.dev) and more. Mix technologies at will.
|
|
73
23
|
- Component library based on [daisyUI](https://daisyui.com/) with icons from [Bootstrap Icons](https://icons.getbootstrap.com/)
|
|
74
|
-
- Seamless reactivity between frontend and backend
|
|
75
24
|
- Authentication and user management with social logins and MFA
|
|
76
25
|
- Static content collections to easily create blogs and manage static content
|
|
77
26
|
- File management with built-in image manipulation and S3 integration
|
|
78
27
|
- Template based emails with [mjml](https://mjml.io) support
|
|
79
|
-
- Background tasks using [dramatiq](https://dramatiq.io/)
|
|
28
|
+
- Background tasks using [dramatiq](https://dramatiq.io/) with sqlite as the default broker
|
|
80
29
|
- Push support for realtime pages using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
|
|
81
30
|
- I18n using [gettext](https://www.gnu.org/software/gettext/)
|
|
82
|
-
- Easily create REST APIs and automatically generate documentation
|
|
83
31
|
- Static, hybrid or dynamic modes for content serving
|
|
84
|
-
- Observable with [OpenTelemetry](https://opentelemetry.io/)
|
|
85
32
|
|
|
86
33
|
[Hyperflask-Start](https://github.com/hyperflask/hyperflask-start) should be used to create new projects:
|
|
87
34
|
|
|
88
35
|
- Dev environment based on [Development Containers](https://containers.dev/)
|
|
89
36
|
- Optimized for VScode with breakpoint debugging for frontend and backend
|
|
90
37
|
- [Mailpit](https://github.com/axllent/mailpit) for email testing
|
|
91
|
-
- Deployments using [
|
|
38
|
+
- Deployments using [docker-web-deploy](https://github.com/hyperflask/docker-web-deploy)
|
|
92
39
|
|
|
93
40
|
## Project status
|
|
94
41
|
|
|
95
42
|
**Hyperflask is being actively developed and is not yet ready to be used.**
|
|
96
43
|
|
|
97
|
-
Checkout the list of all the projects developed as part of the Hyperflask
|
|
44
|
+
Checkout the list of all the projects developed as part of the Hyperflask stack and their current development status on the [Hyperflask Github organization homepage](https://github.com/hyperflask).
|
|
98
45
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
| Feature | Status |
|
|
102
|
-
| --- | --- |
|
|
103
|
-
| Core experience (start project, dev, deploy) | 🚧 |
|
|
104
|
-
| File based routing with mix code page format | ✅ |
|
|
105
|
-
| ORM | ✅ |
|
|
106
|
-
| Assets pipeline | ✅ |
|
|
107
|
-
| Component system + component library | 🚧 (component system almost done, need to create macros for daisyui) |
|
|
108
|
-
| SSE push | ✅ |
|
|
109
|
-
| Collections | 🚧 (finalizing) |
|
|
110
|
-
| Upload files | 🚧 (missing S3 improvements) |
|
|
111
|
-
| Emails | 🚧 |
|
|
112
|
-
| User management and auth | 🚧 |
|
|
113
|
-
| Static site generation | ❌ |
|
|
114
|
-
| I18n | 🚧 (finalizing) |
|
|
115
|
-
| PWA | ❌ |
|
|
116
|
-
| Runner | ✅ |
|
|
46
|
+
[Project status and roadmap](https://hyperflask.dev/roadmap)
|
|
117
47
|
|
|
118
48
|
## Flask extensions
|
|
119
49
|
|
|
@@ -123,7 +53,6 @@ A good part of these extensions is developed as part of the Hyperflask project.
|
|
|
123
53
|
|
|
124
54
|
| Name | Description |
|
|
125
55
|
| --- | --- |
|
|
126
|
-
| [Flask-Apispec-Hyper](https://github.com/hyperflask/flask-apispec-hyper) | [Flask-Apispec](https://github.com/jmcarp/flask-apispec) fork with updates and fixes
|
|
127
56
|
| [Flask-Assets-Pipeline](https://github.com/hyperflask/flask-assets-pipeline) | Modern asset pipeline using [esbuild](https://esbuild.github.io/)
|
|
128
57
|
| [Flask-Babel-Hyper](https://github.com/hyperflask/flask-babel-hyper) | [Flask-Babel](https://github.com/python-babel/flask-babel) fork with additional utilities
|
|
129
58
|
| [Flask-Collections](https://github.com/hyperflask/flask-collections) | Manage collections of static content
|
|
@@ -139,7 +68,6 @@ A good part of these extensions is developed as part of the Hyperflask project.
|
|
|
139
68
|
| [Flask-Mailman](https://github.com/waynerv/flask-mailman) | Send emails |
|
|
140
69
|
| [Flask-Mailman-Templates](https://github.com/hyperflask/flask-mailman-templates) | Email templates for [Flask-Mailman](https://github.com/waynerv/flask-mailman)
|
|
141
70
|
| [Flask-Mercure-SSE](https://github.com/hyperflask/flask-mercure-sse) | Push events via server-sent events using the [Mercure](https://mercure.rocks) protocol
|
|
142
|
-
| [Flask-Observability](https://github.com/hyperflask/flask-observability) | Observable Flask apps with [OpenTelemetry](https://opentelemetry.io/), logging and more
|
|
143
71
|
| [Flask-SQLORM](https://github.com/hyperflask/flask-sqlorm) | Flask integration of [sqlorm](https://github.com/hyperflask/sqlorm)
|
|
144
72
|
| [Flask-Super-Macros](https://github.com/hyperflask/flask-super-macros) | Better macro management for Jinja
|
|
145
73
|
| [Flask-Talisman](https://github.com/wntrblm/flask-talisman) | HTTP security headers for Flask
|
|
@@ -153,4 +81,3 @@ A good part of these extensions is developed as part of the Hyperflask project.
|
|
|
153
81
|
4. Create a pages directory: `mkdir pages`
|
|
154
82
|
5. Create your index page: `echo "hello world" > pages/index.html`
|
|
155
83
|
6. Start a development server using `hyperflask dev`
|
|
156
|
-
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "hyperflask"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "Full stack web framework"
|
|
5
|
+
authors = [
|
|
6
|
+
{"name" = "Maxime Bouroumeau-Fuseau", email = "maxime.bouroumeau@gmail.com"}
|
|
7
|
+
]
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
license = "MIT"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"flask>=3.0.0,<4.0.0",
|
|
13
|
+
"flask-assets-pipeline ~=0.6",
|
|
14
|
+
"flask-babel-hyper ~=5.1",
|
|
15
|
+
"flask-collections ~=0.2",
|
|
16
|
+
"flask-configurator ~=0.1",
|
|
17
|
+
"flask-debugtoolbar ~=0.15",
|
|
18
|
+
"flask-dramatiq ~=0.6",
|
|
19
|
+
"flask-file-routes ~=0.2",
|
|
20
|
+
"flask-files ~=0.2",
|
|
21
|
+
"flask-geo ~=0.1",
|
|
22
|
+
"flask-mailman-templates ~=0.1",
|
|
23
|
+
"flask-mercure-sse ~=0.2",
|
|
24
|
+
#"flask-observability ~=0.1"
|
|
25
|
+
"flask-sqlorm ~=0.2",
|
|
26
|
+
"flask-super-macros ~=0.1",
|
|
27
|
+
"flask-talisman ~=1.1",
|
|
28
|
+
"flask-wtf ~=1.2",
|
|
29
|
+
"frozen-flask ~=1.0",
|
|
30
|
+
#"dramatiq-sqlite ~=0.1"
|
|
31
|
+
"gunicorn ~=22.0",
|
|
32
|
+
"honcho ~=1.1",
|
|
33
|
+
"html-sanitizer ~=2.4",
|
|
34
|
+
"htmx-flask ~=0.1",
|
|
35
|
+
"jinja2-fragments ~=1.3",
|
|
36
|
+
"jinja-layout ~=0.4",
|
|
37
|
+
"jinja-wtforms ~=0.2",
|
|
38
|
+
"periodiq ~=0.12",
|
|
39
|
+
"python-slugify ~=8.0.4"
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
Repository = "https://github.com/hyperflask/hyperflask"
|
|
44
|
+
|
|
45
|
+
[project.scripts]
|
|
46
|
+
hyperflask = "hyperflask.cli:main"
|
|
47
|
+
|
|
48
|
+
[dependency-groups]
|
|
49
|
+
dev = [
|
|
50
|
+
"pytest>=8.4.1",
|
|
51
|
+
"pytest-cov>=6.2.1",
|
|
52
|
+
"ruff>=0.12.4",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[tool.ruff]
|
|
56
|
+
line-length = 100
|
|
57
|
+
|
|
58
|
+
[build-system]
|
|
59
|
+
requires = ["uv_build>=0.8.11,<0.9.0"]
|
|
60
|
+
build-backend = "uv_build"
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
from flask import *
|
|
2
|
-
from .app import Hyperflask
|
|
2
|
+
from .app import Hyperflask
|
|
3
3
|
from .utils.htmx import htmx_redirect, htmx_oob
|
|
4
4
|
|
|
5
5
|
# useful exports from hyperflask managed extensions
|
|
6
|
-
from flask_babel import _, _p, _n, _np, lazy_gettext
|
|
6
|
+
from flask_babel import gettext, _, pgettext, _p, ngettext, _n, npgettext, _np, lazy_gettext, _lazy
|
|
7
7
|
from flask_file_routes import page
|
|
8
8
|
from flask_files import save_file, validate_file
|
|
9
9
|
from flask_mailman_templates import send_mail
|
|
10
|
+
from flask_mercure_sse import publish_signal
|
|
10
11
|
|
|
11
12
|
# useful exports from 3rd party libs
|
|
12
13
|
from htmx_flask import request, make_response
|
|
13
14
|
from jinja2_fragments.flask import render_block
|
|
14
|
-
from flask_apispec import use_args, use_kwargs, marshal_with
|
|
15
15
|
from slugify import slugify
|
|
16
|
+
from blinker import signal
|
|
@@ -29,7 +29,11 @@ from flask_debugtoolbar import DebugToolbarExtension
|
|
|
29
29
|
from .forms import Form
|
|
30
30
|
from .utils.page_actions import page_action_url
|
|
31
31
|
from .utils.htmx import htmx_oob
|
|
32
|
-
from .
|
|
32
|
+
from .utils.markdown import jinja_markdown, MarkdownExtension
|
|
33
|
+
from .utils.html import sanitize_html, nl2br
|
|
34
|
+
from .utils.models import File as SQLFileType
|
|
35
|
+
from .components import discover_components, register_components
|
|
36
|
+
from .components.jsx import ReactAdapter
|
|
33
37
|
from . import page_helpers
|
|
34
38
|
# others
|
|
35
39
|
from jinja_super_macros.registry import FileLoader
|
|
@@ -39,14 +43,11 @@ from periodiq import PeriodiqMiddleware
|
|
|
39
43
|
import os
|
|
40
44
|
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
map_jinja_call_node_to_func(
|
|
46
|
-
map_jinja_call_node_to_func(
|
|
47
|
-
map_jinja_call_node_to_func(_n)
|
|
48
|
-
map_jinja_call_node_to_func(_np)
|
|
49
|
-
map_jinja_call_node_to_func(lazy_gettext)
|
|
46
|
+
map_jinja_call_node_to_func(_, "_")
|
|
47
|
+
map_jinja_call_node_to_func(_p, "_p")
|
|
48
|
+
map_jinja_call_node_to_func(_n, "_n")
|
|
49
|
+
map_jinja_call_node_to_func(_np, "_np")
|
|
50
|
+
map_jinja_call_node_to_func(lazy_gettext, "lazy_gettext")
|
|
50
51
|
|
|
51
52
|
|
|
52
53
|
class Hyperflask(Flask):
|
|
@@ -54,10 +55,11 @@ class Hyperflask(Flask):
|
|
|
54
55
|
|
|
55
56
|
def __init__(self, *args, static_mode="hybrid", instrument=False, layouts_folder="layouts", partials_folder="partials",
|
|
56
57
|
emails_folder="emails", forms_folder="forms", assets_folder="assets", pages_folder="pages", migrations_folder="migrations",
|
|
57
|
-
config=None, config_filename="config.yml", **kwargs):
|
|
58
|
+
config=None, config_filename="config.yml", database_uri="sqlite://:memory:", proxy_fix=True, **kwargs):
|
|
58
59
|
|
|
59
60
|
super().__init__(*args, **kwargs)
|
|
60
|
-
|
|
61
|
+
if proxy_fix:
|
|
62
|
+
self.wsgi_app = ProxyFix(self.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1)
|
|
61
63
|
|
|
62
64
|
self.config.update({
|
|
63
65
|
"FREEZER_DESTINATION": os.path.join(self.root_path, "_site"),
|
|
@@ -66,12 +68,14 @@ class Hyperflask(Flask):
|
|
|
66
68
|
"OTEL_INSTRUMENT": instrument,
|
|
67
69
|
"DRAMATIQ_BROKER": "dramatiq.brokers.redis:RedisBroker",
|
|
68
70
|
"DEBUG_TB_INTERCEPT_REDIRECTS": False,
|
|
69
|
-
"PAGES_MARKDOWN_OPTIONS": {"extensions": ["fenced_code", "nl2br", "attr_list", "admonition", "codehilite"]},
|
|
70
71
|
# Hyperflask specific
|
|
71
|
-
"LAYOUT": "
|
|
72
|
+
"LAYOUT": "layouts/default.html",
|
|
72
73
|
"STATIC_MODE": static_mode,
|
|
73
74
|
"ASSETS_INCLUDE_HTMX": True,
|
|
74
|
-
"
|
|
75
|
+
"HTMX_EXT": ["hf-modal"],
|
|
76
|
+
"HTMX_BOOST_SITE": False,
|
|
77
|
+
"MARKDOWN_OPTIONS": {"extensions": ["fenced_code", "nl2br", "attr_list", "admonition", "codehilite"]},
|
|
78
|
+
"MARKDOWN_SANITIZER_CONFIG": {}
|
|
75
79
|
})
|
|
76
80
|
if config:
|
|
77
81
|
self.config.update(config)
|
|
@@ -80,10 +84,16 @@ class Hyperflask(Flask):
|
|
|
80
84
|
if self.debug:
|
|
81
85
|
self.config.setdefault("MAIL_BACKEND", "console")
|
|
82
86
|
|
|
87
|
+
self.config["PAGES_MARKDOWN_OPTIONS"] = self.config["MARKDOWN_OPTIONS"]
|
|
88
|
+
self.config["COLLECTIONS_MARKDOWN_OPTIONS"] = self.config["MARKDOWN_OPTIONS"]
|
|
89
|
+
self.config["MAIL_TEMPLATES_MARKDOWN_OPTIONS"] = self.config["MARKDOWN_OPTIONS"]
|
|
90
|
+
|
|
83
91
|
#self.otel = Observability(self)
|
|
84
92
|
|
|
85
93
|
self.jinja_env.add_extension(LayoutExtension)
|
|
86
94
|
self.jinja_env.add_extension(WtformExtension)
|
|
95
|
+
self.jinja_env.add_extension(MarkdownExtension)
|
|
96
|
+
self.jinja_env.filters.update(markdown=jinja_markdown, sanitize=sanitize_html, nl2br=nl2br)
|
|
87
97
|
self.jinja_env.form_base_cls = Form
|
|
88
98
|
self.jinja_env.default_layout = self.config["LAYOUT"]
|
|
89
99
|
self.forms = self.jinja_env.forms
|
|
@@ -91,11 +101,10 @@ class Hyperflask(Flask):
|
|
|
91
101
|
self.jinja_env.loader = ChoiceLoader([self.jinja_env.loader])
|
|
92
102
|
if layouts_folder and os.path.exists(os.path.join(self.root_path, layouts_folder)):
|
|
93
103
|
layout_loader = FileSystemLoader(os.path.join(self.root_path, layouts_folder))
|
|
94
|
-
self.jinja_env.loader.loaders.append(layout_loader)
|
|
95
104
|
self.jinja_env.loader.loaders.append(PrefixLoader({os.path.basename(layouts_folder): layout_loader}))
|
|
96
105
|
self.jinja_env.loader.loaders.extend([
|
|
97
|
-
FileLoader(os.path.join(os.path.dirname(__file__), "layouts/web.html"), "
|
|
98
|
-
FileLoader(os.path.join(os.path.dirname(__file__), "layouts/web.html"), "
|
|
106
|
+
FileLoader(os.path.join(os.path.dirname(__file__), "layouts/web.html"), "layouts/default.html"),
|
|
107
|
+
FileLoader(os.path.join(os.path.dirname(__file__), "layouts/web.html"), "layouts/base.html"),
|
|
99
108
|
PrefixLoader({"ui": FileSystemLoader(os.path.join(os.path.dirname(__file__), "ui"))})
|
|
100
109
|
])
|
|
101
110
|
|
|
@@ -110,16 +119,19 @@ class Hyperflask(Flask):
|
|
|
110
119
|
self.actor = self.dramatiq.actor
|
|
111
120
|
|
|
112
121
|
SuperMacros(self)
|
|
113
|
-
|
|
122
|
+
self.components = self.macros # alias
|
|
123
|
+
Babel(self, extract_locale_from_request="locale")
|
|
114
124
|
Geolocation(self)
|
|
115
125
|
Files(self)
|
|
116
126
|
MailTemplates(self, template_folder=emails_folder)
|
|
117
127
|
file_routes = FileRoutes(self, pages_folder=pages_folder, partials_folder=partials_folder)
|
|
118
128
|
self.page_helper = file_routes.page_helper
|
|
119
129
|
self.collections = Collections(self)
|
|
120
|
-
MercureSSE(self)
|
|
130
|
+
self.sse = MercureSSE(self)
|
|
121
131
|
|
|
122
|
-
self.assets = AssetsPipeline(self, assets_folder=assets_folder, inline=True, include_inline_on_demand=False
|
|
132
|
+
self.assets = AssetsPipeline(self, assets_folder=assets_folder, inline=True, include_inline_on_demand=False,
|
|
133
|
+
inline_template_exts=[".html", ".jpy"], tailwind_expand_env_vars=True,
|
|
134
|
+
tailwind_sources=[os.path.join(os.path.dirname(__file__), "ui")])
|
|
123
135
|
self.assets.state.watch_template_folders.extend([
|
|
124
136
|
os.path.join(self.root_path, "pages"),
|
|
125
137
|
os.path.join(self.root_path, "macros"),
|
|
@@ -130,24 +142,15 @@ class Hyperflask(Flask):
|
|
|
130
142
|
"assets": self.assets.state.assets_folder,
|
|
131
143
|
"@hyperflask": os.path.abspath(os.path.join(os.path.dirname(__file__), "static"))
|
|
132
144
|
})
|
|
133
|
-
self.assets.state.tailwind_suggested_content.extend(filter(bool, [
|
|
134
|
-
os.path.join(os.path.dirname(__file__), "ui") + "/**/*.html",
|
|
135
|
-
os.path.join(self.root_path, pages_folder) + "/**/*.html" if pages_folder else None,
|
|
136
|
-
os.path.join(self.root_path, pages_folder) + "/**/*.jpy" if pages_folder else None,
|
|
137
|
-
os.path.join(self.root_path, partials_folder) + "/**/*.html" if partials_folder else None,
|
|
138
|
-
os.path.join(self.root_path, partials_folder) + "/**/*.jpy" if partials_folder else None,
|
|
139
|
-
os.path.join(self.root_path, layouts_folder) + "/**/*.html" if layouts_folder else None,
|
|
140
|
-
os.path.join(self.root_path, "components") + "/**/*.html",
|
|
141
|
-
os.path.join(self.root_path, "components") + "/**/*.jpy",
|
|
142
|
-
]))
|
|
143
145
|
self.assets.state.copy_files_from_node_modules.update({
|
|
144
146
|
"bootstrap-icons/font": "bootstrap-icons"
|
|
145
147
|
})
|
|
146
148
|
self.assets.bundle(
|
|
147
|
-
{"@hyperflask": ["app.js"
|
|
149
|
+
{"@hyperflask": ["app.js"],
|
|
148
150
|
"@hyperflask/reactive": ["reactive.js"],
|
|
149
151
|
"@hyperflask/alpine": ["alpine.js"]},
|
|
150
|
-
|
|
152
|
+
from_package="hyperflask",
|
|
153
|
+
assets_folder="static"
|
|
151
154
|
)
|
|
152
155
|
self.assets.include("@hyperflask", 0)
|
|
153
156
|
|
|
@@ -155,14 +158,17 @@ class Hyperflask(Flask):
|
|
|
155
158
|
self.extensions['mail_templates'].jinja_env.default_layout = "layout.mjml"
|
|
156
159
|
self.extensions['mail_templates'].loaders.extend([
|
|
157
160
|
FileLoader(os.path.join(os.path.dirname(__file__), 'layouts/email.mjml'), 'layout.mjml'),
|
|
158
|
-
FileLoader(os.path.join(os.path.dirname(__file__), 'layouts/email.mjml'), '
|
|
161
|
+
FileLoader(os.path.join(os.path.dirname(__file__), 'layouts/email.mjml'), 'base_layout.mjml')
|
|
159
162
|
])
|
|
160
163
|
|
|
161
164
|
self.macros.register_from_directory(os.path.join(os.path.dirname(__file__), "ui"))
|
|
162
165
|
if hasattr(file_routes, "loader"):
|
|
163
166
|
self.forms.register_from_loader(file_routes.loader, "pages")
|
|
164
167
|
self.macros.create_from_func(htmx_oob, "HtmxOob", receive_caller=True, caller_alias="html")
|
|
165
|
-
|
|
168
|
+
|
|
169
|
+
self.components_loader, _ = register_components(self)
|
|
170
|
+
if self.components_loader:
|
|
171
|
+
self.forms.register_from_loader(self.components_loader)
|
|
166
172
|
|
|
167
173
|
if forms_folder and os.path.isdir(os.path.join(self.root_path, forms_folder)):
|
|
168
174
|
for macro in self.macros.create_from_directory(os.path.join(self.root_path, forms_folder)):
|
|
@@ -173,7 +179,11 @@ class Hyperflask(Flask):
|
|
|
173
179
|
self.collections.register_freezer_generator(self.freezer)
|
|
174
180
|
|
|
175
181
|
SQLTemplate.eval_globals.update(app=self)
|
|
176
|
-
db
|
|
182
|
+
self.db = FlaskSQLORM(self, database_uri=database_uri, migrations_folder=migrations_folder)
|
|
183
|
+
self.db.File = SQLFileType
|
|
184
|
+
|
|
185
|
+
def relative_import_name(self, name):
|
|
186
|
+
return f"{self.import_name}.{name}" if self.import_name != "__main__" else name
|
|
177
187
|
|
|
178
188
|
|
|
179
189
|
def static(func):
|
|
@@ -7,21 +7,21 @@ from importlib.metadata import entry_points
|
|
|
7
7
|
from .core import ComponentAdapter
|
|
8
8
|
from .alpine import AlpineAdapter
|
|
9
9
|
from .webcomponent import WebComponentAdapter
|
|
10
|
+
from .jsx import ReactAdapter
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
def
|
|
13
|
+
def discover_components(app, path=None, package_name=None):
|
|
13
14
|
if not path:
|
|
14
15
|
path = os.path.join(app.root_path, "components")
|
|
15
16
|
if not os.path.exists(path):
|
|
16
|
-
return
|
|
17
|
+
return None, []
|
|
17
18
|
if not package_name:
|
|
18
|
-
package_name = "components"
|
|
19
|
-
|
|
20
|
-
package_name = f"{app.import_name}.{package_name}"
|
|
19
|
+
package_name = app.relative_import_name("components")
|
|
20
|
+
|
|
21
21
|
|
|
22
|
-
url_prefix = "/__components/"
|
|
23
22
|
adapters = list(list_available_adapters())
|
|
24
23
|
force_adapters = app.config.get("COMPONENT_ADAPTERS", {})
|
|
24
|
+
components = []
|
|
25
25
|
|
|
26
26
|
loader = jinjapy.register_package(package_name, path, env=app.jinja_env)
|
|
27
27
|
for module_name, template in loader.list_files(module_with_package=False):
|
|
@@ -42,13 +42,22 @@ def register_components(app, path=None, package_name=None):
|
|
|
42
42
|
if adapter_class:
|
|
43
43
|
name = os.path.basename(template).split(".")[0].replace("-", "_")
|
|
44
44
|
adapter = adapter_class(name, f"{package_name}.{module_name}" if module_name else None, template)
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
components.append(adapter)
|
|
46
|
+
|
|
47
|
+
return loader, components
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def register_components(app, path=None, package_name=None, url_prefix="/__components/"):
|
|
51
|
+
loader, adapters = discover_components(app, path, package_name)
|
|
52
|
+
for adapter in adapters:
|
|
53
|
+
adapter.register(app, url_prefix)
|
|
54
|
+
return loader, adapters
|
|
47
55
|
|
|
48
56
|
|
|
49
57
|
def list_available_adapters():
|
|
50
58
|
yield AlpineAdapter
|
|
51
59
|
yield WebComponentAdapter
|
|
60
|
+
yield ReactAdapter
|
|
52
61
|
for entry in entry_points(group="hyperflask.component_adapters"):
|
|
53
62
|
yield entry.load()
|
|
54
63
|
yield ComponentAdapter
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .core import ComponentAdapter
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AlpineAdapter(ComponentAdapter):
|
|
5
|
+
@classmethod
|
|
6
|
+
def matches(cls, app, module_name, template):
|
|
7
|
+
if not ComponentAdapter.matches(app, module_name, template):
|
|
8
|
+
return False
|
|
9
|
+
tpl = app.jinja_env.loader.get_source(app.jinja_env, template)[0]
|
|
10
|
+
return any(tag in tpl for tag in ["x-data", "x-init"])
|
|
11
|
+
|
|
12
|
+
def register(self, app, url_prefix):
|
|
13
|
+
app.assets.include("@hyperflask/alpine")
|
|
14
|
+
return super().register(app, url_prefix)
|