hyperflask 0.1.6__tar.gz → 0.2.1__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.
Files changed (154) hide show
  1. hyperflask-0.1.6/README.md → hyperflask-0.2.1/PKG-INFO +45 -35
  2. hyperflask-0.1.6/PKG-INFO → hyperflask-0.2.1/README.md +7 -80
  3. hyperflask-0.2.1/pyproject.toml +65 -0
  4. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/__init__.py +4 -3
  5. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/app.py +45 -35
  6. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/cli.py +0 -1
  7. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/components/__init__.py +17 -8
  8. hyperflask-0.2.1/src/hyperflask/components/alpine.py +14 -0
  9. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/components/core.py +18 -5
  10. hyperflask-0.2.1/src/hyperflask/components/jsx.py +41 -0
  11. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/components/webcomponent.py +7 -6
  12. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/factory.py +13 -87
  13. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/forms/__init__.py +9 -2
  14. hyperflask-0.2.1/src/hyperflask/forms/fields.py +40 -0
  15. hyperflask-0.2.1/src/hyperflask/forms/widgets.py +36 -0
  16. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/layouts/email.mjml +1 -1
  17. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/layouts/web.html +6 -1
  18. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/reactivity.py +20 -14
  19. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/static/app.css +8 -0
  20. hyperflask-0.2.1/src/hyperflask/static/app.js +46 -0
  21. hyperflask-0.2.1/src/hyperflask/static/react.js +15 -0
  22. hyperflask-0.2.1/src/hyperflask/static/reactive.js +39 -0
  23. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Accordion.html +8 -0
  24. hyperflask-0.2.1/src/hyperflask/ui/daisyui/AccordionPanel.html +17 -0
  25. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Alert.html +36 -0
  26. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Avatar.html +16 -0
  27. hyperflask-0.2.1/src/hyperflask/ui/daisyui/AvatarGroup.html +8 -0
  28. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Badge.html +6 -0
  29. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Breadcrumbs.html +12 -0
  30. hyperflask-0.2.1/src/hyperflask/ui/daisyui/BreadcrumbsItem.html +6 -0
  31. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Button.html +6 -0
  32. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Card.html +22 -0
  33. hyperflask-0.2.1/src/hyperflask/ui/daisyui/CardActions.html +8 -0
  34. hyperflask-0.2.1/src/hyperflask/ui/daisyui/CardTitle.html +6 -0
  35. hyperflask-0.2.1/src/hyperflask/ui/daisyui/ChatBubble.html +30 -0
  36. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Checkbox.html +3 -0
  37. hyperflask-0.2.1/src/hyperflask/ui/daisyui/CollapsibleSubMenu.html +21 -0
  38. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Countdown.html +9 -0
  39. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Divider.html +6 -0
  40. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Drawer.html +10 -0
  41. hyperflask-0.2.1/src/hyperflask/ui/daisyui/DrawerContent.html +6 -0
  42. hyperflask-0.2.1/src/hyperflask/ui/daisyui/DrawerSide.html +11 -0
  43. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Dropdown.html +17 -0
  44. hyperflask-0.2.1/src/hyperflask/ui/daisyui/DropdownItem.html +8 -0
  45. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Fieldset.html +8 -0
  46. hyperflask-0.2.1/src/hyperflask/ui/daisyui/FieldsetLegend.html +6 -0
  47. hyperflask-0.2.1/src/hyperflask/ui/daisyui/FileInput.html +3 -0
  48. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Filter.html +10 -0
  49. hyperflask-0.2.1/src/hyperflask/ui/daisyui/FilterItem.html +3 -0
  50. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Footer.html +8 -0
  51. hyperflask-0.2.1/src/hyperflask/ui/daisyui/FooterLink.html +6 -0
  52. {hyperflask-0.1.6/hyperflask/ui/components/layout → hyperflask-0.2.1/src/hyperflask/ui/daisyui}/FooterNav.html +3 -2
  53. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Indicator.html +12 -0
  54. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Input.html +3 -0
  55. hyperflask-0.2.1/src/hyperflask/ui/daisyui/InputLabel.html +12 -0
  56. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Join.html +8 -0
  57. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Kbd.html +6 -0
  58. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Label.html +6 -0
  59. hyperflask-0.2.1/src/hyperflask/ui/daisyui/LabeledCheckbox.html +10 -0
  60. hyperflask-0.2.1/src/hyperflask/ui/daisyui/LabeledToggle.html +10 -0
  61. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Link.html +6 -0
  62. hyperflask-0.2.1/src/hyperflask/ui/daisyui/List.html +8 -0
  63. hyperflask-0.2.1/src/hyperflask/ui/daisyui/ListItem.html +8 -0
  64. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Loading.html +4 -0
  65. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Menu.html +12 -0
  66. hyperflask-0.2.1/src/hyperflask/ui/daisyui/MenuItem.html +8 -0
  67. hyperflask-0.2.1/src/hyperflask/ui/daisyui/MenuTitle.html +6 -0
  68. {hyperflask-0.1.6/hyperflask/ui/components/actions → hyperflask-0.2.1/src/hyperflask/ui/daisyui}/Modal.html +3 -3
  69. hyperflask-0.2.1/src/hyperflask/ui/daisyui/ModalAction.html +12 -0
  70. hyperflask-0.2.1/src/hyperflask/ui/daisyui/ModalTitle.html +6 -0
  71. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Navbar.html +36 -0
  72. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Pagination.html +6 -0
  73. hyperflask-0.2.1/src/hyperflask/ui/daisyui/PaginationNext.html +5 -0
  74. hyperflask-0.2.1/src/hyperflask/ui/daisyui/PaginationPage.html +6 -0
  75. hyperflask-0.2.1/src/hyperflask/ui/daisyui/PaginationPrev.html +5 -0
  76. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Progress.html +4 -0
  77. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Radio.html +3 -0
  78. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Range.html +3 -0
  79. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Rating.html +23 -0
  80. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Select.html +12 -0
  81. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Stack.html +8 -0
  82. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Stat.html +14 -0
  83. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Stats.html +6 -0
  84. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Step.html +6 -0
  85. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Steps.html +8 -0
  86. hyperflask-0.2.1/src/hyperflask/ui/daisyui/SubMenu.html +16 -0
  87. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Swap.html +10 -0
  88. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Tab.html +3 -0
  89. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Table.html +6 -0
  90. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Tabs.html +8 -0
  91. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Textarea.html +6 -0
  92. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Toast.html +8 -0
  93. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Toggle.html +3 -0
  94. hyperflask-0.2.1/src/hyperflask/ui/daisyui/Tooltip.html +8 -0
  95. hyperflask-0.2.1/src/hyperflask/ui/flash.html +8 -0
  96. hyperflask-0.2.1/src/hyperflask/ui/forms.html +35 -0
  97. hyperflask-0.2.1/src/hyperflask/ui/sse.html +6 -0
  98. hyperflask-0.2.1/src/hyperflask/utils/__init__.py +0 -0
  99. hyperflask-0.2.1/src/hyperflask/utils/html.py +13 -0
  100. hyperflask-0.2.1/src/hyperflask/utils/htmx.py +27 -0
  101. hyperflask-0.2.1/src/hyperflask/utils/markdown.py +32 -0
  102. hyperflask-0.2.1/src/hyperflask/utils/models.py +5 -0
  103. hyperflask-0.2.1/src/hyperflask/utils/s3.py +4 -0
  104. hyperflask-0.1.6/LICENSE +0 -19
  105. hyperflask-0.1.6/hyperflask/api.py +0 -57
  106. hyperflask-0.1.6/hyperflask/components/alpine.py +0 -16
  107. hyperflask-0.1.6/hyperflask/forms/fields.py +0 -17
  108. hyperflask-0.1.6/hyperflask/forms/widgets.py +0 -19
  109. hyperflask-0.1.6/hyperflask/resources.py +0 -149
  110. hyperflask-0.1.6/hyperflask/static/app.js +0 -5
  111. hyperflask-0.1.6/hyperflask/static/htmx.js +0 -5
  112. hyperflask-0.1.6/hyperflask/static/reactive.js +0 -5
  113. hyperflask-0.1.6/hyperflask/ui/components/actions/Button.html +0 -6
  114. hyperflask-0.1.6/hyperflask/ui/components/actions/Dropdown.html +0 -16
  115. hyperflask-0.1.6/hyperflask/ui/components/actions/DropdownItem.html +0 -8
  116. hyperflask-0.1.6/hyperflask/ui/components/actions/LinkButton.html +0 -6
  117. hyperflask-0.1.6/hyperflask/ui/components/actions/ModalAction.html +0 -12
  118. hyperflask-0.1.6/hyperflask/ui/components/actions/ModalTitle.html +0 -6
  119. hyperflask-0.1.6/hyperflask/ui/components/data-display/Accordion.html +0 -8
  120. hyperflask-0.1.6/hyperflask/ui/components/data-display/AccordionPanel.html +0 -18
  121. hyperflask-0.1.6/hyperflask/ui/components/data-input/Checkbox.html +0 -4
  122. hyperflask-0.1.6/hyperflask/ui/components/data-input/FileInput.html +0 -4
  123. hyperflask-0.1.6/hyperflask/ui/components/data-input/FormControl.html +0 -15
  124. hyperflask-0.1.6/hyperflask/ui/components/data-input/Input.html +0 -4
  125. hyperflask-0.1.6/hyperflask/ui/components/data-input/LabeledCheckbox.html +0 -11
  126. hyperflask-0.1.6/hyperflask/ui/components/data-input/LabeledTextInput.html +0 -11
  127. hyperflask-0.1.6/hyperflask/ui/components/data-input/Radiobox.html +0 -4
  128. hyperflask-0.1.6/hyperflask/ui/components/data-input/Range.html +0 -4
  129. hyperflask-0.1.6/hyperflask/ui/components/data-input/Rating.html +0 -20
  130. hyperflask-0.1.6/hyperflask/ui/components/data-input/Select.html +0 -11
  131. hyperflask-0.1.6/hyperflask/ui/components/data-input/Textarea.html +0 -6
  132. hyperflask-0.1.6/hyperflask/ui/components/data-input/Toggle.html +0 -4
  133. hyperflask-0.1.6/hyperflask/ui/components/feedback/Loading.html +0 -4
  134. hyperflask-0.1.6/hyperflask/ui/components/feedback/Toast.html +0 -8
  135. hyperflask-0.1.6/hyperflask/ui/components/layout/Footer.html +0 -8
  136. hyperflask-0.1.6/hyperflask/ui/components/layout/FooterLink.html +0 -6
  137. hyperflask-0.1.6/hyperflask/ui/components/layout/Indicator.html +0 -11
  138. hyperflask-0.1.6/hyperflask/ui/components/navigation/Link.html +0 -6
  139. hyperflask-0.1.6/hyperflask/ui/components/navigation/Navbar.html +0 -21
  140. hyperflask-0.1.6/hyperflask/ui/forms.html +0 -16
  141. hyperflask-0.1.6/hyperflask/utils/__init__.py +0 -5
  142. hyperflask-0.1.6/hyperflask/utils/htmx.py +0 -24
  143. hyperflask-0.1.6/pyproject.toml +0 -53
  144. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/__main__.py +0 -0
  145. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/page_helpers.py +0 -0
  146. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/static/alpine.js +0 -0
  147. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/static/stimulus.js +0 -0
  148. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/static/translations.js +0 -0
  149. {hyperflask-0.1.6/hyperflask/ui/components → hyperflask-0.2.1/src/hyperflask/ui/daisyui}/README.md +0 -0
  150. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/ui/icons.html +0 -0
  151. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/ui/modal.html +0 -0
  152. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/utils/page_actions.py +0 -0
  153. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/utils/request.py +0 -0
  154. {hyperflask-0.1.6 → hyperflask-0.2.1/src}/hyperflask/utils/tokens.py +0 -0
