fastlifeweb 0.6.0__tar.gz → 0.6.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 (74) hide show
  1. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/PKG-INFO +2 -2
  2. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/pyproject.toml +2 -2
  3. fastlifeweb-0.6.1/src/fastlife/templates/pydantic_form/Boolean.jinja +12 -0
  4. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/pydantic_form/Checklist.jinja +2 -0
  5. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/pydantic_form/Dropdown.jinja +1 -0
  6. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/pydantic_form/Model.jinja +1 -0
  7. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/pydantic_form/Sequence.jinja +1 -0
  8. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/pydantic_form/Union.jinja +4 -4
  9. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/widgets/boolean.py +7 -1
  10. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/widgets/checklist.py +9 -2
  11. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/widgets/dropdown.py +7 -1
  12. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/widgets/factory.py +12 -0
  13. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/widgets/model.py +7 -1
  14. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/widgets/sequence.py +7 -1
  15. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/widgets/union.py +7 -1
  16. fastlifeweb-0.6.0/src/fastlife/templates/pydantic_form/Boolean.jinja +0 -7
  17. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/LICENSE +0 -0
  18. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/README.md +0 -0
  19. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/__init__.py +0 -0
  20. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/configurator/__init__.py +0 -0
  21. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/configurator/base.py +0 -0
  22. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/configurator/configurator.py +0 -0
  23. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/configurator/registry.py +0 -0
  24. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/configurator/settings.py +0 -0
  25. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/py.typed +0 -0
  26. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/request/__init__.py +0 -0
  27. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/request/form_data.py +0 -0
  28. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/request/model_result.py +0 -0
  29. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/security/__init__.py +0 -0
  30. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/security/csrf.py +0 -0
  31. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/security/policy.py +0 -0
  32. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/session/__init__.py +0 -0
  33. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/session/middleware.py +0 -0
  34. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/session/serializer.py +0 -0
  35. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/shared_utils/__init__.py +0 -0
  36. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/shared_utils/infer.py +0 -0
  37. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/shared_utils/resolver.py +0 -0
  38. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/A.jinja +0 -0
  39. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/Button.jinja +0 -0
  40. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/Checkbox.jinja +0 -0
  41. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/CsrfToken.jinja +0 -0
  42. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/Form.jinja +0 -0
  43. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/H1.jinja +0 -0
  44. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/H2.jinja +0 -0
  45. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/H3.jinja +0 -0
  46. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/H4.jinja +0 -0
  47. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/H5.jinja +0 -0
  48. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/H6.jinja +0 -0
  49. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/Hidden.jinja +0 -0
  50. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/Input.jinja +0 -0
  51. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/Label.jinja +0 -0
  52. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/Option.jinja +0 -0
  53. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/P.jinja +0 -0
  54. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/Radio.jinja +0 -0
  55. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/Select.jinja +0 -0
  56. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/__init__.py +0 -0
  57. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/pydantic_form/Error.jinja +0 -0
  58. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/pydantic_form/Hidden.jinja +0 -0
  59. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/pydantic_form/Hint.jinja +0 -0
  60. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/pydantic_form/Text.jinja +0 -0
  61. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templates/pydantic_form/Widget.jinja +0 -0
  62. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/__init__.py +0 -0
  63. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/binding.py +0 -0
  64. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/__init__.py +0 -0
  65. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/abstract.py +0 -0
  66. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/jinjax.py +0 -0
  67. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/widgets/__init__.py +0 -0
  68. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/widgets/base.py +0 -0
  69. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/widgets/hidden.py +0 -0
  70. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/templating/renderer/widgets/text.py +0 -0
  71. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/testing/__init__.py +0 -0
  72. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/testing/testclient.py +0 -0
  73. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/views/__init__.py +0 -0
  74. {fastlifeweb-0.6.0 → fastlifeweb-0.6.1}/src/fastlife/views/pydantic_form.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastlifeweb
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Summary: High-level web framework
5
5
  Home-page: https://github.com/mardiros/fastlife
6
6
  License: BSD-derived
@@ -24,7 +24,7 @@ Requires-Dist: itsdangerous (>=2.1.2,<3.0.0)
24
24
  Requires-Dist: jinjax (>=0.34,<0.35)
25
25
  Requires-Dist: markupsafe (>=2.1.3,<3.0.0)
26
26
  Requires-Dist: multidict (>=6.0.5,<7.0.0)
