hyperflask 0.1.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.
Potentially problematic release.
This version of hyperflask might be problematic. Click here for more details.
- hyperflask-0.1.0/LICENSE +19 -0
- hyperflask-0.1.0/PKG-INFO +157 -0
- hyperflask-0.1.0/README.md +111 -0
- hyperflask-0.1.0/hyperflask/__init__.py +15 -0
- hyperflask-0.1.0/hyperflask/__main__.py +3 -0
- hyperflask-0.1.0/hyperflask/api.py +57 -0
- hyperflask-0.1.0/hyperflask/app.py +176 -0
- hyperflask-0.1.0/hyperflask/cli.py +140 -0
- hyperflask-0.1.0/hyperflask/components/__init__.py +54 -0
- hyperflask-0.1.0/hyperflask/components/alpine.py +16 -0
- hyperflask-0.1.0/hyperflask/components/core.py +60 -0
- hyperflask-0.1.0/hyperflask/components/webcomponent.py +23 -0
- hyperflask-0.1.0/hyperflask/factory.py +173 -0
- hyperflask-0.1.0/hyperflask/forms/__init__.py +51 -0
- hyperflask-0.1.0/hyperflask/forms/fields.py +17 -0
- hyperflask-0.1.0/hyperflask/forms/widgets.py +19 -0
- hyperflask-0.1.0/hyperflask/layout.html +28 -0
- hyperflask-0.1.0/hyperflask/page_helpers.py +36 -0
- hyperflask-0.1.0/hyperflask/reactivity.py +46 -0
- hyperflask-0.1.0/hyperflask/resources.py +149 -0
- hyperflask-0.1.0/hyperflask/static/alpine.js +5 -0
- hyperflask-0.1.0/hyperflask/static/app.js +5 -0
- hyperflask-0.1.0/hyperflask/static/htmx.js +5 -0
- hyperflask-0.1.0/hyperflask/static/reactive.js +5 -0
- hyperflask-0.1.0/hyperflask/static/stimulus.js +4 -0
- hyperflask-0.1.0/hyperflask/static/translations.js +55 -0
- hyperflask-0.1.0/hyperflask/ui/components/README.md +3 -0
- hyperflask-0.1.0/hyperflask/ui/components/actions/Button.html +6 -0
- hyperflask-0.1.0/hyperflask/ui/components/actions/Dropdown.html +16 -0
- hyperflask-0.1.0/hyperflask/ui/components/actions/DropdownItem.html +8 -0
- hyperflask-0.1.0/hyperflask/ui/components/actions/LinkButton.html +6 -0
- hyperflask-0.1.0/hyperflask/ui/components/actions/Modal.html +28 -0
- hyperflask-0.1.0/hyperflask/ui/components/actions/ModalAction.html +12 -0
- hyperflask-0.1.0/hyperflask/ui/components/actions/ModalTitle.html +6 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-display/Accordion.html +8 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-display/AccordionPanel.html +18 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-input/Checkbox.html +4 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-input/FileInput.html +4 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-input/FormControl.html +15 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-input/Input.html +4 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-input/LabeledCheckbox.html +11 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-input/LabeledTextInput.html +11 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-input/Radiobox.html +4 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-input/Range.html +4 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-input/Rating.html +20 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-input/Select.html +11 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-input/Textarea.html +6 -0
- hyperflask-0.1.0/hyperflask/ui/components/data-input/Toggle.html +4 -0
- hyperflask-0.1.0/hyperflask/ui/components/feedback/Loading.html +4 -0
- hyperflask-0.1.0/hyperflask/ui/components/feedback/Toast.html +8 -0
- hyperflask-0.1.0/hyperflask/ui/components/layout/Footer.html +8 -0
- hyperflask-0.1.0/hyperflask/ui/components/layout/FooterLink.html +6 -0
- hyperflask-0.1.0/hyperflask/ui/components/layout/FooterNav.html +11 -0
- hyperflask-0.1.0/hyperflask/ui/components/layout/Indicator.html +11 -0
- hyperflask-0.1.0/hyperflask/ui/components/navigation/Link.html +6 -0
- hyperflask-0.1.0/hyperflask/ui/components/navigation/Navbar.html +21 -0
- hyperflask-0.1.0/hyperflask/ui/forms.html +16 -0
- hyperflask-0.1.0/hyperflask/ui/icons.html +5 -0
- hyperflask-0.1.0/hyperflask/ui/modal.html +7 -0
- hyperflask-0.1.0/hyperflask/utils/__init__.py +5 -0
- hyperflask-0.1.0/hyperflask/utils/htmx.py +24 -0
- hyperflask-0.1.0/hyperflask/utils/page_actions.py +25 -0
- hyperflask-0.1.0/hyperflask/utils/request.py +25 -0
- hyperflask-0.1.0/hyperflask/utils/tokens.py +28 -0
- hyperflask-0.1.0/pyproject.toml +52 -0
hyperflask-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (C) 2024 Maxime Bouroumeau-Fuseau
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
5
|
+
the Software without restriction, including without limitation the rights to
|
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
|
8
|
+
so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: hyperflask
|
|
3
|
+
Version: 0.1.0
|
|
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: dramatiq-sqlite (>=0.1,<0.2)
|
|
16
|
+
Requires-Dist: flask (>=3.0,<4.0)
|
|
17
|
+
Requires-Dist: flask-apispec-hyper (>=0.12,<0.13)
|
|
18
|
+
Requires-Dist: flask-assets-pipeline (>=0.1,<0.2)
|
|
19
|
+
Requires-Dist: flask-babel-hyper (>=5.0,<6.0)
|
|
20
|
+
Requires-Dist: flask-collections (>=0.1,<0.2)
|
|
21
|
+
Requires-Dist: flask-configurator (>=0.1,<0.2)
|
|
22
|
+
Requires-Dist: flask-debugtoolbar (>=0.15,<0.16)
|
|
23
|
+
Requires-Dist: flask-dramatiq (>=0.6,<0.7)
|
|
24
|
+
Requires-Dist: flask-file-routes (>=0.1,<0.2)
|
|
25
|
+
Requires-Dist: flask-files (>=0.1,<0.2)
|
|
26
|
+
Requires-Dist: flask-geo (>=0.1,<0.2)
|
|
27
|
+
Requires-Dist: flask-mailman-templates (>=0.1,<0.2)
|
|
28
|
+
Requires-Dist: flask-mercure-sse (>=0.1,<0.2)
|
|
29
|
+
Requires-Dist: flask-sqlorm (>=0.1,<0.2)
|
|
30
|
+
Requires-Dist: flask-super-macros (>=0.1,<0.2)
|
|
31
|
+
Requires-Dist: flask-talisman (>=1.1,<2.0)
|
|
32
|
+
Requires-Dist: flask-wtf (>=1.2,<2.0)
|
|
33
|
+
Requires-Dist: frozen-flask (>=1.0,<2.0)
|
|
34
|
+
Requires-Dist: gunicorn (>=22.0,<23.0)
|
|
35
|
+
Requires-Dist: honcho (>=1.1,<2.0)
|
|
36
|
+
Requires-Dist: htmx-flask (>=0.1,<0.2)
|
|
37
|
+
Requires-Dist: jinja-layout (>=0.4,<0.5)
|
|
38
|
+
Requires-Dist: jinja-wtforms (>=0.1,<0.2)
|
|
39
|
+
Requires-Dist: jinja2-fragments (>=1.3,<2.0)
|
|
40
|
+
Requires-Dist: periodiq (>=0.12,<0.13)
|
|
41
|
+
Requires-Dist: python-slugify (>=8.0.4,<9.0.0)
|
|
42
|
+
Requires-Dist: redis (>=5.0,<6.0)
|
|
43
|
+
Project-URL: Repository, https://github.com/hyperflask/hyperflask
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
<div><img src="assets/banner.svg" width="100%"></div>
|
|
47
|
+
<hr>
|
|
48
|
+
<div align="center">
|
|
49
|
+
|
|
50
|
+
**Full stack Python web framework to build websites and web apps with as little boilerplate as possible**
|
|
51
|
+
|
|
52
|
+
**⚠️ This is a work in progress project which is not functionnal yet ⚠️**
|
|
53
|
+
|
|
54
|
+
 
