fastlifeweb 0.20.1__py3-none-any.whl → 0.22.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 (93) hide show
  1. CHANGELOG.md +18 -1
  2. fastlife/__init__.py +45 -13
  3. fastlife/adapters/__init__.py +1 -1
  4. fastlife/adapters/fastapi/__init__.py +9 -0
  5. fastlife/adapters/fastapi/form.py +26 -0
  6. fastlife/{request → adapters/fastapi}/form_data.py +1 -1
  7. fastlife/{request → adapters/fastapi}/localizer.py +4 -2
  8. fastlife/adapters/fastapi/request.py +33 -0
  9. fastlife/{routing → adapters/fastapi/routing}/route.py +3 -3
  10. fastlife/{routing → adapters/fastapi/routing}/router.py +1 -1
  11. fastlife/adapters/itsdangerous/__init__.py +3 -0
  12. fastlife/adapters/itsdangerous/session.py +50 -0
  13. fastlife/adapters/jinjax/jinjax_ext/inspectable_component.py +7 -7
  14. fastlife/adapters/jinjax/jinjax_ext/jinjax_doc.py +1 -1
  15. fastlife/adapters/jinjax/renderer.py +9 -57
  16. fastlife/adapters/jinjax/widget_factory/bool_builder.py +2 -2
  17. fastlife/adapters/jinjax/widget_factory/emailstr_builder.py +5 -4
  18. fastlife/adapters/jinjax/widget_factory/enum_builder.py +2 -2
  19. fastlife/adapters/jinjax/widget_factory/factory.py +32 -23
  20. fastlife/adapters/jinjax/widget_factory/literal_builder.py +7 -6
  21. fastlife/adapters/jinjax/widget_factory/model_builder.py +3 -3
  22. fastlife/adapters/jinjax/widget_factory/secretstr_builder.py +2 -2
  23. fastlife/adapters/jinjax/widget_factory/sequence_builder.py +3 -3
  24. fastlife/adapters/jinjax/widget_factory/set_builder.py +2 -2
  25. fastlife/adapters/jinjax/widget_factory/simpletype_builder.py +7 -8
  26. fastlife/adapters/jinjax/widget_factory/union_builder.py +3 -3
  27. fastlife/adapters/jinjax/widgets/base.py +36 -36
  28. fastlife/adapters/jinjax/widgets/boolean.py +13 -34
  29. fastlife/adapters/jinjax/widgets/checklist.py +36 -42
  30. fastlife/adapters/jinjax/widgets/dropdown.py +32 -38
  31. fastlife/adapters/jinjax/widgets/hidden.py +7 -15
  32. fastlife/adapters/jinjax/widgets/model.py +36 -43
  33. fastlife/adapters/jinjax/widgets/sequence.py +63 -42
  34. fastlife/adapters/jinjax/widgets/text.py +39 -78
  35. fastlife/adapters/jinjax/widgets/union.py +51 -58
  36. fastlife/components/CsrfToken.jinja +1 -1
  37. fastlife/components/Form.jinja +1 -1
  38. fastlife/components/pydantic_form/FatalError.jinja +8 -0
  39. fastlife/components/pydantic_form/Widget.jinja +4 -3
  40. fastlife/config/__init__.py +3 -6
  41. fastlife/config/configurator.py +80 -32
  42. fastlife/config/exceptions.py +0 -2
  43. fastlife/config/resources.py +1 -2
  44. fastlife/config/views.py +2 -4
  45. fastlife/domain/__init__.py +1 -0
  46. fastlife/domain/model/__init__.py +1 -0
  47. fastlife/domain/model/asgi.py +3 -0
  48. fastlife/domain/model/csrf.py +19 -0
  49. fastlife/{request → domain/model}/form.py +13 -22
  50. fastlife/{request → domain/model}/request.py +26 -30
  51. fastlife/domain/model/security_policy.py +105 -0
  52. fastlife/{templates/inline.py → domain/model/template.py} +8 -0
  53. fastlife/domain/model/types.py +17 -0
  54. fastlife/middlewares/base.py +1 -1
  55. fastlife/middlewares/reverse_proxy/x_forwarded.py +1 -2
  56. fastlife/middlewares/session/__init__.py +2 -2
  57. fastlife/middlewares/session/middleware.py +4 -3
  58. fastlife/middlewares/session/serializer.py +0 -44
  59. fastlife/{services/policy.py → service/check_permission.py} +1 -1
  60. fastlife/{security → service}/csrf.py +5 -15
  61. fastlife/{services → service}/locale_negociator.py +5 -8
  62. fastlife/{config → service}/registry.py +13 -7
  63. fastlife/service/security_policy.py +100 -0
  64. fastlife/{services → service}/templates.py +10 -48
  65. fastlife/{services → service}/translations.py +15 -0
  66. fastlife/{config/settings.py → settings.py} +6 -12
  67. fastlife/shared_utils/infer.py +24 -1
  68. fastlife/{templates/constants.py → template_globals.py} +2 -2
  69. fastlife/testing/testclient.py +2 -2
  70. fastlife/views/__init__.py +1 -0
  71. fastlife/views/pydantic_form.py +6 -0
  72. {fastlifeweb-0.20.1.dist-info → fastlifeweb-0.22.0.dist-info}/METADATA +1 -1
  73. {fastlifeweb-0.20.1.dist-info → fastlifeweb-0.22.0.dist-info}/RECORD +79 -80
  74. tailwind.config.js +1 -1
  75. fastlife/components/pydantic_form/Boolean.jinja +0 -13
  76. fastlife/components/pydantic_form/Checklist.jinja +0 -21
  77. fastlife/components/pydantic_form/Dropdown.jinja +0 -18
  78. fastlife/components/pydantic_form/Hidden.jinja +0 -3
  79. fastlife/components/pydantic_form/Model.jinja +0 -30
  80. fastlife/components/pydantic_form/Sequence.jinja +0 -47
  81. fastlife/components/pydantic_form/Text.jinja +0 -11
  82. fastlife/components/pydantic_form/Textarea.jinja +0 -38
  83. fastlife/components/pydantic_form/Union.jinja +0 -34
  84. fastlife/request/__init__.py +0 -5
  85. fastlife/security/__init__.py +0 -1
  86. fastlife/security/policy.py +0 -188
  87. fastlife/templates/__init__.py +0 -12
  88. fastlife/templates/binding.py +0 -52
  89. /fastlife/{routing → adapters/fastapi/routing}/__init__.py +0 -0
  90. /fastlife/{services → service}/__init__.py +0 -0
  91. {fastlifeweb-0.20.1.dist-info → fastlifeweb-0.22.0.dist-info}/WHEEL +0 -0
  92. {fastlifeweb-0.20.1.dist-info → fastlifeweb-0.22.0.dist-info}/entry_points.txt +0 -0
  93. {fastlifeweb-0.20.1.dist-info → fastlifeweb-0.22.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,100 @@
1
+ """Security policy."""
2
+
3
+ import abc
4
+ from typing import Annotated, Any, Generic
5
+ from uuid import UUID
6
+
7
+ from fastapi import Depends
8
+
9
+ from fastlife import GenericRequest, get_request
10
+ from fastlife.domain.model.security_policy import (
11
+ Allowed,
12
+ Forbidden,
13
+ HasPermission,
14
+ TUser,
15
+ Unauthorized,
16
+ )
17
+ from fastlife.service.registry import TRegistry
18
+
19
+
20
+ class AbstractSecurityPolicy(abc.ABC, Generic[TUser, TRegistry]):
21
+ """Security policy base class."""
22
+
23
+ Forbidden = Forbidden
24
+ """The exception raised if the user identified is not granted."""
25
+ Unauthorized = Unauthorized
26
+ """The exception raised if no user has been identified."""
27
+
28
+ request: GenericRequest[TRegistry]
29
+ """Request where the security policy is applied."""
30
+
31
+ def __init__(
32
+ self, request: Annotated[GenericRequest[TRegistry], Depends(get_request)]
33
+ ):
34
+ """
35
+ Build the security policy.
36
+
37
+ When implementing a security policy, multiple parameters can be added
38
+ to the constructor as FastAPI dependencies, using the `Depends` FastAPI
39
+ annotation.
40
+ The security policy is installed has a depenency of the router that hold
41
+ a route prefix of the application.
42
+ """
43
+ self.request = request
44
+ self.request.security_policy = self # we do backref to implement has_permission
45
+
46
+ @abc.abstractmethod
47
+ async def identity(self) -> TUser | None:
48
+ """
49
+ Return app-specific user object or raise an HTTPException.
50
+ """
51
+
52
+ @abc.abstractmethod
53
+ async def authenticated_userid(self) -> str | UUID | None:
54
+ """
55
+ Return app-specific user object or raise an HTTPException.
56
+ """
57
+
58
+ @abc.abstractmethod
59
+ async def has_permission(
60
+ self, permission: str
61
+ ) -> HasPermission | type[HasPermission]:
62
+ """Allow access to everything if signed in."""
63
+
64
+ @abc.abstractmethod
65
+ async def remember(self, user: TUser) -> None:
66
+ """Save the user identity in the request session."""
67
+
68
+ @abc.abstractmethod
69
+ async def forget(self) -> None:
70
+ """Destroy the request session."""
71
+
72
+
73
+ class InsecurePolicy(AbstractSecurityPolicy[None, Any]):
74
+ """
75
+ An implementation of the security policy made for explicit unsecured access.
76
+
77
+ Setting a permission on a view require a security policy, if not set, accessing
78
+ to a view will raise a RuntimeError. To bypass this error for testing purpose
79
+ or your own reason, the InsecurePolicy has to be set to the configurator.
80
+ """
81
+
82
+ async def identity(self) -> None:
83
+ """Nobodies is identified."""
84
+ return None
85
+
86
+ async def authenticated_userid(self) -> str | UUID:
87
+ """An uuid mades of 0."""
88
+ return UUID(int=0)
89
+
90
+ async def has_permission(
91
+ self, permission: str
92
+ ) -> HasPermission | type[HasPermission]:
93
+ """Access is allways granted."""
94
+ return Allowed
95
+
96
+ async def remember(self, user: None) -> None:
97
+ """Do nothing."""
98
+
99
+ async def forget(self) -> None:
100
+ """Do nothing."""
@@ -9,14 +9,11 @@ More template engine can be registered using the configurator method
9
9
  """
10
10
 
11
11
  import abc
12
- from collections.abc import Callable, Mapping
12
+ from collections.abc import Mapping
13
13
  from typing import Any
14
14
 
15
15
  from fastlife import Request, Response
16
- from fastlife.security.csrf import create_csrf_token
17
- from fastlife.templates.inline import InlineTemplate
18
-
19
- TemplateParams = Mapping[str, Any]
16
+ from fastlife.domain.model.template import InlineTemplate
20
17
 
21
18
 
22
19
  class AbstractTemplateRenderer(abc.ABC):
@@ -30,6 +27,7 @@ class AbstractTemplateRenderer(abc.ABC):
30
27
 
31
28
  def __init__(self, request: Request) -> None:
32
29
  self.request = request
30
+ self.globals: dict[str, Any] = {}
33
31
 
34
32
  @property
35
33
  def route_prefix(self) -> str:
@@ -43,27 +41,21 @@ class AbstractTemplateRenderer(abc.ABC):
43
41
  status_code: int = 200,
44
42
  content_type: str = "text/html",
45
43
  globals: Mapping[str, Any] | None = None,
46
- params: TemplateParams | InlineTemplate,
47
- _create_csrf_token: Callable[..., str] = create_csrf_token,
44
+ params: InlineTemplate,
48
45
  ) -> Response:
49
46
  """
50
47
  Render the template and build the HTTP Response.
51
48
  """
52
49
  request = self.request
53
- reg = request.registry
54
- request.scope[reg.settings.csrf_token_name] = (
55
- request.cookies.get(reg.settings.csrf_token_name) or _create_csrf_token()
56
- )
57
- if isinstance(params, InlineTemplate):
58
- data = self.render_inline(params)
59
- else:
60
- data = self.render_template(template, **params)
50
+ if globals:
51
+ self.globals.update(globals)
52
+ data = self.render_template(params)
61
53
  resp = Response(
62
54
  data, status_code=status_code, headers={"Content-Type": content_type}
63
55
  )
64
56
  resp.set_cookie(
65
- reg.settings.csrf_token_name,
66
- request.scope[reg.settings.csrf_token_name],
57
+ request.csrf_token.name,
58
+ request.csrf_token.value,
67
59
  secure=request.url.scheme == "https",
68
60
  samesite="strict",
69
61
  max_age=60 * 15,
@@ -71,34 +63,7 @@ class AbstractTemplateRenderer(abc.ABC):
71
63
  return resp
72
64
 
73
65
  @abc.abstractmethod
74
- def render_template(
75
- self,
76
- template: str,
77
- *,
78
- globals: Mapping[str, Any] | None = None,
79
- **params: Any,
80
- ) -> str:
81
- """
82
- Render the given template with the given params.
83
-
84
- While rendering templates, the globals parameter is keps by the instantiated
85
- renderer and sent to every rendering made by the request.
86
- This is used by the pydantic form method that will render other templates
87
- for the request.
88
- In traditional frameworks, only one template is rendered containing the whole
89
- pages. But, while rendering a pydantic form, every field is rendered in its
90
- distinct template. The template renderer keep the globals and git it back
91
- to every templates. This can be used to fillout options in a select without
92
- performing an ajax request for example.
93
-
94
- :param template: name of the template to render.
95
- :param globals: some variable that will be passed to all rendered templates.
96
- :param params: paramaters that are limited to the main rendered templates.
97
- :return: The template rendering result.
98
- """
99
-
100
- @abc.abstractmethod
101
- def render_inline(self, template: InlineTemplate) -> str:
66
+ def render_template(self, template: InlineTemplate) -> str:
102
67
  """
103
68
  Render an inline template.
104
69
 
@@ -110,9 +75,6 @@ class AbstractTemplateRenderer(abc.ABC):
110
75
  class AbstractTemplateRendererFactory(abc.ABC):
111
76
  """
112
77
  The template render factory.
113
-
114
- The implementation of this class is found using the settings
115
- :attr:`fastlife.config.settings.Settings.template_renderer_class`.
116
78
  """
117
79
 
118
80
  @abc.abstractmethod
@@ -64,6 +64,9 @@ class Localizer:
64
64
  self.translations[domain].merge(trans)
65
65
  self.global_translations.merge(trans)
66
66
 
67
+ def __call__(self, message: str, mapping: dict[str, str] | None = None) -> str:
68
+ return self.gettext(message, mapping)
69
+
67
70
  def gettext(self, message: str, mapping: dict[str, str] | None = None) -> str:
68
71
  ret = self.global_translations.gettext(message)
69
72
  if mapping:
@@ -117,6 +120,18 @@ class Localizer:
117
120
  ret = ret.format(**mapping)
118
121
  return ret
119
122
 
123
+ def npgettext(
124
+ self,
125
+ context: str,
126
+ singular: str,
127
+ plural: str,
128
+ n: int,
129
+ mapping: dict[str, str] | None = None,
130
+ ) -> str:
131
+ ret = self.global_translations.npgettext(context, singular, plural, n)
132
+ mapping_num = {"num": n, **(mapping or {})}
133
+ return ret.format(**mapping_num)
134
+
120
135
  def dnpgettext(
121
136
  self,
122
137
  domain: str,
@@ -29,15 +29,9 @@ class Settings(BaseSettings):
29
29
  a python module name. for instance `fastlife:components` is the directory components
30
30
  found in the fastlife package.
31
31
  """
32
- registry_class: str = Field(default="fastlife.config.registry:DefaultRegistry")
32
+ registry_class: str = Field(default="fastlife.service.registry:DefaultRegistry")
33
33
  """Implementation class for the application regitry."""
34
- template_renderer_class: str = Field(
35
- default="fastlife.templates.renderer:JinjaxEngine"
36
- )
37
- """
38
- Implementation class for the
39
- {class}`fastlife.templates.renderer.AbstractTemplateRenderer`.
40
- """
34
+
41
35
  form_data_model_prefix: str = Field(default="payload")
42
36
  """
43
37
  Pydantic form default model prefix for serialized field in www-urlencoded-form.
@@ -70,12 +64,12 @@ class Settings(BaseSettings):
70
64
  Set to true while developing, set false for production.
71
65
  """
72
66
  jinjax_global_catalog_class: str = Field(
73
- default="fastlife.templates.constants:Constants"
67
+ default="fastlife.template_globals:Globals"
74
68
  )
75
69
  """
76
70
  Set global constants accessible in every templates.
77
- Defaults to `fastlife.templates.constants:Constants`
78
- See {class}`fastlife.templates.constants.Constants`
71
+ Defaults to `fastlife.template_globals:Globals`
72
+ See {class}`fastlife.template_globals.Globals`
79
73
  """
80
74
 
81
75
  session_secret_key: str = Field(default="")
@@ -101,7 +95,7 @@ class Settings(BaseSettings):
101
95
  should be true while using https on production.
102
96
  """
103
97
  session_serializer: str = Field(
104
- default="fastlife.middlewares.session.serializer:SignedSessionSerializer"
98
+ default="fastlife.adapters.itsdangerous:SignedSessionSerializer"
105
99
  )
106
100
  """Cookie serializer for the session cookie."""
107
101
 
@@ -1,10 +1,14 @@
1
1
  """Type inference."""
2
2
 
3
+ import inspect
4
+ from collections.abc import Callable
3
5
  from types import UnionType
4
- from typing import Any, Union, get_origin
6
+ from typing import Any, Union, get_args, get_origin
5
7
 
6
8
  from pydantic import BaseModel
7
9
 
10
+ from fastlife.domain.model.template import InlineTemplate
11
+
8
12
 
9
13
  def is_complex_type(typ: type[Any]) -> bool:
10
14
  """
@@ -25,3 +29,22 @@ def is_union(typ: type[Any]) -> bool:
25
29
  if type_origin is UnionType: # T | U
26
30
  return True
27
31
  return False
32
+
33
+
34
+ def is_inline_template_returned(endpoint: Callable[..., Any]) -> bool:
35
+ """Test if a view, the endpoint return a template."""
36
+ signature = inspect.signature(endpoint)
37
+ return_annotation = signature.return_annotation
38
+
39
+ if isinstance(return_annotation, type) and issubclass(
40
+ return_annotation, InlineTemplate
41
+ ):
42
+ return True
43
+
44
+ if is_union(return_annotation):
45
+ return any(
46
+ isinstance(arg, type) and issubclass(arg, InlineTemplate)
47
+ for arg in get_args(return_annotation)
48
+ )
49
+
50
+ return False
@@ -16,7 +16,7 @@ def space_join(*segments: str) -> str:
16
16
  return " ".join(segments)
17
17
 
18
18
 
19
- class Constants(BaseModel):
19
+ class Globals(BaseModel):
20
20
  """Templates constants."""
21
21
 
22
22
  A_CLASS: str = space_join(
@@ -315,7 +315,7 @@ class Constants(BaseModel):
315
315
  SUMMARY_CLASS: str = "flex items-center items-center font-medium cursor-pointer"
316
316
  """Default css class for {jinjax:component}`Summary`."""
317
317
 
318
- TABLE_CLASS: str = "table-auto w-full text-left border-colapse"
318
+ TABLE_CLASS: str = "table-auto w-full text-left border-collapse"
319
319
  """Default css class for {jinjax:component}`Table`."""
320
320
 
321
321
  TD_CLASS: str = "px-4 py-2 font-normal border-b dark:border-neutral-500"
@@ -8,10 +8,10 @@ import bs4
8
8
  import httpx
9
9
  from fastapi.testclient import TestClient
10
10
  from multidict import MultiDict
11
- from starlette.types import ASGIApp
12
11
 
13
- from fastlife.config.settings import Settings
12
+ from fastlife.domain.model.asgi import ASGIApp
14
13
  from fastlife.middlewares.session.serializer import AbsractSessionSerializer
14
+ from fastlife.settings import Settings
15
15
  from fastlife.shared_utils.resolver import resolve
16
16
  from fastlife.testing.dom import Element
17
17
  from fastlife.testing.form import WebForm
@@ -0,0 +1 @@
1
+ """Fastlife views."""
@@ -1,3 +1,9 @@
1
+ """
2
+ Views for pydantic form.
3
+
4
+ Pydantic form generate form that may contains fields that requires some ajax query.
5
+ """
6
+
1
7
  from typing import cast
2
8
 
3
9
  from fastapi import Query
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastlifeweb
3
- Version: 0.20.1
3
+ Version: 0.22.0
4
4
  Summary: High-level web framework
5
5
  Author-Email: Guillaume Gauvrit <guillaume@gauvr.it>
6
6
  License: MIT License
@@ -1,42 +1,52 @@
1
- CHANGELOG.md,sha256=TigqTUTKqu3-oT4WGKkwO84U-SP7PpdzfaEE8C4eMd8,6032
2
- fastlife/__init__.py,sha256=l8SVz6RNy8QJNKFwUx9OHt-V21r9yeKK8pLuUY1u4ps,799
3
- fastlife/adapters/__init__.py,sha256=WYjEN8gp4r7LCHqmIO5VzzvsT8QGRE3w4G47UwYDtAo,94
1
+ CHANGELOG.md,sha256=gtRawAWGc5B7HSVjRWA2eng5K_1jDm-AZrioc2niKWw,6987
2
+ fastlife/__init__.py,sha256=vccDwPrkKjB4N-yBdqWN5fCaUJzUnFyNAE35pcIz9kU,1664
3
+ fastlife/adapters/__init__.py,sha256=imPD1hImpgrYkvUJRhHA5kVyGAua7VbP2WGkhSWKJT8,93
4
+ fastlife/adapters/fastapi/__init__.py,sha256=1goV1FGFP04TGyskJBLKZam4Gvt1yoAvLMNs4ekWSSQ,243
5
+ fastlife/adapters/fastapi/form.py,sha256=csxsDI6RK-g41pMwFhaVQCLDhF7dAZzgUp-VcrC3NFY,823
6
+ fastlife/adapters/fastapi/form_data.py,sha256=2DQ0o-RvY6iROUKQjS-UJdNYEVSsNPd-AjpergI3w54,4473
7
+ fastlife/adapters/fastapi/localizer.py,sha256=XD1kCJuAlkGevivmvAJEcGMCBWMef9rAfTOGmt3PVWU,436
8
+ fastlife/adapters/fastapi/request.py,sha256=oyAZ1QKW2mh-9CadQdOdn_BqnVVjaZ6aG4eTNK2R2j0,1095
9
+ fastlife/adapters/fastapi/routing/__init__.py,sha256=8EMnQE5n8oA4J9_c3nxzwKDVt3tefZ6fGH0d2owE8mo,195
10
+ fastlife/adapters/fastapi/routing/route.py,sha256=g-MlXFvyRzVsNO_bBYDQQHD03fmRXEOm9KHxIHFZmug,1461
11
+ fastlife/adapters/fastapi/routing/router.py,sha256=jzrnU_Lyywu21e3spPaWQw8ujZh_Yy_EJOojcCi6ew4,499
12
+ fastlife/adapters/itsdangerous/__init__.py,sha256=7ocGY7v0cxooZBKQYjA2JkmzRqiBvcU1uzA84UsTVAI,84
13
+ fastlife/adapters/itsdangerous/session.py,sha256=9h_WRsXqZbytHZOv5B_K3OWD5mbfYzxHulXoOf6D2MI,1685
4
14
  fastlife/adapters/jinjax/__init__.py,sha256=4JRAUwFGpTxYtRlg5sU79AahxyAiRMhllRFHoI-dnug,117
5
15
  fastlife/adapters/jinjax/jinjax_ext/__init__.py,sha256=z6NWvHzTNEq6bVO4iJoTR6-y4A6UtS_VuSMV_tff1jY,49
6
16
  fastlife/adapters/jinjax/jinjax_ext/docstring.py,sha256=Zlx0oSxsRU9vQvGoyScXf9uB1W8JaoreGoJK3Xi26RE,2791
7
17
  fastlife/adapters/jinjax/jinjax_ext/inspectable_catalog.py,sha256=KHOYTT6UNA41QwyLNQVoG4trOVXYdChlRmqq_G1pv1s,2987
8
- fastlife/adapters/jinjax/jinjax_ext/inspectable_component.py,sha256=Cz6PrRhO3lXUI9baxosOr6MtZFjuOki9YTEWMkfbbR0,2909
9
- fastlife/adapters/jinjax/jinjax_ext/jinjax_doc.py,sha256=uPcYiUTrliR2lLpRuQUrirmFzTEVRTwo1mUZE4Z5onc,10225
10
- fastlife/adapters/jinjax/renderer.py,sha256=6HjngkDNWUTlR_ST3v_WDu8KD4PJnniK74eQl_RXdzU,6866
18
+ fastlife/adapters/jinjax/jinjax_ext/inspectable_component.py,sha256=Ye_0XIKPC2H2XAvqEc1Er3YWyvNyYS4chuVkTSY5bAk,2909
19
+ fastlife/adapters/jinjax/jinjax_ext/jinjax_doc.py,sha256=S4-JNQ2NehUdKkc6mzAWRE_oyuw3XYPkR53RArgpDFk,10218
20
+ fastlife/adapters/jinjax/renderer.py,sha256=8Pv2Ivg8iObPa-LeIfj764p2MEq78wzHqxZeLDIdLc8,5255
11
21
  fastlife/adapters/jinjax/widget_factory/__init__.py,sha256=Dy_2xr_YDAyEF9WtNpjV-aYaehRO1iKEIHVFdfFeszw,59
12
22
  fastlife/adapters/jinjax/widget_factory/base.py,sha256=TLEpYdekR4AeHhIie_DICc_oSvQaUaL8GlatqNiRewg,1046
13
- fastlife/adapters/jinjax/widget_factory/bool_builder.py,sha256=2-Hv5w4hfBfGWGetb00I8Lm1FDAputH2MNt3tCx-RbA,1280
14
- fastlife/adapters/jinjax/widget_factory/emailstr_builder.py,sha256=GjRCT_kq9D6ZSu_Qs7ef2nj8gfaZMT0J-SpEj6NZWOg,1472
15
- fastlife/adapters/jinjax/widget_factory/enum_builder.py,sha256=xMZpxik9zmpZbMTcldOHQRXYscNO-9YlcduY3GpFEQI,1516
16
- fastlife/adapters/jinjax/widget_factory/factory.py,sha256=tD4RrOgWLqD1_R2ZVHiKDOdPCV5JDN3e6SgpklehBhQ,5649
17
- fastlife/adapters/jinjax/widget_factory/literal_builder.py,sha256=mk8cmXDah_WRpy6wTRA6_du7UV6vxHoDb9ujgAAxH44,1677
18
- fastlife/adapters/jinjax/widget_factory/model_builder.py,sha256=cqrb7zkJHy0r4angYRYnz5hyHx99EL4MbNl-sS6qq8I,2220
19
- fastlife/adapters/jinjax/widget_factory/secretstr_builder.py,sha256=DrFXJeoajai7r1qfq8kBavdoo33-9DImmM4u8l_MKfQ,1562
20
- fastlife/adapters/jinjax/widget_factory/sequence_builder.py,sha256=97aJ4K_pm1zDr_xNYUoO9UeziRT4VeFKIdkZ1gAcjdM,1928
21
- fastlife/adapters/jinjax/widget_factory/set_builder.py,sha256=Qulao7i7pJNF1ZRzFdpJ-onQ2faW8IjACOi2sZyoYzA,2731
22
- fastlife/adapters/jinjax/widget_factory/simpletype_builder.py,sha256=OFkbF_5_9DP56VQLXRXGi6_cm_6JmFgCzdCblnBb1aE,1670
23
- fastlife/adapters/jinjax/widget_factory/union_builder.py,sha256=-FlqGejzfEiyKb8vgSaMbECr8libC4BprK6F2OA_12M,2825
23
+ fastlife/adapters/jinjax/widget_factory/bool_builder.py,sha256=ElIDb6rlUiwuDAetC22TreoMa9HDgoZ2euVV1VurFFY,1291
24
+ fastlife/adapters/jinjax/widget_factory/emailstr_builder.py,sha256=hO0_4yd0lZ8mLqAzM_FMecdtkSa03AIG13cvs6K9JPA,1532
25
+ fastlife/adapters/jinjax/widget_factory/enum_builder.py,sha256=agx67oUeVy5_BKzY4WV0DxT67R43Vy74CoeHl9PBvK4,1527
26
+ fastlife/adapters/jinjax/widget_factory/factory.py,sha256=zTa6zbpW5lAh_eHlhO6XBP2GbeDTHatymhMAJQ-alTI,5915
27
+ fastlife/adapters/jinjax/widget_factory/literal_builder.py,sha256=mrtWbDMKNFtw5ufJK3DnkkttGGk16EnDQhejyOd57Ys,1758
28
+ fastlife/adapters/jinjax/widget_factory/model_builder.py,sha256=WgIEUExtGO_s9AlNQlaTG_136ipe64MIJsNP0nlnsOc,2236
29
+ fastlife/adapters/jinjax/widget_factory/secretstr_builder.py,sha256=JJLqN74tUSTDDBYcRLDuqOLSL0P16S1Fp-SqTCdjjgg,1573
30
+ fastlife/adapters/jinjax/widget_factory/sequence_builder.py,sha256=j5KRfK5R8q_QdzGqjG86mjoKTWH7gvhjXesFAoItPaU,1944
31
+ fastlife/adapters/jinjax/widget_factory/set_builder.py,sha256=kwtVLATkoOFTcKBKHk7xZwQxRomPCic0sp4Bsd8YQfM,2742
32
+ fastlife/adapters/jinjax/widget_factory/simpletype_builder.py,sha256=olP66B9AMY1X8fgEAxhMdozWN_w1TtcIAIW6uPJRSng,1570
33
+ fastlife/adapters/jinjax/widget_factory/union_builder.py,sha256=qQOK3Y4I0Tg0XOzU_DwseaaKRmqQ7ORMfFyIHd6oysU,2841
24
34
  fastlife/adapters/jinjax/widgets/__init__.py,sha256=HERnX9xiXUbTDz3XtlnHWABTBjhIq_kkBgWs5E6ZIMY,42
25
- fastlife/adapters/jinjax/widgets/base.py,sha256=3bBThRMnsdCi6Q_Dm73ep5pNOqgpSXsvAIBbHshfY7I,4037
26
- fastlife/adapters/jinjax/widgets/boolean.py,sha256=w4hZMo_8xDoThStlIUR4eVfLm8JwUp0-TaGCjGSyCbA,1145
27
- fastlife/adapters/jinjax/widgets/checklist.py,sha256=8fgOrdxy1xpyQ6p3_mbRMd2vx6EU2WT5jI7QF27Y5EQ,1664
28
- fastlife/adapters/jinjax/widgets/dropdown.py,sha256=3Kc7i0z-7d6HrQchSHFCO5-xOh3bSEePo_pjXrIkvSE,1599
29
- fastlife/adapters/jinjax/widgets/hidden.py,sha256=ZOJoUwMMgyabTFII38lnr8QRgVo370Go0VZ4qhEW1zc,720
30
- fastlife/adapters/jinjax/widgets/model.py,sha256=t9A3C8wcptxvf7Mlrx9mUraxnG2p_39CrGnRq71t-A0,1322
31
- fastlife/adapters/jinjax/widgets/sequence.py,sha256=60rgz4LgE_TQQwajiZhn6EhY-s-HXOiIdQiQoKlUCvQ,1533
32
- fastlife/adapters/jinjax/widgets/text.py,sha256=KtUieF-q_BigG5AcL-4Sdr6LrIOQdWPwlaVW-2p-KPQ,3205
33
- fastlife/adapters/jinjax/widgets/union.py,sha256=CO6Q4_U8DieVsS5NzMp6TAbVXrBljfcjSARycEKYPDY,2540
35
+ fastlife/adapters/jinjax/widgets/base.py,sha256=jU-oklWuM6MPlNzBvYO0HtxUrUteb-Dh96OudPLFJx4,4120
36
+ fastlife/adapters/jinjax/widgets/boolean.py,sha256=GFvyO2Lz-vTJ8lpX2UrkJk7ymu0vU-xnBBEmyBKamJg,613
37
+ fastlife/adapters/jinjax/widgets/checklist.py,sha256=xsr_edMu1nTcNnMEs1AAS3U-ugK95pEqn5NV5hjTeI0,1747
38
+ fastlife/adapters/jinjax/widgets/dropdown.py,sha256=ou8U48txShr8IXdwF4_pBvTn1VcR9SazZKzbLcsN3_0,1458
39
+ fastlife/adapters/jinjax/widgets/hidden.py,sha256=IKcVYs6NjN8YjW-UTr3DRBong6Wrc0QLgcp8U9JoQmE,638
40
+ fastlife/adapters/jinjax/widgets/model.py,sha256=YBIEWa_6mnmrBnesXjLTrpJ4drUS2CIorNmhK24cz7Q,1298
41
+ fastlife/adapters/jinjax/widgets/sequence.py,sha256=XhIPRJyE9UXFetlDQA83N64kKlTqkj6WPcgPm6XF7mo,2559
42
+ fastlife/adapters/jinjax/widgets/text.py,sha256=uYdJ1bjA3-2vEumh2nnd264wAaHU758ZxEiN2BaqtcE,2143
43
+ fastlife/adapters/jinjax/widgets/union.py,sha256=roCoFA82dLjF1XFW6UYaV7SCQWdFsSAT8Ux7KEB6_Us,2602
34
44
  fastlife/components/A.jinja,sha256=rjnOFNpM2SUeJ0P8FDe3jzc_1WlsL65Kv-tb6KMCEpw,1389
35
45
  fastlife/components/Button.jinja,sha256=COtCjDpzGLNqtBUYsHw7gdUay4kff3KdLJFAzrEnMmo,2310
36
46
  fastlife/components/Checkbox.jinja,sha256=47_E9uPdr3QKUvRVhNQA7VE0uh5FVslQM26cdF0WCtY,753
37
- fastlife/components/CsrfToken.jinja,sha256=ftqhcMibf1G8pbGCytlUcj5LGEmD8QJKwVKTro5w-ns,199
47
+ fastlife/components/CsrfToken.jinja,sha256=mS0q-3_hAevl_waWEPaN0QAYOBzMyzl-W1PSpEHUBA0,215
38
48
  fastlife/components/Details.jinja,sha256=BKyhSU7bZdbd_deTjmAGcMbgUoQW3h8JSR3thH-2oJA,741
39
- fastlife/components/Form.jinja,sha256=Wb0nK5xuhqhkuQll9j76i3nBJcYCIjXG9RE9nWeoPZc,2095
49
+ fastlife/components/Form.jinja,sha256=Aukx9cVR8Af1nIsdHst3Qk7Bz34g1RpDhl7WOIcy0Tg,2094
40
50
  fastlife/components/H1.jinja,sha256=ODwQMgwtuy2E2ShgamjFDlnCwOQQuuLIhvEzUF66nYM,375
41
51
  fastlife/components/H2.jinja,sha256=LcBE2R_N50gio01nxH9qhp8_G1HxOT91xG_u8J8ae_Q,375
42
52
  fastlife/components/H3.jinja,sha256=3PzxfQh07A35Og6dE5ow9BZdNp2Qnu7OuVeWREvD7Uo,375
@@ -1671,67 +1681,56 @@ fastlife/components/icons/solid/Wrench.jinja,sha256=ZdpxRZTC5p54FGWw3bgeaQyaPooJ
1671
1681
  fastlife/components/icons/solid/WrenchScrewdriver.jinja,sha256=bqF-g6PTJds_KK2cMosVfycBVIIrmy_3sCaTkb9-C9o,1566
1672
1682
  fastlife/components/icons/solid/XCircle.jinja,sha256=pO93hG8JImNOy94B62tN7fdzkzGvSsqkSkkZlkLaxeo,791
1673
1683
  fastlife/components/icons/solid/XMark.jinja,sha256=c-ngdLuYwEMicwm4-Aj4xcEc1uQ_LrBoPhdDhQutEA8,705
1674
- fastlife/components/pydantic_form/Boolean.jinja,sha256=PsuEGHO8Fo0tqsgY1S1vyDZkrtwNo9zOGBLQM3doUCM,589
1675
- fastlife/components/pydantic_form/Checklist.jinja,sha256=mWFntBPhJJV1oX-Y4ATQirQYd8o0qxLOyoup0hwiItg,919
1676
- fastlife/components/pydantic_form/Dropdown.jinja,sha256=zAXRPE3as2nCAqvheqh9J2S1e46olwVm18CWUQ3Tj5g,688
1677
1684
  fastlife/components/pydantic_form/Error.jinja,sha256=vVSb1BKyKLOD4IOAM7aCKSNh7aAlmoiZVgRuvDCwLIo,205
1678
- fastlife/components/pydantic_form/Hidden.jinja,sha256=aAi09brl26NV4lE98o86HJIg1Q3x-41ViysJ7ia3ZD0,224
1685
+ fastlife/components/pydantic_form/FatalError.jinja,sha256=lFVlNrXzBR6ExMahq77h0tYlD46T2yUzsBwqO8Gn58g,338
1679
1686
  fastlife/components/pydantic_form/Hint.jinja,sha256=8leBpfMGDmalc_KAjr2paTojr_rwq-luS6m_1BGj7Tw,202
1680
- fastlife/components/pydantic_form/Model.jinja,sha256=GTlxcISBJseMObXDh-OXJOp0HWi8whCoqmUMzarbXL8,917
1681
- fastlife/components/pydantic_form/Sequence.jinja,sha256=LV5N56Z1t2amYfpkIo4jpk-u5pZlEFJmbLK2W3nliNM,1791
1682
- fastlife/components/pydantic_form/Text.jinja,sha256=2f_3Q32GySHTLFt-YO8gEJNCY-3XqCSqZH-RQTMooMg,514
1683
- fastlife/components/pydantic_form/Textarea.jinja,sha256=NzfCi5agRUSVcb5RXw0QamM8P1lZ-CdNI6P30zb2948,1155
1684
- fastlife/components/pydantic_form/Union.jinja,sha256=czTska54z9KCZKu-FaycLmOvtH6y6CGUFQ8DHnkjrJk,1461
1685
- fastlife/components/pydantic_form/Widget.jinja,sha256=EXskDqt22D5grpGVwlZA3ndve2Wr_6yQH4qVE9c31Og,397
1686
- fastlife/config/__init__.py,sha256=R0HXh0rt6Aecf5kJmXvhH-6QrQb1SyuI83bOU8T80fc,488
1687
- fastlife/config/configurator.py,sha256=sVecDJbjeRQRjULjbQH1JCeBOqvS6DUeQGJ5Nh2HQlw,22649
1688
- fastlife/config/exceptions.py,sha256=kH2-akbzGeODlY_1bUhbzDKqBFrpOoqnVom0WPm0IGg,1237
1687
+ fastlife/components/pydantic_form/Widget.jinja,sha256=PgguUpvhG6CY9AW6H8qQMjKqjlybjDCAaFFAOHzrzVQ,418
1688
+ fastlife/config/__init__.py,sha256=5qpuaVYqi-AS0GgsfggM6rFsSwXgrqrLBo9jH6dVroc,407
1689
+ fastlife/config/configurator.py,sha256=nxowUriGj_MYcBlcBLB49HepDIbHiF4gG3baC_V3mFM,24702
1690
+ fastlife/config/exceptions.py,sha256=9MdBnbfy-Aw-KaIFzju0Kh8Snk41-v9LqK2w48Tdy1s,1169
1689
1691
  fastlife/config/openapiextra.py,sha256=rYoerrn9sni2XwnO3gIWqaz7M0aDZPhVLjzqhDxue0o,514
1690
- fastlife/config/registry.py,sha256=zP_LPvwTcUZdrrsCnRaUfJzeYq7M_eVdRWlN0oO52RE,1754
1691
- fastlife/config/resources.py,sha256=Wu3vVr7XD18Gf4-MYYCxAAnuRmsAJmpllonts_BVGdQ,8593
1692
- fastlife/config/settings.py,sha256=t9goMfnc_oWrS_c3vgivIe0w6N2Byohcfol2CAnLiJs,3892
1693
- fastlife/config/views.py,sha256=C6Ot3mxTyN5isVsIe5b9x-VzD2q76pJQ8xY2aPWdMZM,2460
1692
+ fastlife/config/resources.py,sha256=u6OgnbHfGkC5idH-YPNkIPf8GJnZpJoGVZ-Ym022BCo,8533
1693
+ fastlife/config/views.py,sha256=9CZ0qNi8vKvQuGo1GgM6cwNK8WwHOxwIHqtikAOaOHY,2399
1694
+ fastlife/domain/__init__.py,sha256=3zDDos5InVX0el9OO0lgSDGzdUNYIhlA6w4uhBh2pF8,29
1695
+ fastlife/domain/model/__init__.py,sha256=aoBjaSpDscuFXvtknJHwiNyoJRUpE-v4X54h_wNuo2Y,27
1696
+ fastlife/domain/model/asgi.py,sha256=RSTnfTsofOmCaWzHNuRGowjlyHYmoDCrXFbvNY_B55k,129
1697
+ fastlife/domain/model/csrf.py,sha256=BUiWK-S7rVciWHO1qTkM8e_KxzpF6gGC4MMJK1v6iDo,414
1698
+ fastlife/domain/model/form.py,sha256=WriBT1qUUIbf5x5iewo9ChEcr6k0en8jMTD0iaei5Pk,3253
1699
+ fastlife/domain/model/request.py,sha256=K0_pSOboKw5IRL8SCIsEuPZlPPe3h0F5cugZEVFdfoo,2531
1700
+ fastlife/domain/model/security_policy.py,sha256=iYBKXOYaXxM_n-rsyB25lO6RblSx9icTx1Bg-s3Iz9k,2942
1701
+ fastlife/domain/model/template.py,sha256=z9oxdKme1hMPuvk7mBiKR_tuVY8TqH77aTYqMgvEGl8,876
1702
+ fastlife/domain/model/types.py,sha256=64jJKFAi5x0e3vr8naHU1m_as0Qy8MS-s9CG0z6K1qc,381
1694
1703
  fastlife/middlewares/__init__.py,sha256=C3DUOzR5EhlAv5Zq7h-Abyvkd7bUsJohTRSB2wpRYQE,220
1695
- fastlife/middlewares/base.py,sha256=9OYqByRuVoIrLt353NOedPQTLdr7LSmxhb2BZcp20qk,638
1704
+ fastlife/middlewares/base.py,sha256=7FZE_1YU7wNew2u1qdYXjamosk4CXJmg1mJWGp6Xhc0,649
1696
1705
  fastlife/middlewares/reverse_proxy/__init__.py,sha256=g1SoVDmenKzpAAPYHTEsWgdBByOxtLg9fGx6RV3i0ok,846
1697
- fastlife/middlewares/reverse_proxy/x_forwarded.py,sha256=0O9tziA63gQBmKATQz3B8H8G9CjZjnfM9NaisrvJHRY,1714
1698
- fastlife/middlewares/session/__init__.py,sha256=3XgXcIO6yQls5G7x8K2T8b7a_enA_7rQptWZcp3j2Ak,1400
1699
- fastlife/middlewares/session/middleware.py,sha256=R48x3MJ-tu8siy8G12hDHa83sMcZz6E1eEb0xwk77E4,3166
1700
- fastlife/middlewares/session/serializer.py,sha256=wpaktDP5v1spmbD-D3Q68EK9A0KInE4DT8mkogBJ3Fc,2157
1706
+ fastlife/middlewares/reverse_proxy/x_forwarded.py,sha256=PPDjcfwik5eoYaolSY1Y4x5QMKpDV0XrOP_i4Am0y30,1724
1707
+ fastlife/middlewares/session/__init__.py,sha256=ZhXWXs53A__F9wJKBJ87rW8Qyt5Mn866vhzKDxVZ4t0,1348
1708
+ fastlife/middlewares/session/middleware.py,sha256=ituZ5hNipDMkgCXNE4zbnmOcWEF151sucPo4I_FpY-I,3137
1709
+ fastlife/middlewares/session/serializer.py,sha256=nbJGiCJ_ryZxkW1I28kmK6hD3U98D4ZlUQA7B8_tngQ,635
1701
1710
  fastlife/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1702
- fastlife/request/__init__.py,sha256=-wrh12uWM7ysmIUE6FszBit2H6iI5LWVEnHxQJ_23ZE,157
1703
- fastlife/request/form.py,sha256=BiuvbV85NkvnJECSxqabfq3PhMfdKMPVobS35PhxSFA,3595
1704
- fastlife/request/form_data.py,sha256=JZmKbKZz8nnspvCHYHQrz-xsFVJFaWHkTilUWk7Fx-M,4448
1705
- fastlife/request/localizer.py,sha256=9MXAcsod-Po5qeg4lttD3dyumiI0y5vGHCwSSmt9or8,349
1706
- fastlife/request/request.py,sha256=h4Ji0GElWJ3W2hHgOwjSKHQcxUjjPuOk09v-oyfjEd0,2568
1707
- fastlife/routing/__init__.py,sha256=8EMnQE5n8oA4J9_c3nxzwKDVt3tefZ6fGH0d2owE8mo,195
1708
- fastlife/routing/route.py,sha256=vqjfMsHAVO0l2B8fuB8t19CKMtE7WoBkG4kvi4lUonM,1441
1709
- fastlife/routing/router.py,sha256=ho9TvTkX2iUW6GEh99FgclZVFKkCCCxYG4pPHeUtGn8,482
1710
- fastlife/security/__init__.py,sha256=QYDcJ3oXQzqXQxoDD_6biGAtercFrtePttoifiL1j34,25
1711
- fastlife/security/csrf.py,sha256=PIKG83LPqKz4kDALnZxIyPdYVwbNqsIryi7JPqRPQag,2168
1712
- fastlife/security/policy.py,sha256=4WHu8xhR7tAdXUHpHY1kdVIdTOFsUl92R8IsIRyYMSU,5579
1713
- fastlife/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1714
- fastlife/services/locale_negociator.py,sha256=Np2O8s7xnYTpf5eCG7LvcfFJ2LV7p_k86NNrU9Lju88,846
1715
- fastlife/services/policy.py,sha256=RfYGPjfEAAoHECUnZVLPZgN0iRanu8UKQSky6oAz81o,1687
1716
- fastlife/services/templates.py,sha256=xSoVofpKXrZc1fDLAJyDDceJrKZaZRL1K8wFp2rGsE0,4272
1717
- fastlife/services/translations.py,sha256=Akazow9YTb6N2IDdMZOAMef-grbAC7fM0nA3hw-mHt4,5315
1711
+ fastlife/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1712
+ fastlife/service/check_permission.py,sha256=-XD9qA11dLwen0bNCTy2Id_dCjzTJ0j7xuwB9IOtEY0,1695
1713
+ fastlife/service/csrf.py,sha256=wC1PaKOmZ3il0FF_kevxnlg9PxDqruRdLrNnOA3ZHrU,1886
1714
+ fastlife/service/locale_negociator.py,sha256=wXgQR8jCtPd5XtM-vvGZ4OrVnBQlt0deSoE2nInNfb0,770
1715
+ fastlife/service/registry.py,sha256=B6n5b_b0RgxJj0qFOpnrJFmG7_MPtvShwV6yH9V6vi0,2098
1716
+ fastlife/service/security_policy.py,sha256=Ytl8hgXtytvBNoBRHRmqVD96fJMnERnaL90q6XG7yI8,3036
1717
+ fastlife/service/templates.py,sha256=QPAIUbbZiekazz_jV3q4JCwQd6Q4KA6a4RDek2RWuhE,2548
1718
+ fastlife/service/translations.py,sha256=D-1D3pVNytEcps1u-0K7FmgQ8Wo6Yu4XVHvZrPhBmAI,5795
1719
+ fastlife/settings.py,sha256=q-rz4CEF2RQGow5-m-yZJOvdh3PPb2c1Q_ZLJGnu4VQ,3647
1718
1720
  fastlife/shared_utils/__init__.py,sha256=i66ytuf-Ezo7jSiNQHIsBMVIcB-tDX0tg28-pUOlhzE,26
1719
- fastlife/shared_utils/infer.py,sha256=3G_u6q2aWzeiVlAyGaWIlnAcz90m4bFNwpPYd5JIqfE,723
1721
+ fastlife/shared_utils/infer.py,sha256=0GflLkaWJ-4LZ1Ig3moR-_o55wwJ_p_vJ4xo-yi3lyA,1406
1720
1722
  fastlife/shared_utils/resolver.py,sha256=Wb9cO2MWavpti63hju15xmwFMgaD5DsQaxikRpB39E8,3713
1721
- fastlife/templates/__init__.py,sha256=yB6Zpz-jsFytLAz4Z6Nmuvr7Z8kbCXSdgw6kMpggTxk,241
1722
- fastlife/templates/binding.py,sha256=0pE2btOwLf4xOEgBXVOyz_dIX9tBCYCaJ7RhZI3knbs,1464
1723
- fastlife/templates/constants.py,sha256=MGdUjkF9hsPMN8rOS49eWbAApcb8FL-FAeFvJU8k90M,8387
1724
- fastlife/templates/inline.py,sha256=wrZDAtd7zXcACHl2LVz0HqDT1VSPsiVy4srt3JSDiu4,704
1723
+ fastlife/template_globals.py,sha256=rJ7XB9DlPubejs_GDlEyO9V98QZTJnmdTznlguYOyoc,8386
1725
1724
  fastlife/testing/__init__.py,sha256=VpxkS3Zp3t_hH8dBiLaGFGhsvt511dhBS_8fMoFXdmU,99
1726
1725
  fastlife/testing/dom.py,sha256=dVzDoZokn-ii681UaEwAr-khM5KE-CHgXSSLSo24oH0,4489
1727
1726
  fastlife/testing/form.py,sha256=ST0xNCoUqz_oD92cWHzQ6CbJ5hFopvu_NNKpOfiuYWY,7874
1728
1727
  fastlife/testing/session.py,sha256=LEFFbiR67_x_g-ioudkY0C7PycHdbDfaIaoo_G7GXQ8,2226
1729
- fastlife/testing/testclient.py,sha256=WmUnGkDPuSd4dKzTiXWyHWlJ31zBbySvMH9m8p0acg8,6741
1730
- fastlife/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1731
- fastlife/views/pydantic_form.py,sha256=4dv37JORLpvkgCgMGZfUN_qy7wme040GLZAzOTFqdnU,1367
1732
- fastlifeweb-0.20.1.dist-info/METADATA,sha256=1bgPaE9fkIVQFavMvtJgVJbNpOwBezDcb_SwR_2LB00,3663
1733
- fastlifeweb-0.20.1.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
1734
- fastlifeweb-0.20.1.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
1735
- fastlifeweb-0.20.1.dist-info/licenses/LICENSE,sha256=NlRX9Z-dcv8X1VFW9odlIQBbgNN9pcO94XzvKp2R16o,1075
1736
- tailwind.config.js,sha256=y_xTuRmjIdrfyo92PoUW0wjFTnkO27xepwfirkaCFno,1351
1737
- fastlifeweb-0.20.1.dist-info/RECORD,,
1728
+ fastlife/testing/testclient.py,sha256=JTIgeMKooA8L4gEodeC3gy4Lo27y3WNswSEIKLlVVPs,6745
1729
+ fastlife/views/__init__.py,sha256=zG8gveL8e2zBdYx6_9jtZfpQ6qJT-MFnBY3xXkLwHZI,22
1730
+ fastlife/views/pydantic_form.py,sha256=o7EUItciAGL1OSaGNHo-3BTrYAk34GuWE7zGikjiAGY,1486
1731
+ fastlifeweb-0.22.0.dist-info/METADATA,sha256=8ual_JaeNHufsRyP5pdCPu2yHuVpzMzR53aitRbHmjo,3663
1732
+ fastlifeweb-0.22.0.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
1733
+ fastlifeweb-0.22.0.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
1734
+ fastlifeweb-0.22.0.dist-info/licenses/LICENSE,sha256=NlRX9Z-dcv8X1VFW9odlIQBbgNN9pcO94XzvKp2R16o,1075
1735
+ tailwind.config.js,sha256=EN3EahBDmQBbmJvkw3SdGWNOkfkzw0cg-QvBikOhkrw,1348
1736
+ fastlifeweb-0.22.0.dist-info/RECORD,,
tailwind.config.js CHANGED
@@ -2,7 +2,7 @@
2
2
  module.exports = {
3
3
  darkMode: "class",
4
4
  content: [
5
- "./src/fastlife/templates/constants.py",
5
+ "./src/fastlife/template_globals.py",
6
6
  "./src/fastlife/components/*.jinja",
7
7
  "./src/fastlife/components/**/*.jinja",
8
8
  "./tests/fastlife_app/templates/*.jinja",
@@ -1,13 +0,0 @@
1
- {# doc Render a checkbox and a label for boolean field. #}
2
- {# def widget: Annotated[fastlife.adapters.jinjax.widgets.boolean.BooleanWidget, "widget to display."] #}
3
- <pydantic_form.Widget :widget="widget">
4
- <div class="pt-4">
5
- <div class="flex items-center">
6
- <Checkbox :name="widget.name" type="checkbox" :id="widget.id" :checked="widget.value" value="1" />
7
- <Label :for="widget.id" class="ms-2 text-base text-neutral-900 dark:text-white">
8
- {{widget.title|safe}}
9
- </Label>
10
- </div>
11
- <pydantic_form.Error :text="widget.error" />
12
- </div>
13
- </pydantic_form.Widget>
@@ -1,21 +0,0 @@
1
- {# doc Render a list of checkbox and a label for Literal and enum fields #}
2
- {# def widget: Annotated[fastlife.adapters.jinjax.widgets.checklist.ChecklistWidget, "widget to display."] #}
3
- <pydantic_form.Widget :widget="widget">
4
- <div class="pt-4">
5
- <Details>
6
- <Summary :id="widget.id + '-summary'">
7
- <H3 :class="H3_SUMMARY_CLASS">{{widget.title}}</H3>
8
- <pydantic_form.Error :text="widget.error" />
9
- </Summary>
10
- <div>
11
- {% for value in widget.value %}
12
- <div class="flex items-center mb-4">
13
- <Checkbox :name="value.field_name" type="checkbox" :id="value.id" :value="value.value" :checked="value.checked" />
14
- <Label :for="value.id" class="ms-2 text-base text-neutral-900 dark:text-white">{{value.label}}</Label>
15
- <pydantic_form.Error :text="value.error" />
16
- </div>
17
- {% endfor %}
18
- </div>
19
- </Details>
20
- </div>
21
- </pydantic_form.Widget>
@@ -1,18 +0,0 @@
1
- {# doc Render a Select with options #}
2
- {# def widget: Annotated[fastlife.adapters.jinjax.widgets.dropdown.DropDownWidget, "widget to display."] #}
3
-
4
- <pydantic_form.Widget :widget="widget">
5
- <div class="pt-4">
6
- <Label :for="widget.id">{{widget.title}}</Label>
7
- <Select :name="widget.name" :id="widget.id">
8
- {%- for opt in widget.options -%}
9
- <Option :value="opt.value" id={{widget.id + "-" + opt.value.replace(" ", " -")}}
10
- :selected="widget.value==opt.value">
11
- {{- opt.text -}}
12
- </Option>
13
- {%- endfor -%}
14
- </Select>
15
- <pydantic_form.Error :text="widget.error" />
16
- <pydantic_form.Hint :text="widget.hint" />
17
- </div>
18
- </pydantic_form.Widget>