fastlifeweb 0.3.1__tar.gz → 0.4.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.
Files changed (81) hide show
  1. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/PKG-INFO +5 -4
  2. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/README.md +0 -2
  3. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/pyproject.toml +5 -2
  4. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/configurator/registry.py +2 -2
  5. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/configurator/settings.py +3 -0
  6. fastlifeweb-0.4.0/src/fastlife/templates/A.jinja +31 -0
  7. fastlifeweb-0.4.0/src/fastlife/templates/Button.jinja +41 -0
  8. fastlifeweb-0.4.0/src/fastlife/templates/Checkbox.jinja +20 -0
  9. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templates/CsrfToken.jinja +0 -1
  10. fastlifeweb-0.4.0/src/fastlife/templates/Form.jinja +11 -0
  11. fastlifeweb-0.4.0/src/fastlife/templates/H1.jinja +15 -0
  12. fastlifeweb-0.4.0/src/fastlife/templates/H2.jinja +15 -0
  13. fastlifeweb-0.4.0/src/fastlife/templates/H3.jinja +14 -0
  14. fastlifeweb-0.4.0/src/fastlife/templates/H4.jinja +14 -0
  15. fastlifeweb-0.4.0/src/fastlife/templates/H5.jinja +14 -0
  16. fastlifeweb-0.4.0/src/fastlife/templates/H6.jinja +14 -0
  17. fastlifeweb-0.4.0/src/fastlife/templates/Input.jinja +31 -0
  18. fastlifeweb-0.4.0/src/fastlife/templates/Label.jinja +11 -0
  19. fastlifeweb-0.4.0/src/fastlife/templates/Option.jinja +4 -0
  20. fastlifeweb-0.4.0/src/fastlife/templates/P.jinja +9 -0
  21. fastlifeweb-0.4.0/src/fastlife/templates/Radio.jinja +30 -0
  22. fastlifeweb-0.4.0/src/fastlife/templates/Select.jinja +27 -0
  23. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templates/pydantic_form/Boolean.jinja +1 -1
  24. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templates/pydantic_form/Dropdown.jinja +4 -6
  25. fastlifeweb-0.4.0/src/fastlife/templates/pydantic_form/Hint.jinja +4 -0
  26. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templates/pydantic_form/Model.jinja +1 -1
  27. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templates/pydantic_form/Sequence.jinja +3 -3
  28. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templates/pydantic_form/Text.jinja +1 -3
  29. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templates/pydantic_form/Union.jinja +5 -5
  30. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/__init__.py +2 -2
  31. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/binding.py +4 -22
  32. fastlifeweb-0.4.0/src/fastlife/templating/renderer/__init__.py +7 -0
  33. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/renderer/abstract.py +7 -5
  34. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/renderer/jinjax.py +51 -23
  35. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/renderer/widgets/base.py +12 -2
  36. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/renderer/widgets/boolean.py +4 -3
  37. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/renderer/widgets/dropdown.py +7 -6
  38. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/renderer/widgets/factory.py +38 -21
  39. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/renderer/widgets/hidden.py +2 -3
  40. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/renderer/widgets/model.py +7 -6
  41. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/renderer/widgets/sequence.py +8 -9
  42. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/renderer/widgets/text.py +9 -5
  43. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/renderer/widgets/union.py +7 -6
  44. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/testing/testclient.py +116 -55
  45. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/views/pydantic_form.py +5 -2
  46. fastlifeweb-0.3.1/src/fastlife/templates/A.jinja +0 -5
  47. fastlifeweb-0.3.1/src/fastlife/templates/Button.jinja +0 -27
  48. fastlifeweb-0.3.1/src/fastlife/templates/Checkbox.jinja +0 -2
  49. fastlifeweb-0.3.1/src/fastlife/templates/Form.jinja +0 -5
  50. fastlifeweb-0.3.1/src/fastlife/templates/H1.jinja +0 -4
  51. fastlifeweb-0.3.1/src/fastlife/templates/H2.jinja +0 -4
  52. fastlifeweb-0.3.1/src/fastlife/templates/Input.jinja +0 -8
  53. fastlifeweb-0.3.1/src/fastlife/templates/Label.jinja +0 -3
  54. fastlifeweb-0.3.1/src/fastlife/templates/Option.jinja +0 -2
  55. fastlifeweb-0.3.1/src/fastlife/templates/Radio.jinja +0 -8
  56. fastlifeweb-0.3.1/src/fastlife/templates/Select.jinja +0 -8
  57. fastlifeweb-0.3.1/src/fastlife/templating/renderer/__init__.py +0 -4
  58. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/LICENSE +0 -0
  59. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/__init__.py +0 -0
  60. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/configurator/__init__.py +0 -0
  61. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/configurator/base.py +0 -0
  62. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/configurator/configurator.py +0 -0
  63. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/py.typed +0 -0
  64. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/request/__init__.py +0 -0
  65. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/request/form_data.py +0 -0
  66. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/security/__init__.py +0 -0
  67. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/security/csrf.py +0 -0
  68. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/security/policy.py +0 -0
  69. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/session/__init__.py +0 -0
  70. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/session/middleware.py +0 -0
  71. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/session/serializer.py +0 -0
  72. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/shared_utils/__init__.py +0 -0
  73. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/shared_utils/infer.py +0 -0
  74. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/shared_utils/resolver.py +0 -0
  75. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templates/Hidden.jinja +0 -0
  76. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templates/__init__.py +0 -0
  77. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templates/pydantic_form/Hidden.jinja +0 -0
  78. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templates/pydantic_form/Widget.jinja +0 -0
  79. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/templating/renderer/widgets/__init__.py +0 -0
  80. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/testing/__init__.py +0 -0
  81. {fastlifeweb-0.3.1 → fastlifeweb-0.4.0}/src/fastlife/views/__init__.py +0 -0