@@ -1,20 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: hyperflask
3
+ Version: 0.2.1
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.16
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~=23.0
26
+ Requires-Dist: honcho~=2.0
27
+ Requires-Dist: html-sanitizer~=2.6
28
+ Requires-Dist: htmx-flask~=0.1
29
+ Requires-Dist: jinja2-fragments~=1.9
30
+ Requires-Dist: jinja-layout~=0.4
31
+ Requires-Dist: jinja-wtforms~=0.2
32
+ Requires-Dist: periodiq~=0.13
33
+ Requires-Dist: python-slugify~=8.0.4
34
+ Requires-Dist: redis~=6.4
35
+ Requires-Python: >=3.10
36
+ Project-URL: Repository, https://github.com/hyperflask/hyperflask
37
+ Description-Content-Type: text/markdown
38
+
1
39
  <div><img src="https://raw.githubusercontent.com/hyperflask/hyperflask/main/assets/banner.svg" width="100%"></div>
2
40
  <hr>
3
41
  <div align="center">
4
42
 
5
43
  **Full stack Python web framework to build websites and web apps with as little boilerplate as possible**
6
44
 
7
- **⚠️ This is a work in progress project which is not functionnal yet ⚠️**
8
-
9
- ![Project Status](https://img.shields.io/badge/status-prototype-red) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/hyperflask/hyperflask/python.yml?branch=main)
10
-
11
45
  [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
46
 
13
47
  </div>
14
48
 
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).**
49
+ 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
50
 
19
51
  Features and technologies:
20
52
 
@@ -24,52 +56,32 @@ Features and technologies:
24
56
  - SQL focused ORM with [sqlorm](https://github.com/hyperflask/sqlorm), optimized for [sqlite](https://www.sqlite.org/)
25
57
  - Modern asset pipeline using [esbuild](https://esbuild.github.io/) and [tailwindcss](https://tailwindcss.com/)
26
58
  - 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.
59
+ - Easily create reusable backend and frontend components
60
+ - Build frontend components using Web Components, [Alpine.js](https://alpinejs.dev/), [React](https://react.dev) and more. Mix technologies at will.
29
61
  - 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
62
  - Authentication and user management with social logins and MFA
32
63
  - Static content collections to easily create blogs and manage static content
33
64
  - File management with built-in image manipulation and S3 integration
34
65
  - Template based emails with [mjml](https://mjml.io) support
35
- - Background tasks using [dramatiq](https://dramatiq.io/)
66
+ - Background tasks using [dramatiq](https://dramatiq.io/) with sqlite as the default broker
36
67
  - Push support for realtime pages using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
37
68
  - I18n using [gettext](https://www.gnu.org/software/gettext/)
38
- - Easily create REST APIs and automatically generate documentation
39
69
  - Static, hybrid or dynamic modes for content serving
40
- - Observable with [OpenTelemetry](https://opentelemetry.io/)
41
70
 
42
71
  [Hyperflask-Start](https://github.com/hyperflask/hyperflask-start) should be used to create new projects:
43
72
 
44
73
  - Dev environment based on [Development Containers](https://containers.dev/)
45
74
  - Optimized for VScode with breakpoint debugging for frontend and backend
46
75
  - [Mailpit](https://github.com/axllent/mailpit) for email testing
47
- - Deployments using [Hyperflask-Deploy](https://github.com/hyperflask/hyperflask-deploy)
76
+ - Deployments using [docker-web-deploy](https://github.com/hyperflask/docker-web-deploy)
48
77
 
49
78
  ## Project status
50
79
 
51
80
  **Hyperflask is being actively developed and is not yet ready to be used.**
52
81
 
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:
82
+ 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
83
 
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 | ✅ |
84
+ [Project status and roadmap](https://hyperflask.dev/roadmap)
73
85
 
74
86
  ## Flask extensions
75
87
 
@@ -79,7 +91,6 @@ A good part of these extensions is developed as part of the Hyperflask project.
79
91
 
80
92
  | Name | Description |
81
93
  | --- | --- |
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
94
  | [Flask-Assets-Pipeline](https://github.com/hyperflask/flask-assets-pipeline) | Modern asset pipeline using [esbuild](https://esbuild.github.io/)
84
95
  | [Flask-Babel-Hyper](https://github.com/hyperflask/flask-babel-hyper) | [Flask-Babel](https://github.com/python-babel/flask-babel) fork with additional utilities
85
96
  | [Flask-Collections](https://github.com/hyperflask/flask-collections) | Manage collections of static content
@@ -95,7 +106,6 @@ A good part of these extensions is developed as part of the Hyperflask project.
95
106
  | [Flask-Mailman](https://github.com/waynerv/flask-mailman) | Send emails |
96
107
  | [Flask-Mailman-Templates](https://github.com/hyperflask/flask-mailman-templates) | Email templates for [Flask-Mailman](https://github.com/waynerv/flask-mailman)
97
108
  | [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
109
  | [Flask-SQLORM](https://github.com/hyperflask/flask-sqlorm) | Flask integration of [sqlorm](https://github.com/hyperflask/sqlorm)
100
110
  | [Flask-Super-Macros](https://github.com/hyperflask/flask-super-macros) | Better macro management for Jinja
101
111
  | [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.6
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
- ![Project Status](https://img.shields.io/badge/status-prototype-red) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/hyperflask/hyperflask/python.yml?branch=main)
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 Python web framework where all the tech choices have been made. Hyperflask combines multiple Flask extensions and frontend libraries into a seamless experience.
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, compatible with [Storybook](https://storybook.js.org)f
72
- - Build frontend components using Web Components, [Alpine.js](https://alpinejs.dev/), [Stimulus](https://stimulus.hotwired.dev/) and more. Mix technologies at will.
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 [Hyperflask-Deploy](https://github.com/hyperflask/hyperflask-deploy)
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 Stack and their current development status on the [Hyperflask Github organization homepage](https://github.com/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
- Status overview:
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,65 @@
1
+ [project]
2
+ name = "hyperflask"
3
+ version = "0.2.1"
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.16",
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 ~=23.0",
32
+ "honcho ~=2.0",
33
+ "html-sanitizer ~=2.6",
34
+ "htmx-flask ~=0.1",
35
+ "jinja2-fragments ~=1.9",
36
+ "jinja-layout ~=0.4",
37
+ "jinja-wtforms ~=0.2",
38
+ "periodiq ~=0.13",
39
+ "python-slugify ~=8.0.4",
40
+ "redis ~=6.4"
41
+ ]
42
+
43
+ [tool.uv.sources]
44
+ flask-dramatiq = { git = "https://gitlab.com/bersace/flask-dramatiq" }
45
+ periodiq = { git = "https://gitlab.com/bersace/periodiq" }
46
+
47
+ [project.urls]
48
+ Repository = "https://github.com/hyperflask/hyperflask"
49
+
50
+ [project.scripts]
51
+ hyperflask = "hyperflask.cli:main"
52
+
53
+ [dependency-groups]
54
+ dev = [
55
+ "pytest>=8.4.1",
56
+ "pytest-cov>=6.2.1",
57
+ "ruff>=0.12.4",
58
+ ]
59
+
60
+ [tool.ruff]
61
+ line-length = 100
62
+
63
+ [build-system]
64
+ requires = ["uv_build>=0.8.11,<0.9.0"]
65
+ build-backend = "uv_build"
@@ -1,15 +1,16 @@
1
1
  from flask import *
2
- from .app import Hyperflask, db
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 .components import register_components
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
- db = FlaskSQLORM()
43
-
44
-
45
- map_jinja_call_node_to_func(_)
46
- map_jinja_call_node_to_func(_p)
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
- self.wsgi_app = ProxyFix(self.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1)
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": "layout.html",
72
+ "LAYOUT": "layouts/default.html",
72
73
  "STATIC_MODE": static_mode,
73
74
  "ASSETS_INCLUDE_HTMX": True,
74
- "HTMX_BOOST_SITE": False
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"), "layout.html"),
98
- FileLoader(os.path.join(os.path.dirname(__file__), "layouts/web.html"), "hyperflask_layout.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
- Babel(self)
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", "app.css"],
149
+ {"@hyperflask": ["app.js"],
148
150
  "@hyperflask/reactive": ["reactive.js"],
149
151
  "@hyperflask/alpine": ["alpine.js"]},
150
- assets_folder=os.path.join(os.path.dirname(__file__), "static")
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'), 'hyperflask_layout.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
- register_components(self)
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.init_app(self, migrations_folder=migrations_folder)
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):
@@ -14,7 +14,6 @@ def _create_app():
14
14
  try:
15
15
  return info.load_app()
16
16
  except NoAppException:
17
- raise
18
17
  return create_app()
19
18
 
20
19
 
@@ -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 register_components(app, path=None, package_name=None):
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
- if app.import_name != "__main__":
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
- adapter.register(app, url_prefix)
46
- app.macros.create_from_func(adapter.render, name, receive_caller=True)
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)