27
- Requires-Dist: pydantic (==2.5.1)
27
+ Requires-Dist: pydantic (>=2.5.3,<3.0.0)
28
28
  Requires-Dist: pydantic-settings (>=2.0.3,<3.0.0)
29
29
  Requires-Dist: python-multipart (>=0.0.6,<0.0.7)
30
30
  Requires-Dist: venusian (>=3.0.0,<4.0.0)
@@ -15,7 +15,7 @@ classifiers = [
15
15
  "Topic :: Software Development :: Libraries :: Python Modules",
16
16
  "Topic :: Internet :: WWW/HTTP",
17
17
  ]
18
- version = "0.6.0"
18
+ version = "0.6.1"
19
19
 
20
20
  [tool.poetry.dependencies]
21
21
  python = "^3.11"
@@ -26,7 +26,7 @@ itsdangerous = "^2.1.2"
26
26
  jinjax = "^0.34"
27
27
  markupsafe = "^2.1.3"
28
28
  multidict = "^6.0.5"
29
- pydantic = "2.5.1"
29
+ pydantic = "^2.5.3"
30
30
  pydantic-settings = "^2.0.3"
31
31
  python-multipart = "^0.0.6"
32
32
  venusian = "^3.0.0"
@@ -0,0 +1,12 @@
1
+ {# def widget #}
2
+ <pydantic_form.Widget widget={widget} removable={widget.removable}>
3
+ <div class="pt-4">
4
+ <div class="flex items-center">
5
+ <Checkbox name={widget.name} type="checkbox" id={widget.id} checked={widget.value} value="1" />
6
+ <Label for={widget.id} class="ms-2 text-base text-neutral-900 dark:text-white">
7
+ {{widget.title|safe}}
8
+ </Label>
9
+ </div>
10
+ <pydantic_form.Error text={widget.error} />
11
+ </div>
12
+ </pydantic_form.Widget>
@@ -7,12 +7,14 @@ widget,
7
7
  <details open>
8
8
  <summary class="justify-between items-center font-medium cursor-pointer">
9
9
  <H3>{{widget.title}}</H3>
10
+ <pydantic_form.Error text={widget.error} />
10
11
  </summary>
11
12
  <div>
12
13
  {% for value in widget.value %}
13
14
  <div class="flex items-center mb-4">
14
15
  <Checkbox name={value.field_name} type="checkbox" id={value.id} value={value.value} checked={value.checked} />
15
16
  <Label for={value.id} class="ms-2 text-base text-neutral-900 dark:text-white">{{value.label}}</Label>
17
+ <pydantic_form.Error text={value.error} />
16
18
  </div>
17
19
  {% endfor %}
18
20
  </div>
@@ -10,6 +10,7 @@
10
10
  </Option>
11
11
  {%- endfor -%}
12
12
  </Select>
13
+ <pydantic_form.Error text={widget.error} />
13
14
  <pydantic_form.Hint text={widget.hint} />
14
15
  </div>
15
16
  </pydantic_form.Widget>
@@ -5,6 +5,7 @@
5
5
  <details open>
6
6
  <summary class="justify-between items-center font-medium cursor-pointer">
7
7
  <H3>{{widget.title}}</H3>
8
+ <pydantic_form.Error text={widget.error} />
8
9
  </summary>
9
10
  <div>
10
11
  {% for child in children_widget %}
@@ -4,6 +4,7 @@
4
4
  <details id="{{widget.id}}" open>
5
5
  <summary class="justify-between items-center font-medium cursor-pointer">
6
6
  <H3>{{widget.title}}</H3>
7
+ <pydantic_form.Error text={widget.error} />
7
8
  </summary>
8
9
  <div>
9
10
  {% set fnGetName = "get" + widget.id.replace("-", "_") %}
@@ -5,20 +5,20 @@
5
5
  <details open>
6
6
  <summary class="justify-between items-center font-medium cursor-pointer">
7
7
  <H3>{{widget.title}}</H3>
8
+ <pydantic_form.Error text={widget.error} />
8
9
  </summary>
9
10
  <div hx-sync="this" id="{{widget.id}}-child">
10
11
  {% if child %}
11
12
  {{ child }}
12
13
  {% else %}
13
14
  {% for typ in types %}
14
- <Button type="button" hx-target="closest div" hx-get={typ.url} hx-vals={typ.params|tojson}
15
- id={typ.id}
15
+ <Button type="button" hx-target="closest div" hx-get={typ.url} hx-vals={typ.params|tojson} 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" } hx-target={"#" + widget.id} hx-vals={parent_type.params|tojson}
21
- hx-get={parent_type.url} hidden={not child}>
20
+ <Button type="button" id={widget.id + "-remove-btn" } hx-target={"#" + widget.id}
21
+ hx-vals={parent_type.params|tojson} hx-get={parent_type.url} hidden={not child}>
22
22
  Remove
23
23
  </Button>
24
24
  </details>
@@ -8,11 +8,17 @@ class BooleanWidget(Widget[bool]):
8
8
  *,
9
9
  title: str | None,
10
10
  value: bool = False,
11
+ error: str | None = None,
11
12
  removable: bool = False,
12
13
  token: str,
13
14
  ) -> None:
