hyperflask 0.1.0__py3-none-any.whl

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.

Files changed (66) hide show
  1. hyperflask/__init__.py +15 -0
  2. hyperflask/__main__.py +3 -0
  3. hyperflask/api.py +57 -0
  4. hyperflask/app.py +176 -0
  5. hyperflask/cli.py +140 -0
  6. hyperflask/components/__init__.py +54 -0
  7. hyperflask/components/alpine.py +16 -0
  8. hyperflask/components/core.py +60 -0
  9. hyperflask/components/webcomponent.py +23 -0
  10. hyperflask/factory.py +173 -0
  11. hyperflask/forms/__init__.py +51 -0
  12. hyperflask/forms/fields.py +17 -0
  13. hyperflask/forms/widgets.py +19 -0
  14. hyperflask/layout.html +28 -0
  15. hyperflask/page_helpers.py +36 -0
  16. hyperflask/reactivity.py +46 -0
  17. hyperflask/resources.py +149 -0
  18. hyperflask/static/alpine.js +5 -0
  19. hyperflask/static/app.js +5 -0
  20. hyperflask/static/htmx.js +5 -0
  21. hyperflask/static/reactive.js +5 -0
  22. hyperflask/static/stimulus.js +4 -0
  23. hyperflask/static/translations.js +55 -0
  24. hyperflask/ui/components/README.md +3 -0
  25. hyperflask/ui/components/actions/Button.html +6 -0
  26. hyperflask/ui/components/actions/Dropdown.html +16 -0
  27. hyperflask/ui/components/actions/DropdownItem.html +8 -0
  28. hyperflask/ui/components/actions/LinkButton.html +6 -0
  29. hyperflask/ui/components/actions/Modal.html +28 -0
  30. hyperflask/ui/components/actions/ModalAction.html +12 -0
  31. hyperflask/ui/components/actions/ModalTitle.html +6 -0
  32. hyperflask/ui/components/data-display/Accordion.html +8 -0
  33. hyperflask/ui/components/data-display/AccordionPanel.html +18 -0
  34. hyperflask/ui/components/data-input/Checkbox.html +4 -0
  35. hyperflask/ui/components/data-input/FileInput.html +4 -0
  36. hyperflask/ui/components/data-input/FormControl.html +15 -0
  37. hyperflask/ui/components/data-input/Input.html +4 -0
  38. hyperflask/ui/components/data-input/LabeledCheckbox.html +11 -0
  39. hyperflask/ui/components/data-input/LabeledTextInput.html +11 -0
  40. hyperflask/ui/components/data-input/Radiobox.html +4 -0
  41. hyperflask/ui/components/data-input/Range.html +4 -0
  42. hyperflask/ui/components/data-input/Rating.html +20 -0
  43. hyperflask/ui/components/data-input/Select.html +11 -0
  44. hyperflask/ui/components/data-input/Textarea.html +6 -0
  45. hyperflask/ui/components/data-input/Toggle.html +4 -0
  46. hyperflask/ui/components/feedback/Loading.html +4 -0
  47. hyperflask/ui/components/feedback/Toast.html +8 -0
  48. hyperflask/ui/components/layout/Footer.html +8 -0
  49. hyperflask/ui/components/layout/FooterLink.html +6 -0
  50. hyperflask/ui/components/layout/FooterNav.html +11 -0
  51. hyperflask/ui/components/layout/Indicator.html +11 -0
  52. hyperflask/ui/components/navigation/Link.html +6 -0
  53. hyperflask/ui/components/navigation/Navbar.html +21 -0
  54. hyperflask/ui/forms.html +16 -0
  55. hyperflask/ui/icons.html +5 -0
  56. hyperflask/ui/modal.html +7 -0
  57. hyperflask/utils/__init__.py +5 -0
  58. hyperflask/utils/htmx.py +24 -0
  59. hyperflask/utils/page_actions.py +25 -0
  60. hyperflask/utils/request.py +25 -0
  61. hyperflask/utils/tokens.py +28 -0
  62. hyperflask-0.1.0.dist-info/LICENSE +19 -0
  63. hyperflask-0.1.0.dist-info/METADATA +157 -0
  64. hyperflask-0.1.0.dist-info/RECORD +66 -0
  65. hyperflask-0.1.0.dist-info/WHEEL +4 -0
  66. hyperflask-0.1.0.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,28 @@
