fastlifeweb 0.27.0__py3-none-any.whl → 0.28.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.
Files changed (56) hide show
  1. CHANGELOG.md +11 -0
  2. fastlife/__init__.py +2 -1
  3. fastlife/adapters/jinjax/renderer.py +8 -0
  4. fastlife/adapters/jinjax/widgets/union.py +1 -1
  5. fastlife/adapters/xcomponent/__init__.py +1 -0
  6. fastlife/adapters/xcomponent/catalog.py +11 -0
  7. fastlife/adapters/xcomponent/html/__init__.py +7 -0
  8. fastlife/adapters/xcomponent/html/collapsible.py +76 -0
  9. fastlife/adapters/xcomponent/html/form.py +437 -0
  10. fastlife/adapters/xcomponent/html/nav.py +60 -0
  11. fastlife/adapters/xcomponent/html/table.py +130 -0
  12. fastlife/adapters/xcomponent/html/text.py +30 -0
  13. fastlife/adapters/xcomponent/html/title.py +145 -0
  14. fastlife/adapters/xcomponent/icons/__init__.py +0 -0
  15. fastlife/adapters/xcomponent/icons/icons.py +93 -0
  16. fastlife/adapters/xcomponent/pydantic_form/__init__.py +0 -0
  17. fastlife/adapters/xcomponent/pydantic_form/components.py +121 -0
  18. fastlife/adapters/xcomponent/pydantic_form/widget_factory/__init__.py +1 -0
  19. fastlife/adapters/xcomponent/pydantic_form/widget_factory/base.py +40 -0
  20. fastlife/adapters/xcomponent/pydantic_form/widget_factory/bool_builder.py +45 -0
  21. fastlife/adapters/xcomponent/pydantic_form/widget_factory/emailstr_builder.py +50 -0
  22. fastlife/adapters/xcomponent/pydantic_form/widget_factory/enum_builder.py +49 -0
  23. fastlife/adapters/xcomponent/pydantic_form/widget_factory/factory.py +188 -0
  24. fastlife/adapters/xcomponent/pydantic_form/widget_factory/literal_builder.py +55 -0
  25. fastlife/adapters/xcomponent/pydantic_form/widget_factory/model_builder.py +66 -0
  26. fastlife/adapters/xcomponent/pydantic_form/widget_factory/secretstr_builder.py +48 -0
  27. fastlife/adapters/xcomponent/pydantic_form/widget_factory/sequence_builder.py +60 -0
  28. fastlife/adapters/xcomponent/pydantic_form/widget_factory/set_builder.py +85 -0
  29. fastlife/adapters/xcomponent/pydantic_form/widget_factory/simpletype_builder.py +48 -0
  30. fastlife/adapters/xcomponent/pydantic_form/widget_factory/union_builder.py +92 -0
  31. fastlife/adapters/xcomponent/pydantic_form/widgets/__init__.py +1 -0
  32. fastlife/adapters/xcomponent/pydantic_form/widgets/base.py +140 -0
  33. fastlife/adapters/xcomponent/pydantic_form/widgets/boolean.py +25 -0
  34. fastlife/adapters/xcomponent/pydantic_form/widgets/checklist.py +75 -0
  35. fastlife/adapters/xcomponent/pydantic_form/widgets/dropdown.py +72 -0
  36. fastlife/adapters/xcomponent/pydantic_form/widgets/hidden.py +25 -0
  37. fastlife/adapters/xcomponent/pydantic_form/widgets/mfa_code.py +25 -0
  38. fastlife/adapters/xcomponent/pydantic_form/widgets/model.py +49 -0
  39. fastlife/adapters/xcomponent/pydantic_form/widgets/sequence.py +74 -0
  40. fastlife/adapters/xcomponent/pydantic_form/widgets/text.py +121 -0
  41. fastlife/adapters/xcomponent/pydantic_form/widgets/union.py +81 -0
  42. fastlife/adapters/xcomponent/renderer.py +130 -0
  43. fastlife/assets/dist.css +4 -1
  44. fastlife/components/A.jinja +5 -1
  45. fastlife/config/configurator.py +7 -8
  46. fastlife/config/resources.py +9 -3
  47. fastlife/domain/model/template.py +6 -0
  48. fastlife/service/csrf.py +1 -1
  49. fastlife/service/templates.py +44 -2
  50. fastlife/template_globals.py +3 -0
  51. fastlife/views/pydantic_form.py +9 -9
  52. {fastlifeweb-0.27.0.dist-info → fastlifeweb-0.28.0.dist-info}/METADATA +6 -3
  53. {fastlifeweb-0.27.0.dist-info → fastlifeweb-0.28.0.dist-info}/RECORD +56 -18
  54. {fastlifeweb-0.27.0.dist-info → fastlifeweb-0.28.0.dist-info}/WHEEL +1 -1
  55. {fastlifeweb-0.27.0.dist-info → fastlifeweb-0.28.0.dist-info}/entry_points.txt +0 -0
  56. {fastlifeweb-0.27.0.dist-info → fastlifeweb-0.28.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,130 @@
1
+ """
2
+ Template renderer based on XComponent.
3
+
4
+ More template engine can be registered using the configurator method
5
+ {meth}`add_renderer <fastlife.config.configurator.GenericConfigurator.add_renderer>`
6
+ """
7
+
8
+ from typing import Any
9
+
10
+ from markupsafe import Markup
11
+ from pydantic.fields import FieldInfo
12
+
13
+ from fastlife import Request
14
+ from fastlife.adapters.xcomponent.pydantic_form.widget_factory.factory import (
15
+ WidgetFactory,
16
+ )
17
+ from fastlife.config import Configurator, configure
18
+ from fastlife.domain.model.form import FormModel
19
+ from fastlife.domain.model.template import InlineTemplate
20
+ from fastlife.service.templates import (
21
+ AbstractTemplateRenderer,
22
+ AbstractTemplateRendererFactory,
23
+ )
24
+ from fastlife.settings import Settings
25
+ from fastlife.shared_utils.resolver import resolve
26
+
27
+ from .catalog import catalog
28
+
29
+
30
+ class XTemplateRenderer(AbstractTemplateRenderer):
31
+ """
32
+ An object that will be initialized by an AbstractTemplateRendererFactory,
33
+ passing the request to process.
34
+ """
35
+
36
+ request: Request
37
+ """Associated request that needs a response."""
38
+
39
+ def __init__(self, globals: dict[str, Any], request: Request) -> None:
40
+ self.request = request
41
+ self.globals: dict[str, Any] = {**globals}
42
+ self.globals["pydantic_form"] = self.pydantic_form
43
+
44
+ def pydantic_form(
45
+ self, model: FormModel[Any], *, token: str | None = None
46
+ ) -> Markup:
47
+ """
48
+ Generate HTML markup to build a form from the given form model.
49
+
50
+ :param model: the form model that will be transformed to markup.
51
+ :param token: a token used to ensure that unique identifier are unique.
52
+ :return: HTML Markup generated by composign fields widgets.
53
+ """
54
+ return WidgetFactory(self, token).get_markup(model)
55
+
56
+ def pydantic_form_field(
57
+ self,
58
+ model: type[Any],
59
+ *,
60
+ name: str | None,
61
+ token: str | None,
62
+ removable: bool,
63
+ field: FieldInfo | None,
64
+ ) -> Markup:
65
+ """
66
+ Generate HTML for a particular field in a form.
67
+
68
+ This function is used to generate union subtypes in Ajax requests.
69
+ :param model: a pydantic or python builtin type that is requests to be rendered
70
+ :param name: name for the field
71
+ :param token: the token of the form to render unique identifiers
72
+ :param removable: add a way let the user remove the widget
73
+ :param field: only render this particular field for the model.
74
+ :return: HTML Markup.
75
+ """
76
+ return (
77
+ WidgetFactory(self, token)
78
+ .get_widget(
79
+ model,
80
+ form_data={},
81
+ form_errors={},
82
+ prefix=(name or self.request.registry.settings.form_data_model_prefix),
83
+ removable=removable,
84
+ field=field,
85
+ )
86
+ .to_html(self)
87
+ )
88
+
89
+ @property
90
+ def route_prefix(self) -> str:
91
+ """Used to buid pydantic form widget that do ajax requests."""
92
+ return self.request.registry.settings.fastlife_route_prefix
93
+
94
+ def render_template(self, template: InlineTemplate) -> str:
95
+ """
96
+ Render an inline template.
97
+
98
+ :param template: the template to render.
99
+ :return: The template rendering result.
100
+ """
101
+ params = template.model_dump()
102
+ return catalog.render(
103
+ template.template,
104
+ globals=self.globals,
105
+ **params,
106
+ )
107
+
108
+
109
+ class XRendererFactory(AbstractTemplateRendererFactory):
110
+ """
111
+ The template render factory.
112
+ """
113
+
114
+ def __init__(self, settings: "Settings") -> None:
115
+ self.globals = resolve(settings.jinjax_global_catalog_class)().model_dump()
116
+
117
+ def __call__(self, request: Request) -> AbstractTemplateRenderer:
118
+ """
119
+ While processing an HTTP Request, a renderer object is created giving
120
+ isolated context per request.
121
+
122
+ :param Request: the HTTP Request to process.
123
+ :return: The renderer object that will process that request.
124
+ """
125
+ return XTemplateRenderer(globals=self.globals, request=request)
126
+
127
+
128
+ @configure
129
+ def includeme(conf: Configurator) -> None:
130
+ conf.add_renderer("xcomponent", XRendererFactory(conf.registry.settings))
fastlife/assets/dist.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! tailwindcss v4.1.4 | MIT License | https://tailwindcss.com */
1
+ /*! tailwindcss v4.1.11 | MIT License | https://tailwindcss.com */
2
2
  @layer properties;
3
3
  @layer theme, base, components, utilities;
4
4
  @layer theme {
@@ -288,6 +288,9 @@
288
288
  .cursor-pointer {
289
289
  cursor: pointer;
290
290
  }
291
+ .appearance-none {
292
+ appearance: none;
293
+ }
291
294
  .items-center {
292
295
  align-items: center;
293
296
  }
@@ -20,13 +20,17 @@
20
20
  "specify how the response will be swapped in relative to the target of an AJAX request."
21
21
  ] = "innerHTML show:body:top",
22
22
  hx_push_url: Annotated[bool, "replace the browser url with the link."] = True,
23
+ hx_get: Annotated[
24
+ str | None,
25
+ "Override the target link only for htmx request for component rendering. href will be used if None."
26
+ ] = None,
23
27
  disable_htmx: Annotated[bool, "do not add any `hx-*` attibute to the link."] = False
24
28
  #}
25
29
 
26
30
  <a href="{{href}}"
27
31
  {%- if id %} id="{{ id }}" {%- endif %}
28
32
  {%- if not disable_htmx %}
29
- hx-get="{{ href }}"
33
+ hx-get="{{ hx_get or href }}"
30
34
  hx-target="{{ hx_target }}"
31
35
  hx-swap="{{ hx_swap }}"
32
36
  {%- if hx_push_url %} hx-push-url="true" {%- endif %}
@@ -178,12 +178,11 @@ class GenericConfigurator(Generic[TRegistry]):
178
178
 
179
179
  # register our main template renderer at then end, to ensure that
180
180
  # if settings have been manipulated, everything is taken into account.
181
- self.add_renderer(
182
- self.registry.settings.jinjax_file_ext,
183
- resolve("fastlife.adapters.jinjax.renderer:JinjaxEngine")(
184
- self.registry.settings
185
- ),
186
- )
181
+ for optional_adapter in ("jinjax", "xcomponent"):
182
+ try:
183
+ self.include(f"fastlife.adapters.{optional_adapter}")
184
+ except ImportError:
185
+ pass
187
186
 
188
187
  app = FastAPI(
189
188
  title=self.api_title,
@@ -368,7 +367,7 @@ class GenericConfigurator(Generic[TRegistry]):
368
367
  deprecated: bool | None = None,
369
368
  methods: list[str] | None = None,
370
369
  operation_id: str | None = None,
371
- # response_model: Any = Default(None),
370
+ response_model: Any = None,
372
371
  response_model_include: IncEx | None = None,
373
372
  response_model_exclude: IncEx | None = None,
374
373
  response_model_by_alias: bool = True,
@@ -433,7 +432,7 @@ class GenericConfigurator(Generic[TRegistry]):
433
432
  self._current_router.add_api_route(
434
433
  path,
435
434
  endpoint,
436
- # response_model=response_model,
435
+ response_model=response_model,
437
436
  status_code=status_code,
438
437
  tags=tags,
439
438
  dependencies=dependencies,
@@ -99,6 +99,7 @@ def resource(
99
99
  response_description=endpoint.response_description,
100
100
  deprecated=endpoint.deprecated,
101
101
  operation_id=endpoint.operation_id,
102
+ response_model=endpoint.response_model,
102
103
  response_model_include=endpoint.response_model_include,
103
104
  response_model_exclude=endpoint.response_model_exclude,
104
105
  response_model_by_alias=endpoint.response_model_by_alias,
@@ -146,6 +147,7 @@ def resource_view(
146
147
  deprecated: bool | None = None,
147
148
  methods: list[str] | None = None,
148
149
  operation_id: str | None = None,
150
+ response_model: type[Any] | None = None,
149
151
  response_model_include: IncEx | None = None,
150
152
  response_model_exclude: IncEx | None = None,
151
153
  response_model_by_alias: bool = True,
@@ -155,7 +157,7 @@ def resource_view(
155
157
  include_in_schema: bool = True,
156
158
  openapi_extra: dict[str, Any] | None = None,
157
159
  ) -> Callable[..., Any]:
158
- """ "
160
+ """
159
161
  Decorator to use on a method of a class decorated with {func}`resource` in order
160
162
  to add OpenAPI information.
161
163
 
@@ -177,8 +179,11 @@ def resource_view(
177
179
  :param include_in_schema: Expose or not the route in the OpenAPI schema and
178
180
  documentation.
179
181
 
180
- :param response_model_include: customize fields list to include in repsonse.
181
- :param response_model_exclude: customize fields list to exclude in repsonse.
182
+ :param response_model: class used for the api documentation for streaming response.
183
+ It may also be used to validate data in case the view return dict.
184
+ See [FastAPI doc](https://fastapi.tiangolo.com/tutorial/response-model/).
185
+ :param response_model_include: customize fields list to include in response.
186
+ :param response_model_exclude: customize fields list to exclude in response.
182
187
  :param response_model_by_alias: serialize fields by alias or by name if False.
183
188
  :param response_model_exclude_unset: exclude fields that are not explicitly
184
189
  set in response.
@@ -197,6 +202,7 @@ def resource_view(
197
202
  fn.deprecated = deprecated
198
203
  fn.methods = methods
199
204
  fn.operation_id = operation_id
205
+ fn.response_model = response_model
200
206
  fn.response_model_include = response_model_include
201
207
  fn.response_model_exclude = response_model_exclude
202
208
  fn.response_model_by_alias = response_model_by_alias
@@ -28,3 +28,9 @@ class JinjaXTemplate(InlineTemplate):
28
28
  """Template that render JinjaX"""
29
29
 
30
30
  renderer = ".jinja"
31
+
32
+
33
+ class XTemplate(InlineTemplate):
34
+ """Template that render XComponent"""
35
+
36
+ renderer = ".xcomponent"
fastlife/service/csrf.py CHANGED
@@ -11,7 +11,7 @@ to process the request, otherwise an exception
11
11
  The cookie named is configurabllefia the settings
12
12
  :attr:`fastlife.config.settings.Settings.csrf_token_name`
13
13
 
14
- While using the `<Form/>` JinjaX tag, the csrf token is always sent.
14
+ While using the `<Form/>` from XComponent or JinjaX, the csrf token is always sent.
15
15
 
16
16
  The cookie is always set when you render any template. At the moment, there is
17
17
  no way to prevent to set the cookie in the request.
@@ -1,8 +1,12 @@
1
1
  """
2
2
  Base class to of the template renderer.
3
3
 
4
- Fastlife comes with {class}`fastlife.adapters.jinjax.renderer.JinjaxEngine`,
5
- the rendering engine.
4
+ Fastlife comes with two rendering engines:
5
+ {class}`fastlife.adapters.jinjax.renderer.JinjaxEngine`,
6
+ and {class}`fastlife.adapters.xcomponent.renderer.XRendererFactory`,
7
+ they have to be installed using python packaging extra syntax for your tool,
8
+ fastlifeweb[jinjax] or fastlifeweb[xcomponent] since those engine are not
9
+ installed by default.
6
10
 
7
11
  More template engine can be registered using the configurator method
8
12
  {meth}`add_renderer <fastlife.config.configurator.GenericConfigurator.add_renderer>`
@@ -12,7 +16,11 @@ import abc
12
16
  from collections.abc import Mapping
13
17
  from typing import Any
14
18
 
19
+ from markupsafe import Markup
20
+ from pydantic.fields import FieldInfo
21
+
15
22
  from fastlife import Request, Response
23
+ from fastlife.adapters.fastapi.form import FormModel
16
24
  from fastlife.domain.model.template import InlineTemplate
17
25
 
18
26
 
@@ -72,6 +80,40 @@ class AbstractTemplateRenderer(abc.ABC):
72
80
  :return: The template rendering result.
73
81
  """
74
82
 
83
+ @abc.abstractmethod
84
+ def pydantic_form(
85
+ self, model: FormModel[Any], *, token: str | None = None
86
+ ) -> Markup:
87
+ """
88
+ Generate HTML markup to build a form from the given form model.
89
+
90
+ :param model: the form model that will be transformed to markup.
91
+ :param token: a token used to ensure that unique identifier are unique.
92
+ :return: HTML Markup generated by composign fields widgets.
93
+ """
94
+
95
+ @abc.abstractmethod
96
+ def pydantic_form_field(
97
+ self,
98
+ model: type[Any],
99
+ *,
100
+ name: str | None,
101
+ token: str | None,
102
+ removable: bool,
103
+ field: FieldInfo | None,
104
+ ) -> Markup:
105
+ """
106
+ Generate HTML for a particular field in a form.
107
+
108
+ This function is used to generate union subtypes in Ajax requests.
109
+ :param model: a pydantic or python builtin type that is requests to be rendered
110
+ :param name: name for the field
111
+ :param token: the token of the form to render unique identifiers
112
+ :param removable: add a way let the user remove the widget
113
+ :param field: only render this particular field for the model.
114
+ :return: HTML Markup.
115
+ """
116
+
75
117
 
76
118
  class AbstractTemplateRendererFactory(abc.ABC):
77
119
  """
@@ -29,6 +29,7 @@ class Globals(BaseModel):
29
29
  """Default css class for {jinjax:component}`A`."""
30
30
 
31
31
  BUTTON_CLASS: str = space_join(
32
+ "appearance-none",
32
33
  "bg-primary-600",
33
34
  "px-5",
34
35
  "py-2.5",
@@ -52,6 +53,7 @@ class Globals(BaseModel):
52
53
  """Default css class for {jinjax:component}`Details`."""
53
54
 
54
55
  SECONDARY_BUTTON_CLASS: str = space_join(
56
+ "appearance-none",
55
57
  "bg-neutral-300",
56
58
  "px-5",
57
59
  "py-2.5",
@@ -79,6 +81,7 @@ class Globals(BaseModel):
79
81
  """
80
82
 
81
83
  ICON_BUTTON_CLASS: str = space_join(
84
+ "appearance-none",
82
85
  "bg-white",
83
86
  "p-1",
84
87
  "rounded-xs",
@@ -4,13 +4,12 @@ Views for pydantic form.
4
4
  Pydantic form generate form that may contains fields that requires some ajax query.
5
5
  """
6
6
 
7
- from typing import cast
7
+ from typing import Literal
8
8
 
9
9
  from fastapi import Query
10
10
  from pydantic.fields import FieldInfo
11
11
 
12
12
  from fastlife import Configurator, Request, Response, configure
13
- from fastlife.adapters.jinjax.renderer import JinjaxRenderer
14
13
  from fastlife.shared_utils.resolver import resolve_extended
15
14
 
16
15
 
@@ -20,6 +19,7 @@ async def show_widget(
20
19
  title: str | None = Query(None),
21
20
  name: str | None = Query(None),
22
21
  token: str | None = Query(None),
22
+ format: Literal["jinjax", "xcomponent"] | str = Query("jinjax"),
23
23
  removable: bool = Query(False),
24
24
  ) -> Response:
25
25
  """
@@ -29,14 +29,14 @@ async def show_widget(
29
29
  field = None
30
30
  if title:
31
31
  field = FieldInfo(title=title)
32
- # FIXME: .jinja should not be hardcoded
33
- renderer = cast(JinjaxRenderer, request.registry.get_renderer(".jinja")(request))
32
+
33
+ if format == "jinjax":
34
+ # XXX
35
+ format = request.registry.settings.jinjax_file_ext
36
+ rndr = request.registry.get_renderer(f".{format}")(request)
34
37
  lczr = request.registry.localizer(request.locale_name)
35
- renderer.globals = {
36
- "request": request,
37
- **lczr.as_dict(),
38
- }
39
- data = renderer.pydantic_form_field(
38
+ rndr.globals.update({"request": request, **lczr.as_dict()})
39
+ data = rndr.pydantic_form_field(
40
40
  model=model_cls, # type: ignore
41
41
  name=name,
42
42
  token=token,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastlifeweb
3
- Version: 0.27.0
3
+ Version: 0.28.0
4
4
  Summary: High-level web framework
5
5
  Author-Email: Guillaume Gauvrit <guillaume@gauvr.it>
6
6
  License: MIT
@@ -19,13 +19,16 @@ Project-URL: Changelog, https://mardiros.github.io/fastlife/user/changelog.html
19
19
  Requires-Python: >=3.11
20
20
  Requires-Dist: fastapi[standard]<0.116.0,>=0.115.4
21
21
  Requires-Dist: itsdangerous<3,>=2.1.2
22
- Requires-Dist: jinjax<0.49,>=0.48
23
22
  Requires-Dist: markupsafe<3,>=2.1.3
24
23
  Requires-Dist: multidict<7,>=6.0.5
25
24
  Requires-Dist: pydantic<3,>=2.5.3
26
25
  Requires-Dist: pydantic-settings<3,>=2.0.3
27
26
  Requires-Dist: python-multipart<1,>=0.0.13
28
27
  Requires-Dist: venusian<4,>=3.0.0
28
+ Provides-Extra: jinjax
29
+ Requires-Dist: jinjax<0.49,>=0.48; extra == "jinjax"
30
+ Provides-Extra: xcomponent
31
+ Requires-Dist: xcomponent<0.7,>=0.6.6; extra == "xcomponent"
29
32
  Provides-Extra: testing
30
33
  Requires-Dist: beautifulsoup4; extra == "testing"
31
34
  Provides-Extra: docs
@@ -77,7 +80,7 @@ to maintain and scale your project.
77
80
 
78
81
  ## Tests
79
82
 
80
- Fastlife come with [a test client](https://mardiros.github.io/fastlife/develop/fastlife/fastlife.testing.testclient.html) that can interact with html inside unit tests.
83
+ Fastlife comes with [a test client](https://mardiros.github.io/fastlife/develop/fastlife/fastlife.testing.testclient.html) that can interact with html inside unit tests.
81
84
 
82
85
 
83
86
  ## Try it
@@ -1,5 +1,5 @@
1
- CHANGELOG.md,sha256=SaMUOfsgJvjHaEzgvgmtggz0FY0YEqltXogCMACKrvc,8904
2
- fastlife/__init__.py,sha256=Fe8JiQyKIN1WGagUGFct-QBW8-Ku5vXhc_7BkFUGcWk,2475
1
+ CHANGELOG.md,sha256=4y91GixHED3CEyv7z4Y4RrdnQORgWX41F-dqyQH0I68,9426
2
+ fastlife/__init__.py,sha256=XtGrcI5a3MPSl4vupeWT4ZijISiXtAhjcL6eRt9WpfE,2503
3
3
  fastlife/adapters/__init__.py,sha256=imPD1hImpgrYkvUJRhHA5kVyGAua7VbP2WGkhSWKJT8,93
4
4
  fastlife/adapters/fastapi/__init__.py,sha256=1goV1FGFP04TGyskJBLKZam4Gvt1yoAvLMNs4ekWSSQ,243
5
5
  fastlife/adapters/fastapi/form.py,sha256=csxsDI6RK-g41pMwFhaVQCLDhF7dAZzgUp-VcrC3NFY,823
@@ -17,7 +17,7 @@ fastlife/adapters/jinjax/jinjax_ext/docstring.py,sha256=Zlx0oSxsRU9vQvGoyScXf9uB
17
17
  fastlife/adapters/jinjax/jinjax_ext/inspectable_catalog.py,sha256=KHOYTT6UNA41QwyLNQVoG4trOVXYdChlRmqq_G1pv1s,2987
18
18
  fastlife/adapters/jinjax/jinjax_ext/inspectable_component.py,sha256=Ye_0XIKPC2H2XAvqEc1Er3YWyvNyYS4chuVkTSY5bAk,2909
19
19
  fastlife/adapters/jinjax/jinjax_ext/jinjax_doc.py,sha256=S4-JNQ2NehUdKkc6mzAWRE_oyuw3XYPkR53RArgpDFk,10218
20
- fastlife/adapters/jinjax/renderer.py,sha256=8Pv2Ivg8iObPa-LeIfj764p2MEq78wzHqxZeLDIdLc8,5255
20
+ fastlife/adapters/jinjax/renderer.py,sha256=bCY_NBM2YbgaTPk62K20x1t38wRFBWUZo8oQ0ng4D7c,5477
21
21
  fastlife/adapters/jinjax/widget_factory/__init__.py,sha256=Dy_2xr_YDAyEF9WtNpjV-aYaehRO1iKEIHVFdfFeszw,59
22
22
  fastlife/adapters/jinjax/widget_factory/base.py,sha256=TLEpYdekR4AeHhIie_DICc_oSvQaUaL8GlatqNiRewg,1046
23
23
  fastlife/adapters/jinjax/widget_factory/bool_builder.py,sha256=ElIDb6rlUiwuDAetC22TreoMa9HDgoZ2euVV1VurFFY,1291
@@ -41,10 +41,48 @@ fastlife/adapters/jinjax/widgets/mfa_code.py,sha256=dI0CKlx2jCwujfnud_uIjnBCHvlG
41
41
  fastlife/adapters/jinjax/widgets/model.py,sha256=STojkUMfCP1kyPFzzWS-MIZOoxAEFHTIW_jxFnODPb4,1309
42
42
  fastlife/adapters/jinjax/widgets/sequence.py,sha256=aL93-ytj6nlbT8vumt3br6Jq8D97iiCXU3eQXrGYuG0,2577
43
43
  fastlife/adapters/jinjax/widgets/text.py,sha256=XKpoLoBNsvQhHrezKCEcXlF9iQzuclXGaeFu6uq9_5A,3390
44
- fastlife/adapters/jinjax/widgets/union.py,sha256=fNWmAXNEPkDbP14q6HmlD65L7q5_JmspZ_IG_SqB_NM,2624
45
- fastlife/assets/dist.css,sha256=d2ez-igscOaeYtJQc2FQuXlN17cYX13sUansFdg_kdA,19753
44
+ fastlife/adapters/jinjax/widgets/union.py,sha256=tSbiylgBOcvQl3b3SVoXRsdpVqvxVpQAlLuMk1EjTTc,2630
45
+ fastlife/adapters/xcomponent/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
46
+ fastlife/adapters/xcomponent/catalog.py,sha256=i-_HUmAXgtDCl7uHB6EBGncAlt8qtiYEo_zCbeQsnZs,209
47
+ fastlife/adapters/xcomponent/html/__init__.py,sha256=MliLg_8CfMP63GWnRWkia2J_xfBDY5Cr6qO5875IqCE,250
48
+ fastlife/adapters/xcomponent/html/collapsible.py,sha256=9H8JvTHvg-oJGfmk327xp2MzGKDKQDo6ZbzhDQhBcTI,2191
49
+ fastlife/adapters/xcomponent/html/form.py,sha256=TD_cvET1FYqEOJTCED0LMGm25CvZRr48w0_rvEa1oT0,11546
50
+ fastlife/adapters/xcomponent/html/nav.py,sha256=k3IlsBPny7kMlgG0ZHx3I2KVQRQs2PW0OMZvqHcQXNo,1940
51
+ fastlife/adapters/xcomponent/html/table.py,sha256=f-Lir3XxOQUVlUWfSXlPoKwSZ3nROhDqcrEN_g0TMbA,2678
52
+ fastlife/adapters/xcomponent/html/text.py,sha256=Qv1mJx1_xoAZpojiEDfKjrkOBHTa2dQo1J-l4Qpwe_E,699
53
+ fastlife/adapters/xcomponent/html/title.py,sha256=2-n4cs37medT6ovrw1-pUlNRxE3SzZNaDFo0VB5t2OM,3564
54
+ fastlife/adapters/xcomponent/icons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
+ fastlife/adapters/xcomponent/icons/icons.py,sha256=WViJhYBtpej7fs3dwbSo66s5M24bCy0qDLBrPbCjFxI,2402
56
+ fastlife/adapters/xcomponent/pydantic_form/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
+ fastlife/adapters/xcomponent/pydantic_form/components.py,sha256=tfkgWc97atVY27UFMjC50G-FqueoeQINgEmmiVlS4oA,2781
58
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/__init__.py,sha256=Dy_2xr_YDAyEF9WtNpjV-aYaehRO1iKEIHVFdfFeszw,59
59
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/base.py,sha256=iKqYXpKZubdxEh0NJJUDEY9ZZu2XqsZdyWNZ43BtS5Q,1025
60
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/bool_builder.py,sha256=nE8Q2kaYhLyTTPFn7Hi8vSTotGLdmKthM_ryzTiBiIY,1336
61
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/emailstr_builder.py,sha256=9RDlB-Lvmwp0h5XNW-dnb6rDPwx2MabrguQJ2Dtfveg,1611
62
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/enum_builder.py,sha256=wZRODjXX_LAEWbkA61XxtALctw1t94CjEDb52hJ4av0,1590
63
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/factory.py,sha256=V8QBKnz_Bx-7L5B9V0nbYPXFrFXbD4VjeSKPOt-Hg2o,6138
64
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/literal_builder.py,sha256=7_nv3vtnVxKYAuPp2CJVWQvvZLf_NJYZ4qS2l-oqJQg,1821
65
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/model_builder.py,sha256=AgT7dRzu5COns6iUBpDvz2Fq8Ob48fT0aNT-9ozQlkE,2299
66
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/secretstr_builder.py,sha256=TbeYqeHXlSQY2H5B6JsiOmdsT9202ICa4DEvQu_5btE,1627
67
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/sequence_builder.py,sha256=mpdol0o2RnNRUyIUvdkyWsX-EdnGAvxxTBuT6gpY4lw,2007
68
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/set_builder.py,sha256=4Zn9pK8vFmyVN2x6Ur5vG40L_gGFDvrwAc2KDv9RB7E,2818
69
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/simpletype_builder.py,sha256=ADQH1YogP5NHkWPoqi7aTWICAVZ33m8Q1i_dx4w4nx8,1633
70
+ fastlife/adapters/xcomponent/pydantic_form/widget_factory/union_builder.py,sha256=bRxEF75S3In2vGnHxcONEjUGeVt_5c_6CP11WOfXP4Y,2904
71
+ fastlife/adapters/xcomponent/pydantic_form/widgets/__init__.py,sha256=HERnX9xiXUbTDz3XtlnHWABTBjhIq_kkBgWs5E6ZIMY,42
72
+ fastlife/adapters/xcomponent/pydantic_form/widgets/base.py,sha256=iHcZb_9-qTiVGUiRS9aYHrQPlqcws05LMTnQlE8qIBM,4128
73
+ fastlife/adapters/xcomponent/pydantic_form/widgets/boolean.py,sha256=MVPehGxij8o1rul5cr4d4YIdtBu3tpT4Pj0jgcIFUws,586
74
+ fastlife/adapters/xcomponent/pydantic_form/widgets/checklist.py,sha256=G_1beOKHmlETg2zvAGt6zmYEqFRs2Rf9iFSPjWdtWfA,1896
75
+ fastlife/adapters/xcomponent/pydantic_form/widgets/dropdown.py,sha256=YdTGDyXVj5YxCtsO0h_c9qBnK5K6fQYzcQZ0lUIV6no,1760
76
+ fastlife/adapters/xcomponent/pydantic_form/widgets/hidden.py,sha256=p5Bun1ETOEIALjitE5TD3Ad4KfUihEIVSFNgYAkQ2zA,671
77
+ fastlife/adapters/xcomponent/pydantic_form/widgets/mfa_code.py,sha256=beQ58s47FP194MTf_9dEPtM0ELJSoin54valVbpb-vo,686
78
+ fastlife/adapters/xcomponent/pydantic_form/widgets/model.py,sha256=HnZyDVyfW0s-u9VsoWGimCQGtzzHNmbV2U042n2PEFg,1350
79
+ fastlife/adapters/xcomponent/pydantic_form/widgets/sequence.py,sha256=ANilerP-RfOO5nakIpuhmG1levPlO8O8ge-786qkGcw,2551
80
+ fastlife/adapters/xcomponent/pydantic_form/widgets/text.py,sha256=_cms11Ir_onCORmdrW_N5ZeLb-0hCM2fIwWdR_uLXQU,3513
81
+ fastlife/adapters/xcomponent/pydantic_form/widgets/union.py,sha256=MlmfEsAx9vZdtZMNSILdAV5cq5R_yzbLLppT1NE675E,2646
82
+ fastlife/adapters/xcomponent/renderer.py,sha256=zLwWpoE0OPjvBtaIRGWxMwQqxVrL0kITQBUjDaqkanI,4243
83
+ fastlife/assets/dist.css,sha256=xuD2jjSO5GMCjyr_rmhcazJQ5wQpcYUvFxKm0RcC1XY,19801
46
84
  fastlife/assets/source.css,sha256=0KtDcsKHj9LOcqNR1iv9pACwNBaNWkieEDqqjkgNL_s,47
47
- fastlife/components/A.jinja,sha256=MDNJ2auIeYbpNeErvJdlGid4nIKfbi85ArmMgChsCJU,1384
85
+ fastlife/components/A.jinja,sha256=hTZeYWXKLgnqPucSrF2IY7TDP4d_xNfU2Rjl-bXnpGc,1548
48
86
  fastlife/components/Button.jinja,sha256=itKU-ct45XissU33yfmTekyHsNe00fr4RQL-e9cxbgU,2305
49
87
  fastlife/components/Checkbox.jinja,sha256=g62A1LR8TaN60h94pE2e5l9_eMmgnhVVE9HVCQtVVMo,748
50
88
  fastlife/components/CsrfToken.jinja,sha256=mS0q-3_hAevl_waWEPaN0QAYOBzMyzl-W1PSpEHUBA0,215
@@ -1690,10 +1728,10 @@ fastlife/components/pydantic_form/FatalError.jinja,sha256=ADtQvmo-e-NmDcFM1E6wZV
1690
1728
  fastlife/components/pydantic_form/Hint.jinja,sha256=8leBpfMGDmalc_KAjr2paTojr_rwq-luS6m_1BGj7Tw,202
1691
1729
  fastlife/components/pydantic_form/Widget.jinja,sha256=PgguUpvhG6CY9AW6H8qQMjKqjlybjDCAaFFAOHzrzVQ,418
1692
1730
  fastlife/config/__init__.py,sha256=5qpuaVYqi-AS0GgsfggM6rFsSwXgrqrLBo9jH6dVroc,407
1693
- fastlife/config/configurator.py,sha256=82YEVRoI6VoyFPIbkWgnqlLIVNSVP9TUkbKl6qksWs8,24898
1731
+ fastlife/config/configurator.py,sha256=yhwI6rDMFud931NoxyCR5muHRdnsBt-DZJXEkXsAODw,24869
1694
1732
  fastlife/config/exceptions.py,sha256=9MdBnbfy-Aw-KaIFzju0Kh8Snk41-v9LqK2w48Tdy1s,1169
1695
1733
  fastlife/config/openapiextra.py,sha256=rYoerrn9sni2XwnO3gIWqaz7M0aDZPhVLjzqhDxue0o,514
1696
- fastlife/config/resources.py,sha256=EcPTM25pnHcGFTtXjeZnWn5Mo_-8rhJ72HJ6rxnjPg8,8389
1734
+ fastlife/config/resources.py,sha256=stKCuZQGgiDW9xTrTNxKMb_JzkgkM1Ubum1b7OK4Lm4,8780
1697
1735
  fastlife/config/views.py,sha256=9CZ0qNi8vKvQuGo1GgM6cwNK8WwHOxwIHqtikAOaOHY,2399
1698
1736
  fastlife/domain/__init__.py,sha256=3zDDos5InVX0el9OO0lgSDGzdUNYIhlA6w4uhBh2pF8,29
1699
1737
  fastlife/domain/model/__init__.py,sha256=aoBjaSpDscuFXvtknJHwiNyoJRUpE-v4X54h_wNuo2Y,27
@@ -1703,7 +1741,7 @@ fastlife/domain/model/form.py,sha256=JP6uumlZBYhiPxzcdxOsfsFm5BRfvkDFvlUCD6Vy8dI
1703
1741
  fastlife/domain/model/request.py,sha256=hHtGsfVND3TSG7HQZI_I0n4Gp4KyaAtsjaZEc4lwrv0,3090
1704
1742
  fastlife/domain/model/response.py,sha256=Vsd2zYGGhH0D2DlfiKz1CX9OJZ_ZYoEv_-foMZpDFZo,1294
1705
1743
  fastlife/domain/model/security_policy.py,sha256=f9SLi54vvRU-KSPJ5K0unoqYpkxIyzuZjKf2Ylwf5Rg,4796
1706
- fastlife/domain/model/template.py,sha256=z9oxdKme1hMPuvk7mBiKR_tuVY8TqH77aTYqMgvEGl8,876
1744
+ fastlife/domain/model/template.py,sha256=xpvWb_EMdAbdx5VIG7DDjmDZMXbF7DUs0INlXvzN_wY,983
1707
1745
  fastlife/domain/model/types.py,sha256=64jJKFAi5x0e3vr8naHU1m_as0Qy8MS-s9CG0z6K1qc,381
1708
1746
  fastlife/middlewares/__init__.py,sha256=C3DUOzR5EhlAv5Zq7h-Abyvkd7bUsJohTRSB2wpRYQE,220
1709
1747
  fastlife/middlewares/base.py,sha256=7FZE_1YU7wNew2u1qdYXjamosk4CXJmg1mJWGp6Xhc0,649
@@ -1715,27 +1753,27 @@ fastlife/middlewares/session/serializer.py,sha256=nbJGiCJ_ryZxkW1I28kmK6hD3U98D4
1715
1753
  fastlife/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1716
1754
  fastlife/service/__init__.py,sha256=SfM2eSrMjDx6safjBc2LVFty4Wy2H1ZsHQSHeDcZ7dU,31
1717
1755
  fastlife/service/check_permission.py,sha256=WodiDVTnY-dZmTfbQV-YmJfPOLtE07mfqvG6jvL0xeA,1828
1718
- fastlife/service/csrf.py,sha256=wC1PaKOmZ3il0FF_kevxnlg9PxDqruRdLrNnOA3ZHrU,1886
1756
+ fastlife/service/csrf.py,sha256=hxcn4IMXLnxUVGtXHCqy5dm3APY0K8sZo-7NLrSkghc,1901
1719
1757
  fastlife/service/locale_negociator.py,sha256=4HifgNkyI7DxR3_IdSUMG0UUY-JZeQsJ_MMSqiyFzgc,730
1720
1758
  fastlife/service/registry.py,sha256=0r8dVCF44JUugRctL9sDQjnHDV7SepH06OfkV6KE-4s,2937
1721
1759
  fastlife/service/request_factory.py,sha256=9o4B_78qrKPXQAq8A_RDhzAqCHdt6arV96Bq_JByyIM,931
1722
1760
  fastlife/service/security_policy.py,sha256=qYXs4mhfz_u4x59NhUkirqKYKQbFv9YrzyRuXj7mxE0,4688
1723
- fastlife/service/templates.py,sha256=xNMKH-jNkEoCscO04H-QlzTqg-0pYbF_fc65xG-2rzs,2575
1761
+ fastlife/service/templates.py,sha256=MkH-fRYBYmb6kgtnmuUmhCHrYXxsvRynjyI8QVyj8OA,4146
1724
1762
  fastlife/service/translations.py,sha256=UrkITvfdfw68GzWn_uFlCjjhRvwhc0aCJPnEr_Y1rK8,7151
1725
1763
  fastlife/settings.py,sha256=q-rz4CEF2RQGow5-m-yZJOvdh3PPb2c1Q_ZLJGnu4VQ,3647
1726
1764
  fastlife/shared_utils/__init__.py,sha256=i66ytuf-Ezo7jSiNQHIsBMVIcB-tDX0tg28-pUOlhzE,26
1727
1765
  fastlife/shared_utils/infer.py,sha256=0GflLkaWJ-4LZ1Ig3moR-_o55wwJ_p_vJ4xo-yi3lyA,1406
1728
1766
  fastlife/shared_utils/resolver.py,sha256=Wb9cO2MWavpti63hju15xmwFMgaD5DsQaxikRpB39E8,3713
1729
- fastlife/template_globals.py,sha256=bKcj6kSnQlzuOeoILA5oRxxzy6CsrBFMZv9S0w5XlTQ,9021
1767
+ fastlife/template_globals.py,sha256=pn2fWRE5QwYii4K0XJtfCt1hUmN8VvXXwAOWSwRFe94,9102
1730
1768
  fastlife/testing/__init__.py,sha256=VpxkS3Zp3t_hH8dBiLaGFGhsvt511dhBS_8fMoFXdmU,99
1731
1769
  fastlife/testing/dom.py,sha256=q2GFrHWjwKMMTR0dsP3J-rXSxojZy8rOQ-07h2gfLKA,5869
1732
1770
  fastlife/testing/form.py,sha256=diiGfVMfNt19JTNUxlnbGfcbskR3ZMpk0Y-A57vfShc,7871
1733
1771
  fastlife/testing/session.py,sha256=LEFFbiR67_x_g-ioudkY0C7PycHdbDfaIaoo_G7GXQ8,2226
1734
1772
  fastlife/testing/testclient.py,sha256=gqgHQalhrLLZ8eveN2HeuoG9ne8CwxCm-Ll4b7jo9Xo,7249
1735
1773
  fastlife/views/__init__.py,sha256=zG8gveL8e2zBdYx6_9jtZfpQ6qJT-MFnBY3xXkLwHZI,22
1736
- fastlife/views/pydantic_form.py,sha256=M4uGP-QiDuSyrkYAsvSVJYZzdBUPOmCghQdwtR28K5E,1630
1737
- fastlifeweb-0.27.0.dist-info/METADATA,sha256=5cvmsfd1YF7lhRZtH53Ip9Qxd7EwE54AQK4pFV2IChI,3690
1738
- fastlifeweb-0.27.0.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
1739
- fastlifeweb-0.27.0.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
1740
- fastlifeweb-0.27.0.dist-info/licenses/LICENSE,sha256=JFWuiKYRXKKMEAsX0aZp3hBcju-HYflJ2rwJAGwbCJo,1080
1741
- fastlifeweb-0.27.0.dist-info/RECORD,,
1774
+ fastlife/views/pydantic_form.py,sha256=9lcS14jxddIpoN_n4VqWwU8CKhKZ8AtoD3c1Pdc-Oe4,1651
1775
+ fastlifeweb-0.28.0.dist-info/METADATA,sha256=gPnwO8lHfw5Lz0qY7hm83yc5LiuEMQxZ7C2FRMW2VUk,3821
1776
+ fastlifeweb-0.28.0.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
1777
+ fastlifeweb-0.28.0.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
1778
+ fastlifeweb-0.28.0.dist-info/licenses/LICENSE,sha256=JFWuiKYRXKKMEAsX0aZp3hBcju-HYflJ2rwJAGwbCJo,1080
1779
+ fastlifeweb-0.28.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: pdm-backend (2.4.4)
2
+ Generator: pdm-backend (2.4.5)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any