|
|
55
|
+
|
|
56
|
+
[hyperflask.dev](https://hyperflask.dev) • [Get started](https://hyperflask.dev/getting-started) • [Docs](https://hyperflask.dev/guides) • [Example apps](https://github.com/hyperflask/examples)
|
|
57
|
+
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
A [Flask](https://flask.palletsprojects.com)-based (very) opiniated Python web framework where all the tech choices have been made. Hyperflask combines multiple Flask extensions and frontend libraries into a seamless experience.
|
|
61
|
+
|
|
62
|
+
**This project is part of the [Hyperflask Stack](https://hyperflask.dev).**
|
|
63
|
+
|
|
64
|
+
Features and technologies:
|
|
65
|
+
|
|
66
|
+
- Web framework built on top of [Flask](https://flask.palletsprojects.com) as a set of extensions
|
|
67
|
+
- File-based and/or app-based routing
|
|
68
|
+
- A new file format combining python code in frontmatter and html templates to define routes
|
|
69
|
+
- SQL focused ORM with [sqlorm](https://github.com/hyperflask/sqlorm), optimized for [sqlite](https://www.sqlite.org/)
|
|
70
|
+
- Modern asset pipeline using [esbuild](https://esbuild.github.io/) and [tailwindcss](https://tailwindcss.com/)
|
|
71
|
+
- Deep integration with [htmx](https://htmx.org/)
|
|
72
|
+
- Easily create reusable backend and frontend components, compatible with [Storybook](https://storybook.js.org)f
|
|
73
|
+
- Build frontend components using Web Components, [Alpine.js](https://alpinejs.dev/), [Stimulus](https://stimulus.hotwired.dev/) and more. Mix technologies at will.
|
|
74
|
+
- Component library based on [daisyUI](https://daisyui.com/) with icons from [Bootstrap Icons](https://icons.getbootstrap.com/)
|
|
75
|
+
- Seamless reactivity between frontend and backend
|
|
76
|
+
- Authentication and user management with social logins and MFA
|
|
77
|
+
- Static content collections to easily create blogs and manage static content
|
|
78
|
+
- File management with built-in image manipulation and S3 integration
|
|
79
|
+
- Template based emails with [mjml](https://mjml.io) support
|
|
80
|
+
- Background tasks using [dramatiq](https://dramatiq.io/)
|
|
81
|
+
- Push support for realtime pages using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
|
|
82
|
+
- I18n using [gettext](https://www.gnu.org/software/gettext/)
|
|
83
|
+
- Easily create REST APIs and automatically generate documentation
|
|
84
|
+
- Static, hybrid or dynamic modes for content serving
|
|
85
|
+
- Observable with [OpenTelemetry](https://opentelemetry.io/)
|
|
86
|
+
|
|
87
|
+
[Hyperflask-Start](https://github.com/hyperflask/hyperflask-start) should be used to create new projects:
|
|
88
|
+
|
|
89
|
+
- Dev environment based on [Development Containers](https://containers.dev/)
|
|
90
|
+
- Optimized for VScode with breakpoint debugging for frontend and backend
|
|
91
|
+
- [Mailpit](https://github.com/axllent/mailpit) for email testing
|
|
92
|
+
- Deployments using [Hyperflask-Deploy](https://github.com/hyperflask/hyperflask-deploy)
|
|
93
|
+
|
|
94
|
+
## Project status
|
|
95
|
+
|
|
96
|
+
**Hyperflask is being actively developed and is not yet ready to be used.**
|
|
97
|
+
|
|
98
|
+
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).
|
|
99
|
+
|
|
100
|
+
Status overview:
|
|
101
|
+
|
|
102
|
+
| Feature | Status |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| Core experience (start project, dev, deploy) | 🚧 |
|
|
105
|
+
| File based routing with mix code page format | ✅ |
|
|
106
|
+
| ORM | ✅ |
|
|
107
|
+
| Assets pipeline | ✅ |
|
|
108
|
+
| Component system + component library | 🚧 (component system almost done, need to create macros for daisyui) |
|
|
109
|
+
| SSE push | ✅ |
|
|
110
|
+
| Collections | 🚧 (finalizing) |
|
|
111
|
+
| Upload files | 🚧 (missing S3 improvements) |
|
|
112
|
+
| Emails | 🚧 |
|
|
113
|
+
| User management and auth | 🚧 |
|
|
114
|
+
| Static site generation | ❌ |
|
|
115
|
+
| I18n | 🚧 (finalizing) |
|
|
116
|
+
| PWA | ❌ |
|
|
117
|
+
| Runner | ✅ |
|
|
118
|
+
|
|
119
|
+
## Flask extensions
|
|
120
|
+
|
|
121
|
+
Hyperflask itself is minimal and mostly a collection of Flask extensions seamlessly integrated together.
|
|
122
|
+
|
|
123
|
+
A good part of these extensions is developed as part of the Hyperflask project. Checkout the [Hyperflask organization page](https://github.com/hyperflask) for a list of all these projects.
|
|
124
|
+
|
|
125
|
+
| Name | Description |
|
|
126
|
+
| --- | --- |
|
|
127
|
+
| [Flask-Apispec-Hyper](https://github.com/hyperflask/flask-apispec-hyper) | [Flask-Apispec](https://github.com/jmcarp/flask-apispec) fork with updates and fixes
|
|
128
|
+
| [Flask-Assets-Pipeline](https://github.com/hyperflask/flask-assets-pipeline) | Modern asset pipeline using [esbuild](https://esbuild.github.io/)
|
|
129
|
+
| [Flask-Babel-Hyper](https://github.com/hyperflask/flask-babel-hyper) | [Flask-Babel](https://github.com/python-babel/flask-babel) fork with additional utilities
|
|
130
|
+
| [Flask-Collections](https://github.com/hyperflask/flask-collections) | Manage collections of static content
|
|
131
|
+
| [Flask-Configurator](https://github.com/hyperflask/flask-configurator) | File based configuration
|
|
132
|
+
| [Flask-DebugToolbar](https://github.com/pallets-eco/flask-debugtoolbar) | Debug Toolbar
|
|
133
|
+
| [Flask-Dramatiq](https://flask-dramatiq.readthedocs.io) | Background tasks powered by [Dramatiq](https://dramatiq.io/) |
|
|
134
|
+
| [Flask-File-Routes](https://github.com/hyperflask/flask-file-routes) | File-based routing with a new file format combining python and jinja template in a single file
|
|
135
|
+
| [Flask-Files](https://github.com/hyperflask/flask-files) | [Fsspec](https://filesystem-spec.readthedocs.io/en/latest/) based files management (upload, storage and image manipulation)
|
|
136
|
+
| [Frozen-Flask](https://github.com/Frozen-Flask/Frozen) | Generate a static website from your Flask app |
|
|
137
|
+
| [Flask-Geo](https://github.com/hyperflask/flask-geo) | Geolocation using [Maxmind](https://www.maxmind.com/en/geoip-databases)
|
|
138
|
+
| [Htmx-Flask](https://github.com/sponsfreixes/htmx-flask) | HTMX integration for Flask |
|
|
139
|
+
| [Flask-Login](https://github.com/maxcountryman/flask-login) | User session management |
|
|
140
|
+
| [Flask-Mailman](https://github.com/waynerv/flask-mailman) | Send emails |
|
|
141
|
+
| [Flask-Mailman-Templates](https://github.com/hyperflask/flask-mailman-templates) | Email templates for [Flask-Mailman](https://github.com/waynerv/flask-mailman)
|
|
142
|
+
| [Flask-Mercure-SSE](https://github.com/hyperflask/flask-mercure-sse) | Push events via server-sent events using the [Mercure](https://mercure.rocks) protocol
|
|
143
|
+
| [Flask-Observability](https://github.com/hyperflask/flask-observability) | Observable Flask apps with [OpenTelemetry](https://opentelemetry.io/), logging and more
|
|
144
|
+
| [Flask-SQLORM](https://github.com/hyperflask/flask-sqlorm) | Flask integration of [sqlorm](https://github.com/hyperflask/sqlorm)
|
|
145
|
+
| [Flask-Super-Macros](https://github.com/hyperflask/flask-super-macros) | Better macro management for Jinja
|
|
146
|
+
| [Flask-Talisman](https://github.com/wntrblm/flask-talisman) | HTTP security headers for Flask
|
|
147
|
+
| [Flask-WTF](https://flask-wtf.readthedocs.io) | [WTForms](https://wtforms.readthedocs.io) integration
|
|
148
|
+
|
|
149
|
+
## Using without Hyperflask-Start
|
|
150
|
+
|
|
151
|
+
1. Create your project directory: `mkdir example-project && cd example-project`
|
|
152
|
+
2. Create and activate a virtualenv: `python -m venv .venv && source .venv/bin/activate`
|
|
153
|
+
3. `pip install hyperflask`
|
|
154
|
+
4. Create a pages directory: `mkdir pages`
|
|
155
|
+
5. Create your index page: `echo "hello world" > pages/index.html`
|
|
156
|
+
6. Start a development server using `hyperflask dev`
|
|
157
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<div><img src="assets/banner.svg" width="100%"></div>
|
|
2
|
+
<hr>
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
**Full stack Python web framework to build websites and web apps with as little boilerplate as possible**
|
|
6
|
+
|
|
7
|
+
**⚠️ This is a work in progress project which is not functionnal yet ⚠️**
|
|
8
|
+
|
|
9
|
+
 
|
|
10
|
+
|
|
11
|
+
[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
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
A [Flask](https://flask.palletsprojects.com)-based (very) opiniated Python web framework where all the tech choices have been made. Hyperflask combines multiple Flask extensions and frontend libraries into a seamless experience.
|
|
16
|
+
|
|
17
|
+
**This project is part of the [Hyperflask Stack](https://hyperflask.dev).**
|
|
18
|
+
|
|
19
|
+
Features and technologies:
|
|
20
|
+
|
|
21
|
+
- Web framework built on top of [Flask](https://flask.palletsprojects.com) as a set of extensions
|
|
22
|
+
- File-based and/or app-based routing
|
|
23
|
+
- A new file format combining python code in frontmatter and html templates to define routes
|
|
24
|
+
- SQL focused ORM with [sqlorm](https://github.com/hyperflask/sqlorm), optimized for [sqlite](https://www.sqlite.org/)
|
|
25
|
+
- Modern asset pipeline using [esbuild](https://esbuild.github.io/) and [tailwindcss](https://tailwindcss.com/)
|
|
26
|
+
- Deep integration with [htmx](https://htmx.org/)
|
|
27
|
+
- Easily create reusable backend and frontend components, compatible with [Storybook](https://storybook.js.org)f
|
|
28
|
+
- Build frontend components using Web Components, [Alpine.js](https://alpinejs.dev/), [Stimulus](https://stimulus.hotwired.dev/) and more. Mix technologies at will.
|
|
29
|
+
- 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
|
+
- Authentication and user management with social logins and MFA
|
|
32
|
+
- Static content collections to easily create blogs and manage static content
|
|
33
|
+
- File management with built-in image manipulation and S3 integration
|
|
34
|
+
- Template based emails with [mjml](https://mjml.io) support
|
|
35
|
+
- Background tasks using [dramatiq](https://dramatiq.io/)
|
|
36
|
+
- Push support for realtime pages using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
|
|
37
|
+
- I18n using [gettext](https://www.gnu.org/software/gettext/)
|
|
38
|
+
- Easily create REST APIs and automatically generate documentation
|
|
39
|
+
- Static, hybrid or dynamic modes for content serving
|
|
40
|
+
- Observable with [OpenTelemetry](https://opentelemetry.io/)
|
|
41
|
+
|
|
42
|
+
[Hyperflask-Start](https://github.com/hyperflask/hyperflask-start) should be used to create new projects:
|
|
43
|
+
|
|
44
|
+
- Dev environment based on [Development Containers](https://containers.dev/)
|
|
45
|
+
- Optimized for VScode with breakpoint debugging for frontend and backend
|
|
46
|
+
- [Mailpit](https://github.com/axllent/mailpit) for email testing
|
|
47
|
+
- Deployments using [Hyperflask-Deploy](https://github.com/hyperflask/hyperflask-deploy)
|
|
48
|
+
|
|
49
|
+
## Project status
|
|
50
|
+
|
|
51
|
+
**Hyperflask is being actively developed and is not yet ready to be used.**
|
|
52
|
+
|
|
53
|
+
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).
|
|
54
|
+
|
|
55
|
+
Status overview:
|
|
56
|
+
|
|
57
|
+
| Feature | Status |
|
|
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 | ✅ |
|
|
73
|
+
|
|
74
|
+
## Flask extensions
|
|
75
|
+
|
|
76
|
+
Hyperflask itself is minimal and mostly a collection of Flask extensions seamlessly integrated together.
|
|
77
|
+
|
|
78
|
+
A good part of these extensions is developed as part of the Hyperflask project. Checkout the [Hyperflask organization page](https://github.com/hyperflask) for a list of all these projects.
|
|
79
|
+
|
|
80
|
+
| Name | Description |
|
|
81
|
+
| --- | --- |
|
|
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
|
+
| [Flask-Assets-Pipeline](https://github.com/hyperflask/flask-assets-pipeline) | Modern asset pipeline using [esbuild](https://esbuild.github.io/)
|
|
84
|
+
| [Flask-Babel-Hyper](https://github.com/hyperflask/flask-babel-hyper) | [Flask-Babel](https://github.com/python-babel/flask-babel) fork with additional utilities
|
|
85
|
+
| [Flask-Collections](https://github.com/hyperflask/flask-collections) | Manage collections of static content
|
|
86
|
+
| [Flask-Configurator](https://github.com/hyperflask/flask-configurator) | File based configuration
|
|
87
|
+
| [Flask-DebugToolbar](https://github.com/pallets-eco/flask-debugtoolbar) | Debug Toolbar
|
|
88
|
+
| [Flask-Dramatiq](https://flask-dramatiq.readthedocs.io) | Background tasks powered by [Dramatiq](https://dramatiq.io/) |
|
|
89
|
+
| [Flask-File-Routes](https://github.com/hyperflask/flask-file-routes) | File-based routing with a new file format combining python and jinja template in a single file
|
|
90
|
+
| [Flask-Files](https://github.com/hyperflask/flask-files) | [Fsspec](https://filesystem-spec.readthedocs.io/en/latest/) based files management (upload, storage and image manipulation)
|
|
91
|
+
| [Frozen-Flask](https://github.com/Frozen-Flask/Frozen) | Generate a static website from your Flask app |
|
|
92
|
+
| [Flask-Geo](https://github.com/hyperflask/flask-geo) | Geolocation using [Maxmind](https://www.maxmind.com/en/geoip-databases)
|
|
93
|
+
| [Htmx-Flask](https://github.com/sponsfreixes/htmx-flask) | HTMX integration for Flask |
|
|
94
|
+
| [Flask-Login](https://github.com/maxcountryman/flask-login) | User session management |
|
|
95
|
+
| [Flask-Mailman](https://github.com/waynerv/flask-mailman) | Send emails |
|
|
96
|
+
| [Flask-Mailman-Templates](https://github.com/hyperflask/flask-mailman-templates) | Email templates for [Flask-Mailman](https://github.com/waynerv/flask-mailman)
|
|
97
|
+
| [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
|
+
| [Flask-SQLORM](https://github.com/hyperflask/flask-sqlorm) | Flask integration of [sqlorm](https://github.com/hyperflask/sqlorm)
|
|
100
|
+
| [Flask-Super-Macros](https://github.com/hyperflask/flask-super-macros) | Better macro management for Jinja
|
|
101
|
+
| [Flask-Talisman](https://github.com/wntrblm/flask-talisman) | HTTP security headers for Flask
|
|
102
|
+
| [Flask-WTF](https://flask-wtf.readthedocs.io) | [WTForms](https://wtforms.readthedocs.io) integration
|
|
103
|
+
|
|
104
|
+
## Using without Hyperflask-Start
|
|
105
|
+
|
|
106
|
+
1. Create your project directory: `mkdir example-project && cd example-project`
|
|
107
|
+
2. Create and activate a virtualenv: `python -m venv .venv && source .venv/bin/activate`
|
|
108
|
+
3. `pip install hyperflask`
|
|
109
|
+
4. Create a pages directory: `mkdir pages`
|
|
110
|
+
5. Create your index page: `echo "hello world" > pages/index.html`
|
|
111
|
+
6. Start a development server using `hyperflask dev`
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from flask import *
|
|
2
|
+
from .app import Hyperflask, db
|
|
3
|
+
from .utils.htmx import htmx_redirect, htmx_oob
|
|
4
|
+
|
|
5
|
+
# useful exports from hyperflask managed extensions
|
|
6
|
+
from flask_babel import _, _p, _n, _np, lazy_gettext
|
|
7
|
+
from flask_file_routes import page
|
|
8
|
+
from flask_files import save_file, validate_file
|
|
9
|
+
from flask_mailman_templates import send_mail
|
|
10
|
+
|
|
11
|
+
# useful exports from 3rd party libs
|
|
12
|
+
from htmx_flask import request, make_response
|
|
13
|
+
from jinja2_fragments.flask import render_block
|
|
14
|
+
from flask_apispec import use_args, use_kwargs, marshal_with
|
|
15
|
+
from slugify import slugify
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import flask_apispec
|
|
2
|
+
from flask_apispec.extension import FlaskApiSpec
|
|
3
|
+
from flask_apispec.annotations import activate
|
|
4
|
+
import functools
|
|
5
|
+
import inspect
|
|
6
|
+
from .resources import Resource
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Api:
|
|
10
|
+
def __init__(self, app, version="v1", **kwargs):
|
|
11
|
+
self.url_prefix = f"/api/{version}"
|
|
12
|
+
self.endpoint_prefix = f"api_{version}_"
|
|
13
|
+
kwargs.setdefault("url_prefix", self.url_prefix)
|
|
14
|
+
kwargs.setdefault("spec_url", "/spec.json")
|
|
15
|
+
kwargs.setdefault("doc_url", "/")
|
|
16
|
+
self.app = app
|
|
17
|
+
self.docs = FlaskApiSpec(app, version=version, **kwargs)
|
|
18
|
+
self.spec = self.docs.spec
|
|
19
|
+
|
|
20
|
+
def expose(self, rule, endpoint=None, **kwargs):
|
|
21
|
+
def decorator(target):
|
|
22
|
+
nonlocal endpoint
|
|
23
|
+
if inspect.isclass(target) and issubclass(target, Resource):
|
|
24
|
+
for e in target.register(self.app, self.url_prefix, self.endpoint_prefix + (endpoint or "")):
|
|
25
|
+
self.docs.register(self.app.view_functions[e], endpoint=e)
|
|
26
|
+
else:
|
|
27
|
+
view_func = create_view_func(target)
|
|
28
|
+
endpoint = self.endpoint_prefix + (endpoint or view_func.__name__)
|
|
29
|
+
self.app.add_url_rule(self.url_prefix + rule, endpoint, view_func, **kwargs)
|
|
30
|
+
self.docs.register(view_func, endpoint)
|
|
31
|
+
return target
|
|
32
|
+
return decorator
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def args(*args, **kwargs):
|
|
36
|
+
kwargs["activate"] = False
|
|
37
|
+
return flask_apispec.use_args(*args, **kwargs)
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def kwargs(*args, **kwargs):
|
|
41
|
+
kwargs["activate"] = False
|
|
42
|
+
return flask_apispec.use_kwargs(*args, **kwargs)
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def marshal_with(*args, **kwargs):
|
|
46
|
+
kwargs["activate"] = False
|
|
47
|
+
return flask_apispec.marshal_with(*args, **kwargs)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def create_view_func(func):
|
|
51
|
+
@functools.wraps(func)
|
|
52
|
+
def view_func(*args, **kwargs):
|
|
53
|
+
return func(*args, **kwargs)
|
|
54
|
+
if hasattr(func, "__apispec__"):
|
|
55
|
+
view_func.__apispec__ = func.__apispec__
|
|
56
|
+
func.view_func = activate(view_func)
|
|
57
|
+
return view_func
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# flask
|
|
2
|
+
from flask import Flask
|
|
3
|
+
from jinja2 import ChoiceLoader, FileSystemLoader, PrefixLoader
|
|
4
|
+
# hyperflask extensions
|
|
5
|
+
from jinja_layout import LayoutExtension
|
|
6
|
+
from jinja_wtforms import WtformExtension
|
|
7
|
+
from flask_assets_pipeline import AssetsPipeline
|
|
8
|
+
from flask_super_macros import SuperMacros
|
|
9
|
+
from flask_collections import Collections
|
|
10
|
+
from flask_file_routes import FileRoutes
|
|
11
|
+
from flask_configurator import Config
|
|
12
|
+
from flask_babel import Babel, _, _p, _n, _np, lazy_gettext
|
|
13
|
+
from flask_geo import Geolocation
|
|
14
|
+
from flask_files import Files
|
|
15
|
+
from flask_sqlorm import FlaskSQLORM
|
|
16
|
+
from flask_mercure_sse import MercureSSE
|
|
17
|
+
from flask_mailman_templates import MailTemplates
|
|
18
|
+
from flask_observability import Observability
|
|
19
|
+
# 3rd party extensions
|
|
20
|
+
from flask_wtf.csrf import CSRFProtect
|
|
21
|
+
from flask_talisman import Talisman
|
|
22
|
+
from flask_frozen import Freezer
|
|
23
|
+
from htmx_flask import Htmx
|
|
24
|
+
from flask_mailman import Mail
|
|
25
|
+
from flask_dramatiq import Dramatiq
|
|
26
|
+
from flask_debugtoolbar import DebugToolbarExtension
|
|
27
|
+
# from hyperflask
|
|
28
|
+
from .forms import Form
|
|
29
|
+
from .utils.page_actions import page_action_url
|
|
30
|
+
from .utils.htmx import htmx_oob
|
|
31
|
+
from .components import register_components
|
|
32
|
+
from . import page_helpers
|
|
33
|
+
# others
|
|
34
|
+
from jinja_super_macros.registry import FileLoader
|
|
35
|
+
from jinja_wtforms.extractor import map_jinja_call_node_to_func
|
|
36
|
+
from sqlorm.sql_template import SQLTemplate
|
|
37
|
+
from periodiq import PeriodiqMiddleware
|
|
38
|
+
import os
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
db = FlaskSQLORM()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
map_jinja_call_node_to_func(_)
|
|
45
|
+
map_jinja_call_node_to_func(_p)
|
|
46
|
+
map_jinja_call_node_to_func(_n)
|
|
47
|
+
map_jinja_call_node_to_func(_np)
|
|
48
|
+
map_jinja_call_node_to_func(lazy_gettext)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class Hyperflask(Flask):
|
|
52
|
+
config_class = Config
|
|
53
|
+
|
|
54
|
+
def __init__(self, *args, static_mode="hybrid", instrument=False, layouts_folder="layouts", partials_folder="partials",
|
|
55
|
+
emails_folder="emails", forms_folder="forms", assets_folder="assets", pages_folder="pages", migrations_folder="migrations",
|
|
56
|
+
config=None, config_filename="config.yml", **kwargs):
|
|
57
|
+
super().__init__(*args, **kwargs)
|
|
58
|
+
|
|
59
|
+
self.config.update({
|
|
60
|
+
"FREEZER_DESTINATION": os.path.join(self.root_path, "_site"),
|
|
61
|
+
"FREEZER_STATIC_IGNORE": [],
|
|
62
|
+
"WTF_CSRF_CHECK_DEFAULT": False,
|
|
63
|
+
"OTEL_INSTRUMENT": instrument,
|
|
64
|
+
"DRAMATIQ_BROKER": "dramatiq.brokers.redis:RedisBroker",
|
|
65
|
+
"DEBUG_TB_INTERCEPT_REDIRECTS": False,
|
|
66
|
+
"PAGES_MARKDOWN_OPTIONS": {"extensions": ["fenced_code", "nl2br", "attr_list", "admonition", "codehilite"]},
|
|
67
|
+
# Hyperflask specific
|
|
68
|
+
"LAYOUT": "layout.html",
|
|
69
|
+
"STATIC_MODE": static_mode,
|
|
70
|
+
"ASSETS_INCLUDE_HTMX": True,
|
|
71
|
+
"HTMX_BOOST_SITE": False
|
|
72
|
+
})
|
|
73
|
+
if config:
|
|
74
|
+
self.config.update(config)
|
|
75
|
+
if config_filename:
|
|
76
|
+
self.config.load(config_filename)
|
|
77
|
+
if self.debug:
|
|
78
|
+
self.config.setdefault("MAIL_BACKEND", "console")
|
|
79
|
+
|
|
80
|
+
self.otel = Observability(self)
|
|
81
|
+
|
|
82
|
+
self.jinja_env.add_extension(LayoutExtension)
|
|
83
|
+
self.jinja_env.add_extension(WtformExtension)
|
|
84
|
+
self.jinja_env.form_base_cls = Form
|
|
85
|
+
self.jinja_env.default_layout = self.config["LAYOUT"]
|
|
86
|
+
self.forms = self.jinja_env.forms
|
|
87
|
+
|
|
88
|
+
self.jinja_env.loader = ChoiceLoader([self.jinja_env.loader])
|
|
89
|
+
if layouts_folder and os.path.exists(os.path.join(self.root_path, layouts_folder)):
|
|
90
|
+
layout_loader = FileSystemLoader(os.path.join(self.root_path, layouts_folder))
|
|
91
|
+
self.jinja_env.loader.loaders.append(layout_loader)
|
|
92
|
+
self.jinja_env.loader.loaders.append(PrefixLoader({os.path.basename(layouts_folder): layout_loader}))
|
|
93
|
+
self.jinja_env.loader.loaders.extend([
|
|
94
|
+
FileLoader(os.path.join(os.path.dirname(__file__), "layout.html")),
|
|
95
|
+
FileLoader(os.path.join(os.path.dirname(__file__), "layout.html"), "hyperflask_layout.html"),
|
|
96
|
+
PrefixLoader({"ui": FileSystemLoader(os.path.join(os.path.dirname(__file__), "ui"))})
|
|
97
|
+
])
|
|
98
|
+
|
|
99
|
+
DebugToolbarExtension(self)
|
|
100
|
+
self.freezer = Freezer(self)
|
|
101
|
+
self.csrf = CSRFProtect(self)
|
|
102
|
+
#self.talisman = Talisman(self)
|
|
103
|
+
Htmx(self)
|
|
104
|
+
Mail(self)
|
|
105
|
+
self.dramatiq = Dramatiq(self)
|
|
106
|
+
self.dramatiq.broker.add_middleware(PeriodiqMiddleware())
|
|
107
|
+
self.actor = self.dramatiq.actor
|
|
108
|
+
|
|
109
|
+
SuperMacros(self)
|
|
110
|
+
Babel(self)
|
|
111
|
+
Geolocation(self)
|
|
112
|
+
Files(self)
|
|
113
|
+
MailTemplates(self, template_folder=emails_folder)
|
|
114
|
+
file_routes = FileRoutes(self, pages_folder=pages_folder, partials_folder=partials_folder)
|
|
115
|
+
self.page_helper = file_routes.page_helper
|
|
116
|
+
self.collections = Collections(self)
|
|
117
|
+
MercureSSE(self)
|
|
118
|
+
|
|
119
|
+
self.assets = AssetsPipeline(self, assets_folder=assets_folder, inline=True, include_inline_on_demand=False)
|
|
120
|
+
self.assets.state.watch_template_folders.extend([
|
|
121
|
+
os.path.join(self.root_path, "pages"),
|
|
122
|
+
os.path.join(self.root_path, "macros"),
|
|
123
|
+
os.path.join(self.root_path, "components"),
|
|
124
|
+
os.path.join(self.root_path, "forms")
|
|
125
|
+
])
|
|
126
|
+
self.assets.state.esbuild_aliases.update({
|
|
127
|
+
"assets": self.assets.state.assets_folder,
|
|
128
|
+
"@hyperflask": os.path.abspath(os.path.join(os.path.dirname(__file__), "static"))
|
|
129
|
+
})
|
|
130
|
+
self.assets.state.tailwind_suggested_content.extend(filter(bool, [
|
|
131
|
+
os.path.join(os.path.dirname(__file__), "ui") + "/**/*.html",
|
|
132
|
+
os.path.join(self.root_path, pages_folder) + "/**/*.html" if pages_folder else None,
|
|
133
|
+
os.path.join(self.root_path, pages_folder) + "/**/*.jpy" if pages_folder else None,
|
|
134
|
+
os.path.join(self.root_path, partials_folder) + "/**/*.html" if partials_folder else None,
|
|
135
|
+
os.path.join(self.root_path, partials_folder) + "/**/*.jpy" if partials_folder else None,
|
|
136
|
+
os.path.join(self.root_path, layouts_folder) + "/**/*.html" if layouts_folder else None,
|
|
137
|
+
os.path.join(self.root_path, "components") + "/**/*.html",
|
|
138
|
+
os.path.join(self.root_path, "components") + "/**/*.jpy",
|
|
139
|
+
]))
|
|
140
|
+
self.assets.state.copy_files_from_node_modules.update({
|
|
141
|
+
"bootstrap-icons/font": "bootstrap-icons"
|
|
142
|
+
})
|
|
143
|
+
self.assets.bundle(
|
|
144
|
+
{"@hyperflask": ["app.js"],
|
|
145
|
+
"@hyperflask/reactive": ["reactive.js"],
|
|
146
|
+
"@hyperflask/alpine": ["alpine.js"]},
|
|
147
|
+
assets_folder=os.path.join(os.path.dirname(__file__), "static")
|
|
148
|
+
)
|
|
149
|
+
self.assets.include("@hyperflask", 0)
|
|
150
|
+
|
|
151
|
+
self.macros.register_from_directory(os.path.join(os.path.dirname(__file__), "ui"))
|
|
152
|
+
if hasattr(file_routes, "loader"):
|
|
153
|
+
self.forms.register_from_loader(file_routes.loader, "pages")
|
|
154
|
+
self.macros.create_from_func(htmx_oob, "HtmxOob", receive_caller=True, caller_alias="html")
|
|
155
|
+
register_components(self)
|
|
156
|
+
|
|
157
|
+
if forms_folder and os.path.isdir(os.path.join(self.root_path, forms_folder)):
|
|
158
|
+
for macro in self.macros.create_from_directory(os.path.join(self.root_path, forms_folder)):
|
|
159
|
+
self.forms.register(self.macros.resolve_template(macro), macro)
|
|
160
|
+
|
|
161
|
+
self.jinja_env.globals.update(page_action_url=page_action_url)
|
|
162
|
+
|
|
163
|
+
self.collections.register_freezer_generator(self.freezer)
|
|
164
|
+
|
|
165
|
+
SQLTemplate.eval_globals.update(app=self)
|
|
166
|
+
db.init_app(self, migrations_folder=migrations_folder)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def static(func):
|
|
170
|
+
pass
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def dynamic(func=None, static_template=None):
|
|
174
|
+
def decorator(func):
|
|
175
|
+
pass
|
|
176
|
+
return decorator(func) if func else decorator
|