@@ -1,7 +1,8 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastlifeweb
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: High-level web framework
5
+ Home-page: https://github.com/mardiros/fastlife
5
6
  License: BSD-derived
6
7
  Author: Guillaume Gauvrit
7
8
  Author-email: guillaume@gauvr.it
@@ -20,12 +21,14 @@ Requires-Dist: beautifulsoup4[testing] (>=4.12.2,<5.0.0)
20
21
  Requires-Dist: behave (>=1.2.6,<2.0.0)
21
22
  Requires-Dist: fastapi (>=0.110.0,<0.111.0)
22
23
  Requires-Dist: itsdangerous (>=2.1.2,<3.0.0)
23
- Requires-Dist: jinjax (>=0.31,<0.32)
24
+ Requires-Dist: jinjax (>=0.32,<0.33)
24
25
  Requires-Dist: markupsafe (>=2.1.3,<3.0.0)
26
+ Requires-Dist: multidict (>=6.0.5,<7.0.0)
25
27
  Requires-Dist: pydantic (>=2.3.0,<3.0.0)
26
28
  Requires-Dist: pydantic-settings (>=2.0.3,<3.0.0)
27
29
  Requires-Dist: python-multipart (>=0.0.6,<0.0.7)
28
30
  Requires-Dist: venusian (>=3.0.0,<4.0.0)
31
+ Project-URL: Repository, https://github.com/mardiros/fastlife
29
32
  Description-Content-Type: text/markdown
30
33
 
31
34
  # Fastlife
@@ -44,5 +47,3 @@ Under heavy development.
44
47
 
45
48
  The package is available on pypi with the name fastlifeweb.
46
49
 
47
- The name fastlife is squatted and I am tired of PEP 541 requests.
48
-
@@ -13,5 +13,3 @@ Under heavy development.
13
13
 
14
14
 
15
15
  The package is available on pypi with the name fastlifeweb.
16
-
17
- The name fastlife is squatted and I am tired of PEP 541 requests.
@@ -4,6 +4,8 @@ description = "High-level web framework"
4
4
  name = "fastlifeweb"