14
15
  super().__init__(
15
- name, title=title, value=value, removable=removable, token=token
16
+ name,
17
+ title=title,
18
+ value=value,
19
+ error=error,
20
+ removable=removable,
21
+ token=token,
16
22
  )
17
23
 
18
24
  def get_template(self) -> str:
@@ -1,6 +1,6 @@
1
1
  from typing import Sequence
2
2
 
3
- from pydantic import BaseModel
3
+ from pydantic import BaseModel, Field
4
4
 
5
5
  from .base import Widget
6
6
 
@@ -11,6 +11,7 @@ class Checkable(BaseModel):
11
11
  value: str
12
12
  token: str
13
13
  checked: bool
14
+ error: str | None = Field(default=None)
14
15
 
15
16
  @property
16
17
  def id(self) -> str:
@@ -29,11 +30,17 @@ class ChecklistWidget(Widget[Sequence[Checkable]]):
29
30
  *,
30
31
  title: str | None,
31
32
  value: Sequence[Checkable],
33
+ error: str | None = None,
32
34
  token: str,
33
35
  removable: bool,
34
36
  ) -> None:
35
37
  super().__init__(
36
- name, value=value, token=token, title=title, removable=removable
38
+ name,
39
+ value=value,
40
+ error=error,
41
+ token=token,
42
+ title=title,
43
+ removable=removable,
37
44
  )
38
45
 
39
46
  def get_template(self) -> str:
@@ -10,13 +10,19 @@ class DropDownWidget(Widget[str]):
10
10
  *,
11
11
  title: Optional[str],
12
12
  value: Optional[str] = None,
13
+ error: str | None = None,
13
14
  options: Sequence[Tuple[str, str]] | Sequence[str],
14
15
  removable: bool = False,
15
16
  token: Optional[str] = None,
16
17
  hint: Optional[str] = None,
17
18
  ) -> None:
18
19
  super().__init__(
19
- name, value=value, title=title, token=token, removable=removable
20
+ name,
21
+ value=value,
22
+ error=error,
23
+ title=title,
24
+ token=token,
25
+ removable=removable,
20
26
  )
21
27
  self.options: list[dict[str, str]] = []
22
28
  for opt in options:
@@ -88,6 +88,7 @@ class WidgetFactory:
88
88
  title=field.title if field else "",
89
89
  aria_label=field.description if field else None,
90
90
  token=self.token,
91
+ error=form_errors.get(name),
91
92
  ),
92
93
  )
93
94
 
@@ -175,6 +176,7 @@ class WidgetFactory:
175
176
  removable=removable,
176
177
  title=get_title(typ),
177
178
  token=self.token,
179
+ error=form_errors.get(field_name),
178
180
  )
179
181
 
180
182
  def build_union(
@@ -233,6 +235,7 @@ class WidgetFactory:
233
235
  title=field.title if field else "",
234
236
  token=self.token,
235
237
  removable=removable,
238
+ error=form_errors.get(field_name),
236
239
  )
237
240
 
238
241
  return widget
@@ -267,6 +270,7 @@ class WidgetFactory:
267
270
  item_type=typ, # type: ignore
268
271
  token=self.token,
269
272
  removable=removable,
273
+ error=form_errors.get(field_name),
270
274
  )
271
275
 
272
276
  def build_set(
@@ -291,6 +295,7 @@ class WidgetFactory:
291
295
  checked=c in value if value else False, # type: ignore
292
296
  name=field_name,
293
297
  token=self.token,
298
+ error=form_errors.get(f"{field_name}-{c}"),
294
299
  )
295
300
  for c in litchoice
296
301
  ]
@@ -305,6 +310,7 @@ class WidgetFactory:
305
310
  checked=e.name in value if value else False, # type: ignore