1
+ {% macro Modal(close_btn=None, open=None, position=None, responsive=True, width=None, large=None, no_blur=None) -%}
2
+ <dialog class="modal {{kwargs.pop('class', '')}} {% if close_btn %} {% endif %} {% if open %} modal-open{% endif %} {% if position %} modal-{{position}}{% endif %} {% if responsive %} modal-bottom sm:modal-middle{% endif %}" {{ html_attrs(kwargs) }}>
3
+
4
+ <div class="modal-box {% if width %} {{width}}{% endif %} {% if large %} w-11/12 max-w-full{% endif %}">
5
+
6
+ {% if not close_btn %}{% else %}<form method="dialog">
7
+
8
+ <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">
9
+ ✕
10
+ </button>
11
+
12
+ </form>{% endif %}
13
+
14
+ {{ caller() }}
15
+
16
+
17
+ </div>
18
+
19
+ {% if no_blur %}{% else %}<form method="dialog" class="modal-backdrop">
20
+
21
+ <button >
22
+ close
23
+ </button>
24
+
25
+ </form>{% endif %}
26
+
27
+ </dialog>
28
+ {%- endmacro %}
@@ -0,0 +1,12 @@
1
+ {% macro ModalAction() -%}
2
+ <div class="modal-action">
3
+
4
+ <form method="dialog">
5
+
6
+ {{ caller() }}
7
+
8
+
9
+ </form>
10
+
11
+ </div>
12
+ {%- endmacro %}
@@ -0,0 +1,6 @@
1
+ {% macro ModalTitle() -%}
2
+ <h3 class="text-lg font-bold mb-4">
3
+ {{ caller() }}
4
+
5
+ </h3>
6
+ {%- endmacro %}
@@ -0,0 +1,8 @@
1
+ {% macro Accordion() -%}
2
+ <div class="join join-vertical w-full">
3
+
4
+ {{ caller() }}
5
+
6
+
7
+ </div>
8
+ {%- endmacro %}
@@ -0,0 +1,18 @@
1
+ {% macro AccordionPanel(title=None, open=None, toggle_icon=None) -%}
2
+ <div class="collapse bg-base-200 {% if toggle_icon %} collapse-{{toggle_icon}}{% endif %}">
3
+
4
+ <input type="radio" name="my-accordion-1" {% if open %}checked="checked"{% endif %}>
5
+ </input>
6
+
7
+ <div class="collapse-title text-xl font-medium">
8
+ {{title}}
9
+
10
+ </div>
11
+
12
+ <div class="collapse-content">
13
+ {{ caller() }}
14
+
15
+ </div>
16
+
17
+ </div>
18
+ {%- endmacro %}
@@ -0,0 +1,4 @@
1
+ {% macro Checkbox(style=None, size=None) -%}
2
+ <input type="checkbox" class="checkbox {{kwargs.pop('class', '')}} {% if style %} checkbox-{{style}}{% endif %} {% if size %} checkbox-{{size}}{% endif %}" {{ html_attrs(kwargs) }}>
3
+ </input>
4
+ {%- endmacro %}
@@ -0,0 +1,4 @@
1
+ {% macro FileInput(bordered=None, style=None, size=None) -%}
2
+ <input type="file" class="file-input w-full max-w-xs {{kwargs.pop('class', '')}} {% if bordered %} file-input-bordered{% endif %} {% if style %} file-input-{{style}}{% endif %} {% if size %} file-input-{{size}}{% endif %}" {{ html_attrs(kwargs) }}>
3
+ </input>
4
+ {%- endmacro %}
@@ -0,0 +1,15 @@
1
+ {% macro FormControl(label=None) -%}
2
+ <div class="form-control w-full {{kwargs.pop('class', '')}}" {{ html_attrs(kwargs) }}>
3
+
4
+ <div class="label">
5
+
6
+ <span class="label-text">{% if label %}{{label}}{% else %}
7
+ {% endif %}</span>
8
+
9
+ </div>
10
+
11
+ {{ caller() }}
12
+
13
+
14
+ </div>
15
+ {%- endmacro %}
@@ -0,0 +1,4 @@
1
+ {% macro Input(bordered=True, ghost=None, style=None, size=None, type="text") -%}
2
+ <input class="input w-full {{kwargs.pop('class', '')}} {% if bordered %} input-bordered{% endif %} {% if ghost %} input-ghost{% endif %} {% if style %} input-{{style}}{% endif %} {% if size %} input-{{size}}{% endif %}" {% if type %}type="{{type}}"{% endif %} {{ html_attrs(kwargs) }}>
3
+ </input>
4
+ {%- endmacro %}
@@ -0,0 +1,11 @@
1
+ {% macro LabeledCheckbox(label, style=None, size=None) -%}
2
+ <label class="label cursor-pointer justify-start gap-2 {{kwargs.pop('class', '')}} {% if style %} checkbox-{{style}}{% endif %} {% if size %} checkbox-{{size}}{% endif %}" {{ html_attrs(kwargs) }}>
3
+
4
+ <input type="checkbox" class="checkbox">
5
+ </input>
6
+
7
+ <span class="label-text">{{label}}
8
+ </span>
9
+
10
+ </label>
11
+ {%- endmacro %}
@@ -0,0 +1,11 @@
1
+ {% macro LabeledTextInput(slot, bordered=True, ghost=None, style=None, size=None, type="text") -%}
2
+ <label class="input flex items-center gap-2 {% if bordered %} input-bordered{% endif %} {% if ghost %} input-ghost{% endif %} {% if style %} input-{{style}}{% endif %} {% if size %} input-{{size}}{% endif %}">
3
+
4
+ {{slot}}
5
+
6
+
7
+ <input {% if type %}{{type}}{% else %} text{% endif %} class="grow {{kwargs.pop('class', '')}}" {{ html_attrs(kwargs) }}>
8
+ </input>
9
+
10
+ </label>
11
+ {%- endmacro %}
@@ -0,0 +1,4 @@
1
+ {% macro Radiobox(style=None, size=None) -%}
2
+ <input type="radio" class="radio {{kwargs.pop('class', '')}} {% if style %} radio-{{style}}{% endif %} {% if size %} radio-{{size}}{% endif %}" {{ html_attrs(kwargs) }}>
3
+ </input>
4
+ {%- endmacro %}
@@ -0,0 +1,4 @@
1
+ {% macro Range(style=None, size=None) -%}
2
+ <input type="range" class="range {{kwargs.pop('class', '')}} {% if style %} range-{{style}}{% endif %} {% if size %} range-{{size}}{% endif %}" {{ html_attrs(kwargs) }}>
3
+ </input>
4
+ {%- endmacro %}
@@ -0,0 +1,20 @@
1
+ {% macro Rating(name=None, rating=None, mask="star", size=None) -%}
2
+ <div class="rating {% if size %} rating-{{size}}{% endif %}">
3
+
4
+ <input type="radio" class="mask {% if mask %} mask-{{mask}}{% endif %}" value="1" {% if name %}name="{{name}}"{% endif %} {% if rating > 0 %}checked="checked"{% endif %}>
5
+ </input>
6
+
7
+ <input type="radio" class="mask {% if mask %} mask-{{mask}}{% endif %}" value="2" {% if name %}name="{{name}}"{% endif %} {% if rating > 1 %}checked="checked"{% endif %}>
8
+ </input>
9
+
10
+ <input type="radio" class="mask {% if mask %} mask-{{mask}}{% endif %}" value="3" {% if name %}name="{{name}}"{% endif %} {% if rating > 2 %}checked="checked"{% endif %}>
11
+ </input>
12
+
13
+ <input type="radio" class="mask {% if mask %} mask-{{mask}}{% endif %}" value="4" {% if name %}name="{{name}}"{% endif %} {% if rating > 3 %}checked="checked"{% endif %}>
14
+ </input>
15
+
16
+ <input type="radio" class="mask {% if mask %} mask-{{mask}}{% endif %}" value="5" {% if name %}name="{{name}}"{% endif %} {% if rating > 4 %}checked="checked"{% endif %}>
17
+ </input>
18
+
19
+ </div>
20
+ {%- endmacro %}
@@ -0,0 +1,11 @@
1
+ {% macro Select(bordered=True, style=None, size=None, ghost=None, placeholder=None) -%}
2
+ <select class="select w-full max-w-xs {{kwargs.pop('class', '')}} {% if bordered %} select-bordered{% endif %} {% if style %} select-{{style}}{% endif %} {% if size %} select-{{size}}{% endif %} {% if ghost %} select-ghost{% endif %}" {{ html_attrs(kwargs) }}>
3
+
4
+ {% if not placeholder %}{% else %}<option disabled="" selected="">{% if placeholder %}{{placeholder}}{% else %}
5
+ {% endif %}</option>{% endif %}
6
+
7
+ {{ caller() }}
8
+
9
+
10
+ </select>
11
+ {%- endmacro %}
@@ -0,0 +1,6 @@
1
+ {% macro Textarea(bordered=True, ghost=None, style=None, size=None) -%}
2
+ <textarea class="textarea {{kwargs.pop('class', '')}} {% if bordered %} textarea-bordered{% endif %} {% if ghost %} textarea-ghost{% endif %} {% if style %} textarea-{{style}}{% endif %} {% if size %} textarea-{{size}}{% endif %}" {{ html_attrs(kwargs) }}>
3
+ {{ caller() }}
4
+
5
+ </textarea>
6
+ {%- endmacro %}
@@ -0,0 +1,4 @@
1
+ {% macro Toggle(style=None, size=None) -%}
2
+ <input type="checkbox" class="toggle {{kwargs.pop('class', '')}} {% if style %} toggle-{{style}}{% endif %} {% if size %} toggle-{{size}}{% endif %}" {{ html_attrs(kwargs) }}>
3
+ </input>
4
+ {%- endmacro %}
@@ -0,0 +1,4 @@
1
+ {% macro Loading(style="spinner", size="md") -%}
2
+ <span class="loading {% if style %} loading-{{style}}{% endif %} {% if size %} loading-{{size}}{% endif %}">
3
+ </span>
4
+ {%- endmacro %}
@@ -0,0 +1,8 @@
1
+ {% macro Toast(x=None, y=None) -%}
2
+ <div class="toast {% if x %} toast-{{x}}{% endif %} {% if y %} toast-{{y}}{% endif %}">
3
+
4
+ {{ caller() }}
5
+
6
+
7
+ </div>
8
+ {%- endmacro %}
@@ -0,0 +1,8 @@
1
+ {% macro Footer(center=None, rows=None) -%}
2
+ <footer class="footer bg-neutral text-neutral-content p-10 {% if center %} footer-center{% endif %} {% if rows %} grid-rows-{{rows}}{% endif %}">
3
+
4
+ {{ caller() }}
5
+
6
+
7
+ </footer>
8
+ {%- endmacro %}
@@ -0,0 +1,6 @@
1
+ {% macro FooterLink() -%}
2
+ <a class="link link-hover {{kwargs.pop('class', '')}}" {{ html_attrs(kwargs) }}>
3
+ {{ caller() }}
4
+
5
+ </a>
6
+ {%- endmacro %}
@@ -0,0 +1,11 @@
1
+ {% macro FooterNav(title=None) -%}
2
+ <nav class="{{kwargs.pop('class', '')}}" {{ html_attrs(kwargs) }}>
3
+
4
+ {% if not title %}{% else %}<h6 class="footer-title">{% if title %}{{title}}{% else %}
5
+ {% endif %}</h6>{% endif %}
6
+
7
+ {{ caller() }}
8
+
9
+
10
+ </nav>
11
+ {%- endmacro %}
@@ -0,0 +1,11 @@
1
+ {% macro Indicator(value=None, style="neutral", size=None, outline=None, position=None) -%}
2
+ <div class="indicator">
3
+
4
+ <span class="indicator-item badge {% if style %} badge-{{style}}{% endif %} {% if size %} badge-{{size}}{% endif %} {% if outline %} badge-outline{% endif %} {% if position %} indicator-{{position}}{% endif %}">{% if value %}{{value}}{% else %}
5
+ {% endif %}</span>
6
+
7
+ {{ caller() }}
8
+
9
+
10
+ </div>
11
+ {%- endmacro %}
@@ -0,0 +1,6 @@
1
+ {% macro Link(style=None) -%}
2
+ <a class="link {{kwargs.pop('class', '')}} {% if style %} link-{{style}}{% endif %}" {{ html_attrs(kwargs) }}>
3
+ {{ caller() }}
4
+
5
+ </a>
6
+ {%- endmacro %}
@@ -0,0 +1,21 @@
1
+ {% macro Navbar(title, title_href=None, style=None) -%}
2
+ <div class="navbar bg-base-100 {{kwargs.pop('class', '')}} {% if style %} bg-{{style}} text-{{style}}-content{% endif %}" {{ html_attrs(kwargs) }}>
3
+
4
+ <div class="flex-1">
5
+
6
+ <a class="btn btn-ghost text-xl" {% if title_href %}href="{{title_href}}"{% endif %}>
7
+ {{title}}
8
+
9
+ </a>
10
+
11
+ </div>
12
+
13
+ <div class="flex-none gap-2">
14
+
15
+ {{ caller() }}
16
+
17
+
18
+ </div>
19
+
20
+ </div>
21
+ {%- endmacro %}
@@ -0,0 +1,16 @@
1
+
2
+ {% macro Form() -%}
3
+ {% set inner = caller() %}
4
+ <{form class__="space-y-5" method=kwargs.pop('method', 'post') **kwargs}>
5
+ {{form.hidden_tag()}}
6
+ {{inner}}
7
+ </{form}>
8
+ {%- endmacro %}
9
+
10
+ {% macro HxForm(action=None) -%}
11
+ {% set inner = caller() %}
12
+ <{Form hx_boost="false" hx_post=(action or request.url)
13
+ hx_on__after_request=("event.detail.successful && event.target.reset();" + kwargs.pop("hx_on__after_request", "")) **kwargs}>
14
+ {{inner}}
15
+ </{Form}>
16
+ {%- endmacro %}
@@ -0,0 +1,5 @@
1
+
2
+ {% macro Icon(name) -%}
3
+ {{ include_asset("bootstrap-icons/bootstrap-icons.min.css") }}
4
+ <i {{html_attrs(class__="bi-"+name, **kwargs)}}></i>
5
+ {%- endmacro %}
@@ -0,0 +1,7 @@
1
+
2
+ {% macro AutoOpenModal() -%}
3
+ {%- set inner = caller() -%}
4
+ <{Modal x_init="$el.showModal()" **kwargs }>
5
+ {{inner}}
6
+ </{}>
7
+ {%- endmacro %}
@@ -0,0 +1,5 @@
1
+
2
+
3
+
4
+ def send_email():
5
+ pass
@@ -0,0 +1,24 @@
1
+ from htmx_flask import request
2
+ from htmx_flask import make_response
3
+ from markupsafe import Markup
4
+ import re
5
+
6
+
7
+ def htmx_redirect(url):
8
+ return make_response(redirect=url)
9
+
10
+
11
+ def htmx_oob(html, swap="outerHTML", target=None):
12
+ if not request.htmx:
13
+ return ""
14
+ if callable(html):
15
+ html = html()
16
+ if target:
17
+ swap = f"{swap}:{target}"
18
+ html = str(html).strip()
19
+ if re.match(r'<([a-z]+)', html, re.I):
20
+ tag, html = html.split(" ", 1)
21
+ html = f"{tag} hx-swap-oob=\"{swap}\" {html}"
22
+ if tag[1:].lower() in ("tr", "td", "th", "thead", "tbody", "tfoot", "colgroup", "caption", "col"):
23
+ html = f"<template>{html}</template>"
24
+ return Markup(html)
@@ -0,0 +1,25 @@
1
+ from flask import request, url_for
2
+ from flask_file_routes import page
3
+ import inspect
4
+
5
+
6
+ def page_action(func=None, name=None):
7
+ def decorator(func):
8
+ action_name = func.__name__[3:] if not name else name
9
+ if request.method != "POST" or request.args.get("__action") != action_name:
10
+ return
11
+ sig = inspect.signature(func)
12
+ args = {}
13
+ for param in sig.parameters:
14
+ args[param.name] = request.values.get(param)
15
+ rv = func(**args)
16
+ page.respond(rv or ("", 200))
17
+ return decorator(func) if func else decorator
18
+
19
+
20
+ def page_action_url(action, endpoint=None, **kwargs):
21
+ return url_for(endpoint or request.endpoint, __action=action, **kwargs)
22
+
23
+
24
+ def hx_page_action(action, **kwargs):
25
+ return 'hx-post="%s"' % page_action_url(action, **kwargs)
@@ -0,0 +1,25 @@
1
+ from flask import request
2
+ from urllib.parse import urlparse, urljoin
3
+ import functools
4
+
5
+
6
+ def is_safe_redirect_url(target):
7
+ host_url = urlparse(request.host_url)
8
+ redirect_url = urlparse(urljoin(request.host_url, target))
9
+ return (
10
+ redirect_url.scheme in ("http", "https")
11
+ and host_url.netloc == redirect_url.netloc
12
+ )
13
+
14
+
15
+ def marshal_with_depends(content_types):
16
+ def decorator(func):
17
+ @functools.wraps(func)
18
+ def wrapper(*args, **kwargs):
19
+ response = func(*args, **kwargs)
20
+ response.headers["Content-Type"] = content_types
21
+ return response
22
+
23
+ return wrapper
24
+
25
+ return decorator
@@ -0,0 +1,28 @@
1
+ from flask import current_app, abort
2
+ from werkzeug.local import LocalProxy
3
+ from itsdangerous import URLSafeTimedSerializer, BadSignature
4
+
5
+
6
+ def get_token_serializer():
7
+ return URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
8
+
9
+
10
+ token_serializer = LocalProxy(get_token_serializer)
11
+
12
+
13
+ def create_token(data, **serializer_kwargs):
14
+ return token_serializer.dumps(data, **serializer_kwargs)
15
+
16
+
17
+ def load_token(token, **serializer_kwargs):
18
+ try:
19
+ return token_serializer.loads(token, **serializer_kwargs)
20
+ except BadSignature:
21
+ return None
22
+
23
+
24
+ def load_token_or_404(token, **serializer_kwargs):
25
+ data = load_token(token)
26
+ if data is None:
27
+ abort(404)
28
+ return data
@@ -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
+ ![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)
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
+