5
5
  license = "BSD-derived"
6
6
  packages = [{include = "fastlife", from = "src"}]
7
+ homepage = "https://github.com/mardiros/fastlife"
8
+ repository = "https://github.com/mardiros/fastlife"
7
9
  readme = "README.md"
8
10
  classifiers = [
9
11
  "Development Status :: 4 - Beta",
@@ -13,13 +15,13 @@ classifiers = [
13
15
  "Topic :: Software Development :: Libraries :: Python Modules",
14
16
  "Topic :: Internet :: WWW/HTTP",
15
17
  ]
16
- version = "0.3.1"
18
+ version = "0.4.0"
17
19
 
18
20
  [tool.poetry.dependencies]
19
21
  python = "^3.11"
20
22
  beautifulsoup4 = {version = "^4.12.2", extras = ["testing"]}
21
23
  fastapi = "^0.110.0"
22
- jinjax = "^0.31"
24
+ jinjax = "^0.32"
23
25
  pydantic = "^2.3.0"
24
26
  pydantic-settings = "^2.0.3"
25
27
  python-multipart = "^0.0.6"
@@ -27,6 +29,7 @@ venusian = "^3.0.0"
27
29
  markupsafe = "^2.1.3"
28
30
  behave = "^1.2.6"
29
31
  itsdangerous = "^2.1.2"
32
+ multidict = "^6.0.5"
30
33
 
31
34
  [tool.poetry.group.dev.dependencies]
32
35
  beautifulsoup4 = "^4.12.2"
@@ -7,7 +7,7 @@ from fastlife.shared_utils.resolver import resolve
7
7
 
8
8
  if TYPE_CHECKING:
9
9
  from fastlife.templating.renderer import ( # coverage: ignore
10
- AbstractTemplateRenderer, # coverage: ignore
10
+ AbstractTemplateRendererFactory, # coverage: ignore
11
11
  ) # coverage: ignore
12
12
 
13
13
  from .settings import Settings
@@ -15,7 +15,7 @@ from .settings import Settings
15
15
 
16
16
  class AppRegistry:
17
17
  settings: Settings
18
- renderer: "AbstractTemplateRenderer"
18
+ renderer: "AbstractTemplateRendererFactory"
19
19
  check_permission: CheckPermission
20
20
 
21
21
  def __init__(self, settings: Settings) -> None:
@@ -17,6 +17,9 @@ class Settings(BaseSettings):
17
17
  form_data_model_prefix: str = Field(default="payload")
18
18
  csrf_token_name: str = Field(default="csrf_token")
19
19
 
20
+ jinjax_use_cache: bool = Field(default=True)
21
+ jinjax_auto_reload: bool = Field(default=False)
22
+
20
23
  session_secret_key: str = Field(default="")
21
24
  session_cookie_name: str = Field(default="flsess")
22
25
  session_cookie_domain: str = Field(default="")
@@ -0,0 +1,31 @@
1
+ {# def
2
+ href,
3
+ disable_htmx=false,
4
+ hx_target="#maincontent",
5
+ hx_select=None,
6
+ hx_swap="innerHTML show:body:top",
7
+ hx_push_url=true,
8
+ class_="""
9
+ bg-neutral-200
10
+ px-5
11
+ py-2.5
12
+ rounded-lg
13
+ text-center
14
+ text-neutral-900
15
+ text-sm
16
+ font-medium
17
+ focus:outline-none
18
+ focus:ring-4
19
+ focus:ring-primary-300
20
+ hover:bg-neutral-50
21
+ dark:bg-neutral-400
22
+ dark:focus:ring-neutral-100
23
+ dark:hover:bg-neutral-300
24
+ """
25
+ #}
26
+
27
+ <a href="{{href}}" {% if not disable_htmx %} hx-get="{{href}}" hx-target="{{hx_target}}" hx-swap="{{hx_swap}}" {% if
28
+ hx_push_url %} hx-push-url="true" {%- endif %}{% if hx_select %} hx-select="{{hx_select}}" {%- endif %}{%- endif
29
+ %}class="{{attrs.class or class_}}">
30
+ {{- content -}}
31
+ </a>
@@ -0,0 +1,41 @@
1
+ {# def
2
+ type="submit",
3
+ id="",
4
+ name="action",
5
+ value="submit",
6
+ hidden=false,
7
+ aria_label="",
8
+ onclick="",
9
+ hx_target="",
10
+ hx_swap="",
11
+ hx_get="",
12
+ hx_select="",
13
+ hx_after_request="",
14
+ hx_vals="",
15
+ full_width=false,
16
+ class_="""
17
+ bg-primary-600
18
+ font-medium
19
+ px-5
20
+ py-2.5
21
+ rounded-lg
22
+ text-center
23
+ text-sm
24
+ text-white
25
+ hover:bg-primary-700
26
+ focus:outline-none
27
+ focus:ring-4
28
+ focus:ring-primary-300
29
+ dark:bg-primary-600
30
+ dark:focus:ring-primary-800
31
+ dark:hover:bg-primary-700
32
+ """
33
+ #}
34
+ <button type="{{type}}" {%if id %}id="{{id}}" {%endif%} name="{{name}}" value="{{value}}" {% if
35
+ hx_target%}hx-target="{{hx_target}}" {% endif %} {% if hx_swap %}hx-swap="{{hx_swap}}" {% endif %} {% if hx_select
36
+ %}hx-select="{{hx_select}}" {% endif %} {% if hx_get %}hx-get="{{hx_get}}" {% endif %} {% if onclick %}onclick="{{onclick}}" {%
37
+ endif %}{% if hx_after_request %}hx-on::after-request="{{hx_after_request}}" {% endif %} {% if hx_vals
38
+ %}hx-vals='{{hx_vals|safe}}' {% endif %} {% if aria_label %}aria-label="{{aria_label}}" {% endif %}
39
+ class="{% if full_width %}w-full {% endif %}{{attrs.class or class_}}" {% if hidden %}hidden{% endif %}>
40
+ {{- content -}}
41
+ </button>
@@ -0,0 +1,20 @@
1
+ {# def
2
+ name,
3
+ value,
4
+ id,
5
+ class_="""
6
+ bg-neutral-100
7
+ border-neutral-300
8
+ h-4
9
+ rounded
10
+ text-primary-600
11
+ w-4
12
+ dark:bg-neutral-700
13
+ dark:border-neutral-600
14
+ dark:focus:ring-primary-600
15
+ dark:ring-offset-neutral-800
16
+ focus:ring-2
17
+ focus:ring-primary-500
18
+ """
19
+ #}
20
+ <input name="{{name}}" {% if value%}checked{% endif %} type="checkbox" id="{{id}}" class="{{attrs.class or class_}}" />
@@ -1,2 +1 @@
1
- {# def csrf_token #}
2
1
  <Hidden name={csrf_token.name} value={csrf_token.value} />
@@ -0,0 +1,11 @@
1
+ {# def
2
+ method="",
3
+ action=None,
4
+ hx_post=None,
5
+ class_="space-y-4 md:space-y-6"
6
+ #}
7
+ <form class="{{attrs.class or class_}}" {% if hx_post is not none %}hx-post="{{hx_post}}" {% endif %}{% if action is not
8
+ none %}action="{{action}}" {% endif %}{% if method %}method="{{method}}" {% endif %}>
9
+ <CsrfToken />
10
+ {{ content }}
11
+ </form>
@@ -0,0 +1,15 @@
1
+ {# def
2
+ class_="""
3
+ block
4
+ font-bold
5
+ font-sans
6
+ leading-tight
7
+ pb-4
8
+ text-5xl
9
+ text-neutral-900
10
+ tracking-tight
11
+ dark:text-white
12
+ md:text-4xl
13
+ """
14
+ #}
15
+ <h1 class="{{attrs.class or class_}}">{{ content }}</h1>
@@ -0,0 +1,15 @@
1
+ {# def
2
+ class_="""
3
+ block
4
+ font-bold
5
+ font-sans
6
+ leading-tight
7
+ pb-4
8
+ text-4xl
9
+ text-neutral-900
10
+ tracking-tight
11
+ dark:text-white
12
+ md:text-4xl
13
+ """
14
+ #}
15
+ <h2 class="{{attrs.class or class_}}">{{ content }}</h2>
@@ -0,0 +1,14 @@
1
+ {# def
2
+ class_="""
3
+ block
4
+ font-bold
5
+ font-sans
6
+ leading-tight
7
+ pb-4
8
+ text-3xl
9
+ text-neutral-900
10
+ tracking-tight
11
+ dark:text-white
12
+ md:text-3xl"""
13
+ #}
14
+ <h3 class="{{attrs.class or class_}}">{{ content }}</h3>
@@ -0,0 +1,14 @@
1
+ {# def
2
+ class_="""
3
+ block
4
+ font-bold
5
+ font-sans
6
+ leading-tight
7
+ pb-4
8
+ text-2xl
9
+ text-neutral-900
10
+ tracking-tight
11
+ dark:text-white
12
+ md:text-2xl"""
13
+ #}
14
+ <h4 class="{{attrs.class or class_}}">{{ content }}</h4>
@@ -0,0 +1,14 @@
1
+ {# def
2
+ class_="""
3
+ block
4
+ font-bold
5
+ font-sans
6
+ leading-tight
7
+ pb-4
8
+ text-xl
9
+ text-neutral-900
10
+ tracking-tight
11
+ dark:text-white
12
+ md:text-xl"""
13
+ #}
14
+ <h5 class="{{attrs.class or class_}}">{{ content }}</h5>
@@ -0,0 +1,14 @@
1
+ {# def
2
+ class_="""
3
+ block
4
+ font-bold
5
+ font-sans
6
+ leading-tight
7
+ pb-4
8
+ text-l
9
+ text-neutral-900
10
+ tracking-tight
11
+ dark:text-white
12
+ md:text-l"""
13
+ #}
14
+ <h6 class="{{attrs.class or class_}}">{{ content }}</h6>
@@ -0,0 +1,31 @@
1
+ {# def
2
+ name,
3
+ value="",
4
+ type="text",
5
+ id="",
6
+ aria_label="",
7
+ placeholder="",
8
+ class_="""
9
+ bg-neutral-50
10
+ block
11
+ border
12
+ border-neutral-300
13
+ p-2.5
14
+ rounded-lg
15
+ text-base
16
+ text-neutral-900
17
+ w-full
18
+ dark:bg-neutral-700
19
+ dark:border-neutral-600
20
+ dark:focus:border-primary-500
21
+ dark:focus:ring-primary-500
22
+ dark:placeholder-neutral-400
23
+ dark:text-white
24
+ focus:border-primary-500
25
+ focus:ring-primary-500
26
+ """
27
+ #}
28
+
29
+ <input name="{{name}}" value="{{value}}" type="{{type}}" {% if id %}id="{{id}}" {% endif %}{% if aria_label
30
+ %}aria-label="{{aria_label}}" {% endif %} {% if placeholder %}placeholder="{{placeholder}}" {% endif %}
31
+ class="{{attrs.class or class_}}" />
@@ -0,0 +1,11 @@
1
+ {#def
2
+ class_="""
3
+ block
4
+ font-bold
5
+ mb-2
6
+ text-base
7
+ text-neutral-900
8
+ dark:text-white
9
+ """ #}
10
+
11
+ <label for="{{attrs.for}}" class="{{attrs.class or class_}}">{{content}}</label>
@@ -0,0 +1,4 @@
1
+ {# def value, selected=False #}
2
+ <option value="{{value}}" {%if selected%}selected{% endif%}>
3
+ {{- content -}}
4
+ </option>
@@ -0,0 +1,9 @@
1
+ {# def
2
+ id="",
3
+ class_="""
4
+ text-base
5
+ text-neutral-900
6
+ dark:text-white
7
+ """
8
+ #}
9
+ <p {% if id %}id="{{id}}" {% endif %} class="{{ attrs.class or class_}}">{{content}}</p>
@@ -0,0 +1,30 @@
1
+ {# def
2
+ label,
3
+ name,
4
+ id,
5
+ value,
6
+ checked=false,
7
+ disabled=false,
8
+ onclick="",
9
+ class_="""
10
+ bg-neutral-100
11
+ border-neutral-300
12
+ w-4
13
+ h-4
14
+ text-primary-600
15
+ focus:ring-2
16
+ focus:ring-primary-500
17
+ dark:bg-neutral-700
18
+ dark:border-neutral-600
19
+ dark:focus:ring-primary-600
20
+ dark:ring-offset-neutral-800
21
+ """,
22
+ label_class="ms-2 text-sm font-medium text-neutral-900 dark:text-neutral-300",
23
+ div_class="flex items-center mb-4"
24
+ #}
25
+ <div class="{{div_class}}">
26
+ <input type="radio" name="{{name}}" id="{{id}}" value="{{value}}" {% if checked %}checked{% endif %}
27
+ class="{{attrs.class or class_}}" {% if onclick %}onclick="{{onclick}}" {% endif %} {%if
28
+ disabled%}disabled{%endif%}>
29
+ <Label for={id} class={label_class}>{{label}}</Label>
30
+ </div>
@@ -0,0 +1,27 @@
1
+ {# def
2
+ name,
3
+ id,
4
+ class_="""
5
+ bg-neutral-50
6
+ block
7
+ border
8
+ border-neutral-300
9
+ p-2.5
10
+ rounded-lg
11
+ text-base
12
+ text-neutral-900
13
+ w-full
14
+ focus:border-primary-500
15
+ focus:ring-primary-500
16
+ dark:bg-neutral-700
17
+ dark:border-neutral-600
18
+ dark:focus:border-primary-500
19
+ dark:focus:ring-primary-500
20
+ dark:placeholder-neutral-400
21
+ dark:text-white
22
+ """
23
+ #}
24
+
25
+ <select name="{{name}}" id="{{id}}" class="{{attrs.class or class_}}">
26
+ {{- content -}}
27
+ </select>
@@ -2,6 +2,6 @@
2
2
  <pydantic_form.Widget widget={widget} removable={widget.removable}>
3
3
  <div class="pt-4">
4
4
  <Label for={widget.id}>{{widget.title}}</Label>
5
- <Checkbox name={widget.name} value={widget.value} type="checkbox" id={widget.id} />
5
+ <Checkbox name={widget.name} type="checkbox" id={widget.id} {% if widget.value %}checked{% endif %} />
6
6
  </div>
7
7
  </pydantic_form.Widget>
@@ -5,13 +5,11 @@
5
5
  <Label for={widget.id}>{{widget.title}}</Label>
6
6
  <Select name={widget.name} id={widget.id}>
7
7
  {%- for opt in widget.options -%}
8
- <Option value={opt.value}>
9
- {{ opt.text }}
10
- </Option>
8
+ <Option value={opt.value} id={widget.id + "-" + opt.value} selected={widget.value==opt.value}>
9
+ {{ opt.text }}
10
+ </Option>
11
11
  {%- endfor -%}
12
12
  </Select>
13
- {%- if widget.help_text -%}
14
- <span class="mt-2 text-sm text-neutral-500 dark:text-neutral-400">{{widget.help_text}}</span>
15
- {%- endif %}
13
+ <pydantic_form.Hint text={widget.hint} />
16
14
  </div>
17
15
  </pydantic_form.Widget>
@@ -0,0 +1,4 @@
1
+ {# def text #}
2
+ {% if text %}
3
+ <span class="mt-2 text-sm text-neutral-500 dark:text-neutral-400">{{text}}</span>
4
+ {% endif %}
@@ -4,7 +4,7 @@
4
4
  <div id="{{widget.id}}" class="m-4">
5
5
  <details open>
6
6
  <summary class="justify-between items-center font-medium cursor-pointer">
7
- <h4 class="inline font-sans text-3xl font-bold">{{widget.title}}</h4>
7
+ <H3>{{widget.title}}</H3>
8
8
  </summary>
9
9
  <div>
10
10
  {% for child in children_widget %}
@@ -3,12 +3,12 @@
3
3
  <pydantic_form.Widget widget={widget} removable={widget.removable}>
4
4
  <details id="{{widget.id}}" open>
5
5
  <summary class="justify-between items-center font-medium cursor-pointer">
6
- <h4 class="inline font-sans text-3xl font-bold">{{widget.title}}</h4>
6
+ <H3>{{widget.title}}</H3>
7
7
  </summary>
8
8
  <div>
9
9
  {% set fnGetName = "get" + widget.id.replace("-", "_") %}
10
10
  <script>
11
- function {{fnGetName}}() {
11
+ function {{ fnGetName }} () {
12
12
  const el = document.getElementById("{{widget.id}}-content");
13
13
  const len = el.dataset.length;
14
14
  el.dataset.length = parseInt(len) + 1;
@@ -28,7 +28,7 @@
28
28
  {% set container_id = "#" + widget.id + "-container" %}
29
29
  {% set add_id = widget.id + "-add" %}
30
30
  {% set vals = 'js:{"name": '+ fnGetName + '(), "token": "' + type.token + '", "removable": true}' %}
31
- <Button type="button" target={container_id} swap="beforeend" id={add_id} vals={vals} get={type.url}>
31
+ <Button type="button" hx-target={container_id} hx-swap="beforeend" id={add_id} hx-vals={vals} hx-get={type.url}>
32
32
  Add
33
33
  </Button>
34
34
  </div>
@@ -5,8 +5,6 @@
5
5
  <Label for={widget.id}>{{widget.title}}</Label>
6
6
  <Input name={widget.name} value={widget.value} type={widget.input_type} id={widget.id}
7
7
  aria-label={widget.aria_label} placeholder={widget.placeholder} />
8
- {%- if widget.help_text -%}
9
- <span class="mt-2 text-sm text-neutral-500 dark:text-neutral-400">{{widget.help_text}}</span>
10
- {%- endif %}
8
+ <pydantic_form.Hint text={widget.hint} />
11
9
  </div>
12
10
  </pydantic_form.Widget>
@@ -4,21 +4,21 @@
4
4
  <div id="{{widget.id}}">
5
5
  <details open>
6
6
  <summary class="justify-between items-center font-medium cursor-pointer">
7
- <h4 class="inline font-sans text-3xl font-bold">{{widget.title}}</h4>
7
+ <H3>{{widget.title}}</H3>
8
8
  </summary>
9
9
  <div hx-sync="this" id="{{widget.id}}-child">
10
10
  {% if child %}
11
11
  {{ child }}
12
12
  {% else %}
13
13
  {% for typ in types %}
14
- <Button type="button" target="closest div" get={typ.url} vals={typ.params|tojson}
15
- id={typ.fullname + "-" + widget.token}
14
+ <Button type="button" hx-target="closest div" hx-get={typ.url} hx-vals={typ.params|tojson}
15
+ id={typ.id}
16
16
  onclick={"document.getElementById('" + widget.id +"-remove-btn').hidden=false"}>{{typ.title}}</Button>
17
17
  {% endfor %}
18
18
  {% endif %}
19
19
  </div>
20
- <Button type="button" id={widget.id + "-remove-btn" } target={"#" + widget.id} vals={parent_type.params|tojson}
21
- get={parent_type.url} hidden={not child}>
20
+ <Button type="button" id={widget.id + "-remove-btn" } hx-target={"#" + widget.id} hx-vals={parent_type.params|tojson}
21
+ hx-get={parent_type.url} hidden={not child}>
22
22
  Remove
23
23
  </Button>
24
24
  </details>
@@ -1,8 +1,8 @@
1
1
  from .binding import Template, template
2
- from .renderer import AbstractTemplateRenderer, JinjaxTemplateRenderer
2
+ from .renderer import AbstractTemplateRendererFactory, JinjaxTemplateRenderer
3
3
 
4
4
  __all__ = [
5
- "AbstractTemplateRenderer",
5
+ "AbstractTemplateRendererFactory",
6
6
  "JinjaxTemplateRenderer",
7
7
  "Template",
8
8
  "template",
@@ -9,9 +9,7 @@ Template = Callable[..., Response]
9
9
  TemplateEngine = Callable[["Registry", Request], Template]
10
10
 
11
11
 
12
- def get_page_template(
13
- template: str, *, content_type: str = "text/html"
14
- ) -> TemplateEngine:
12
+ def get_template(template: str, *, content_type: str = "text/html") -> TemplateEngine:
15
13
  def render_template(
16
14
  reg: "Registry",
17
15
  request: Request,
@@ -23,7 +21,7 @@ def get_page_template(
23
21
  request.cookies.get(reg.settings.csrf_token_name)
24
22
  or _create_csrf_token()
25
23
  )
26
- data = reg.renderer.render_page(request, template, **kwargs)
24
+ data = reg.renderer(request).render_template(template, **kwargs)
27
25
  resp = Response(data, headers={"Content-Type": content_type})
28
26
  resp.set_cookie(
29
27
  reg.settings.csrf_token_name,
@@ -39,21 +37,5 @@ def get_page_template(
39
37
  return render_template
40
38
 
41
39
 
42
- def get_template(
43
- template: str, *, content_type: str = "text/html"
44
- ) -> Callable[["Registry"], Template]:
45
- def render_template(reg: "Registry") -> Template:
46
- def parametrizer(**kwargs: Any) -> Response:
47
- data = reg.renderer.render_template(template, **kwargs)
48
- resp = Response(data, headers={"Content-Type": content_type})
49
- return resp
50
-
51
- return parametrizer
52
-
53
- return render_template
54
-
55
-
56
- def template(template_path: str, page: bool = True) -> Template:
57
- return Depends(
58
- get_page_template(template_path) if page else get_template(template_path)
59
- )
40
+ def template(template_path: str) -> Template:
41
+ return Depends(get_template(template_path))
@@ -0,0 +1,7 @@
1
+ from .abstract import AbstractTemplateRendererFactory
2
+ from .jinjax import JinjaxTemplateRenderer
3
+
4
+ __all__ = [
5
+ "AbstractTemplateRendererFactory",
6
+ "JinjaxTemplateRenderer",
7
+ ]
@@ -8,11 +8,7 @@ from pydantic.fields import FieldInfo
8
8
 
9
9
  class AbstractTemplateRenderer(abc.ABC):
10
10
  route_prefix: str
11
- """Used to prefix url to fetch fast life widgets."""
12
-
13
- @abc.abstractmethod
14
- def render_page(self, request: Request, template: str, **params: Any) -> str:
15
- ...
11
+ """Used to buid pydantic form"""
16
12
 
17
13
  @abc.abstractmethod
18
14
  def render_template(self, template: str, **params: Any) -> str:
@@ -29,3 +25,9 @@ class AbstractTemplateRenderer(abc.ABC):
29
25
  field: FieldInfo | None = None,
30
26
  ) -> Markup:
31
27
  ...
28
+
29
+
30
+ class AbstractTemplateRendererFactory(abc.ABC):
31
+ @abc.abstractmethod
32
+ def __call__(self, request: Request) -> AbstractTemplateRenderer:
33
+ ...