306
311
  name=field_name,
307
312
  token=self.token,
313
+ error=form_errors.get(f"{field_name}-{e.name}"),
308
314
  )
309
315
  for e in choice_wrapper
310
316
  ]
@@ -317,6 +323,7 @@ class WidgetFactory:
317
323
  token=self.token,
318
324
  value=choices,
319
325
  removable=removable,
326
+ error=form_errors.get(field_name),
320
327
  )
321
328
 
322
329
  def build_boolean(
@@ -334,6 +341,7 @@ class WidgetFactory:
334
341
  title=field.title if field else "",
335
342
  token=self.token,
336
343
  value=value,
344
+ error=form_errors.get(field_name),
337
345
  )
338
346
 
339
347
  def build_emailtype(
@@ -354,6 +362,7 @@ class WidgetFactory:
354
362
  title=field.title if field else "",
355
363
  token=self.token,
356
364
  value=str(value),
365
+ error=form_errors.get(field_name),
357
366
  )
358
367
 
359
368
  def build_secretstr(
@@ -374,6 +383,7 @@ class WidgetFactory:
374
383
  title=field.title if field else "",
375
384
  token=self.token,
376
385
  value=value.get_secret_value() if isinstance(value, SecretStr) else value,
386
+ error=form_errors.get(field_name),
377
387
  )
378
388
 
379
389
  def build_literal(
@@ -399,6 +409,7 @@ class WidgetFactory:
399
409
  title=field.title if field else "",
400
410
  token=self.token,
401
411
  value=str(value),
412
+ error=form_errors.get(field_name),
402
413
  )
403
414
 
404
415
  def build_enum(
@@ -418,6 +429,7 @@ class WidgetFactory:
418
429
  title=field.title if field else "",
419
430
  token=self.token,
420
431
  value=str(value),
432
+ error=form_errors.get(field_name),
421
433
  )
422
434
 
423
435
  def build_simpletype(
@@ -13,12 +13,18 @@ class ModelWidget(Widget[Sequence[Widget[Any]]]):
13
13
  name: str,
14
14
  *,
15
15
  value: Sequence[Widget[Any]],
16
+ error: str | None = None,
16
17
  removable: bool,
17
18
  title: str,
18
19
  token: str,
19
20
  ):
20
21
  super().__init__(
21
- name, title=title, value=value, removable=removable, token=token
22
+ name,
23
+ title=title,
24
+ value=value,
25
+ error=error,
26
+ removable=removable,
27
+ token=token,
22
28
  )
23
29
 
24
30
  def get_template(self) -> str:
@@ -15,12 +15,18 @@ class SequenceWidget(Widget[Sequence[Widget[Any]]]):
15
15
  title: Optional[str],
16
16
  hint: Optional[str],
17
17
  value: Optional[Sequence[Widget[Any]]],
18
+ error: str | None = None,
18
19
  item_type: Type[Any],
19
20
  token: str,
20
21
  removable: bool,
21
22
  ):
22
23
  super().__init__(
23
- name, value=value, title=title, token=token, removable=removable
24
+ name,
25
+ value=value,
26
+ error=error,
27
+ title=title,
28
+ token=token,
29
+ removable=removable,
24
30
  )
25
31
  self.item_type = item_type
26
32
  self.hint = hint
@@ -15,12 +15,18 @@ class UnionWidget(Widget[Widget[Any]]):
15
15
  *,
16
16
  title: Optional[str],
17
17
  value: Optional[Widget[Any]],
18
+ error: str | None = None,
18
19
  children_types: Sequence[Type[BaseModel]],
19
20
  token: str,
20
21
  removable: bool,
21
22
  ):
22
23
  super().__init__(
23
- name, value=value, title=title, token=token, removable=removable
24
+ name,
25
+ value=value,
26
+ error=error,
27
+ title=title,
28
+ token=token,
29
+ removable=removable,
24
30
  )
25
31
  self.children_types = children_types
26
32
  self.parent_name = name
@@ -1,7 +0,0 @@
1
- {# def widget #}
2
- <pydantic_form.Widget widget={widget} removable={widget.removable}>
3
- <div class="pt-4">
4
- <Label for={widget.id}>{{widget.title}}</Label>
5
- <Checkbox name={widget.name} type="checkbox" id={widget.id} checked={widget.value} />
6
- </div>
7
- </pydantic_form.Widget>
File without changes
File without changes