fastlifeweb 0.3.1__py3-none-any.whl → 0.4.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.
- fastlife/configurator/registry.py +2 -2
- fastlife/configurator/settings.py +3 -0
- fastlife/templates/A.jinja +30 -4
- fastlife/templates/Button.jinja +31 -17
- fastlife/templates/Checkbox.jinja +20 -2
- fastlife/templates/CsrfToken.jinja +0 -1
- fastlife/templates/Form.jinja +9 -3
- fastlife/templates/H1.jinja +15 -4
- fastlife/templates/H2.jinja +15 -4
- fastlife/templates/H3.jinja +14 -0
- fastlife/templates/H4.jinja +14 -0
- fastlife/templates/H5.jinja +14 -0
- fastlife/templates/H6.jinja +14 -0
- fastlife/templates/Input.jinja +29 -6
- fastlife/templates/Label.jinja +10 -2
- fastlife/templates/Option.jinja +4 -2
- fastlife/templates/P.jinja +9 -0
- fastlife/templates/Radio.jinja +29 -7
- fastlife/templates/Select.jinja +25 -6
- fastlife/templates/pydantic_form/Boolean.jinja +1 -1
- fastlife/templates/pydantic_form/Dropdown.jinja +4 -6
- fastlife/templates/pydantic_form/Hint.jinja +4 -0
- fastlife/templates/pydantic_form/Model.jinja +1 -1
- fastlife/templates/pydantic_form/Sequence.jinja +3 -3
- fastlife/templates/pydantic_form/Text.jinja +1 -3
- fastlife/templates/pydantic_form/Union.jinja +5 -5
- fastlife/templating/__init__.py +2 -2
- fastlife/templating/binding.py +4 -22
- fastlife/templating/renderer/__init__.py +5 -2
- fastlife/templating/renderer/abstract.py +7 -5
- fastlife/templating/renderer/jinjax.py +51 -23
- fastlife/templating/renderer/widgets/base.py +12 -2
- fastlife/templating/renderer/widgets/boolean.py +4 -3
- fastlife/templating/renderer/widgets/dropdown.py +7 -6
- fastlife/templating/renderer/widgets/factory.py +38 -21
- fastlife/templating/renderer/widgets/hidden.py +2 -3
- fastlife/templating/renderer/widgets/model.py +7 -6
- fastlife/templating/renderer/widgets/sequence.py +8 -9
- fastlife/templating/renderer/widgets/text.py +9 -5
- fastlife/templating/renderer/widgets/union.py +7 -6
- fastlife/testing/testclient.py +116 -55
- fastlife/views/pydantic_form.py +5 -2
- {fastlifeweb-0.3.1.dist-info → fastlifeweb-0.4.0.dist-info}/METADATA +5 -4
- fastlifeweb-0.4.0.dist-info/RECORD +69 -0
- fastlifeweb-0.3.1.dist-info/RECORD +0 -63
- {fastlifeweb-0.3.1.dist-info → fastlifeweb-0.4.0.dist-info}/LICENSE +0 -0
- {fastlifeweb-0.3.1.dist-info → fastlifeweb-0.4.0.dist-info}/WHEEL +0 -0
fastlife/testing/testclient.py
CHANGED
@@ -1,18 +1,23 @@
|
|
1
1
|
import re
|
2
2
|
import time
|
3
3
|
from collections.abc import MutableMapping
|
4
|
+
from http.cookiejar import Cookie
|
4
5
|
from typing import Any, Iterator, Literal, Mapping, Optional, Sequence
|
5
6
|
from urllib.parse import urlencode
|
6
7
|
|
7
8
|
import bs4
|
8
9
|
import httpx
|
9
10
|
from fastapi.testclient import TestClient
|
11
|
+
from multidict import MultiDict
|
10
12
|
from starlette.types import ASGIApp
|
11
13
|
|
12
14
|
from fastlife.configurator.settings import Settings
|
13
15
|
from fastlife.session.serializer import AbsractSessionSerializer
|
14
16
|
from fastlife.shared_utils.resolver import resolve
|
15
17
|
|
18
|
+
CookieTypes = httpx._types.CookieTypes # type: ignore
|
19
|
+
Cookies = httpx._models.Cookies # type: ignore
|
20
|
+
|
16
21
|
|
17
22
|
class Element:
|
18
23
|
def __init__(self, client: "WebTestClient", tag: bs4.Tag):
|
@@ -34,10 +39,6 @@ class Element:
|
|
34
39
|
def text(self) -> str:
|
35
40
|
return self._tag.text.strip()
|
36
41
|
|
37
|
-
@property
|
38
|
-
def form(self) -> "Element | None":
|
39
|
-
return Element(self._client, self._tag.form) if self._tag.form else None
|
40
|
-
|
41
42
|
@property
|
42
43
|
def h1(self) -> "Element":
|
43
44
|
nodes = self.by_node_name("h1")
|
@@ -48,6 +49,10 @@ class Element:
|
|
48
49
|
def h2(self) -> Sequence["Element"]:
|
49
50
|
return self.by_node_name("h2")
|
50
51
|
|
52
|
+
@property
|
53
|
+
def form(self) -> "Element | None":
|
54
|
+
return Element(self._client, self._tag.form) if self._tag.form else None
|
55
|
+
|
51
56
|
@property
|
52
57
|
def hx_target(self) -> Optional[str]:
|
53
58
|
el: bs4.Tag | None = self._tag
|
@@ -115,57 +120,130 @@ class WebForm:
|
|
115
120
|
self._form = form
|
116
121
|
self._origin = origin
|
117
122
|
self._formfields: dict[str, Element] = {}
|
118
|
-
self._formdata:
|
123
|
+
self._formdata: MultiDict[str] = MultiDict()
|
119
124
|
inputs = self._form.by_node_name("input")
|
120
125
|
for input in inputs:
|
121
126
|
self._formfields[input.attrs["name"]] = input
|
122
127
|
if input.attrs.get("type") == "checkbox" and "checked" not in input.attrs:
|
123
128
|
continue
|
124
|
-
self._formdata
|
125
|
-
|
126
|
-
|
127
|
-
for
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
129
|
+
self._formdata.add(input.attrs["name"], input.attrs.get("value", ""))
|
130
|
+
|
131
|
+
selects = self._form.by_node_name("select")
|
132
|
+
for select in selects:
|
133
|
+
fieldname = select.attrs["name"]
|
134
|
+
self._formfields[fieldname] = select
|
135
|
+
options = select.by_node_name("option")
|
136
|
+
if "multiple" in select.attrs:
|
137
|
+
for option in options:
|
138
|
+
if "selected" in option.attrs:
|
139
|
+
self._formdata.add(
|
140
|
+
fieldname, option.attrs.get("value", option.text)
|
141
|
+
)
|
142
|
+
else:
|
143
|
+
if options:
|
144
|
+
self._formdata[fieldname] = options[0].attrs.get(
|
145
|
+
"value", options[0].text
|
133
146
|
)
|
147
|
+
for option in options:
|
148
|
+
if "selected" in option.attrs:
|
149
|
+
self._formdata[fieldname] = option.attrs.get(
|
150
|
+
"value", option.text
|
151
|
+
)
|
152
|
+
break
|
153
|
+
|
134
154
|
# field textearea...
|
135
155
|
|
136
156
|
def set(self, fieldname: str, value: str) -> Any:
|
137
157
|
if fieldname not in self._formfields:
|
138
|
-
raise ValueError(f"{fieldname} does not exists
|
158
|
+
raise ValueError(f'"{fieldname}" does not exists')
|
139
159
|
if self._formfields[fieldname].node_name == "select":
|
140
|
-
raise
|
160
|
+
raise ValueError(f'"{fieldname}" is a <select>, use select() instead')
|
161
|
+
|
162
|
+
if self._formfields[fieldname].attrs.get("type") == "checkbox":
|
163
|
+
self._formdata.add(fieldname, value)
|
164
|
+
return
|
165
|
+
|
166
|
+
if self._formfields[fieldname].attrs.get("type") == "radio":
|
167
|
+
radio = self._form.by_node_name(
|
168
|
+
"input", attrs={"type": "radio", "value": value}
|
169
|
+
)
|
170
|
+
if not radio:
|
171
|
+
raise ValueError(
|
172
|
+
f'radio "{fieldname}" does not contains {value} option'
|
173
|
+
)
|
174
|
+
|
141
175
|
self._formdata[fieldname] = value
|
142
176
|
|
177
|
+
def unset(self, fieldname: str, value: str) -> Any:
|
178
|
+
if fieldname not in self._formfields:
|
179
|
+
raise ValueError(f'"{fieldname}" does not exists')
|
180
|
+
if self._formfields[fieldname].node_name != "input":
|
181
|
+
raise ValueError(f'"{fieldname}" is not a checkbox')
|
182
|
+
if self._formfields[fieldname].attrs.get("type") != "checkbox":
|
183
|
+
raise ValueError(f'"{fieldname}" is not a checkbox')
|
184
|
+
values = self._formdata.popall(fieldname)
|
185
|
+
if value not in values:
|
186
|
+
raise ValueError(f'"{value}" not in "{fieldname}"')
|
187
|
+
for val in values:
|
188
|
+
if val != value:
|
189
|
+
self._formdata[fieldname] = val
|
190
|
+
|
143
191
|
def select(self, fieldname: str, value: str) -> Any:
|
144
192
|
if fieldname not in self._formfields:
|
145
|
-
raise ValueError(f"{fieldname} does not exists
|
146
|
-
|
147
|
-
|
148
|
-
|
193
|
+
raise ValueError(f'"{fieldname}" does not exists')
|
194
|
+
field = self._formfields[fieldname]
|
195
|
+
if field.node_name != "select":
|
196
|
+
raise ValueError(f"{fieldname} is a {repr(field)}, " "use set() instead")
|
197
|
+
|
198
|
+
for option in field.by_node_name("option"):
|
199
|
+
if option.text == value.strip():
|
200
|
+
if "multiple" in field.attrs:
|
201
|
+
self._formdata.add(fieldname, value)
|
202
|
+
else:
|
203
|
+
self._formdata[fieldname] = option.attrs.get("value", option.text)
|
204
|
+
break
|
205
|
+
else:
|
206
|
+
raise ValueError(f'No option {value} in <select name="{fieldname}">')
|
207
|
+
|
208
|
+
def unselect(self, fieldname: str, value: str) -> Any:
|
209
|
+
if fieldname not in self._formfields:
|
210
|
+
raise ValueError(f'"{fieldname}" does not exists')
|
211
|
+
field = self._formfields[fieldname]
|
212
|
+
|
213
|
+
if field.node_name != "select":
|
214
|
+
raise ValueError(
|
215
|
+
f"{fieldname} is a {repr(self._formfields[fieldname])}, "
|
216
|
+
"use unset() for checkbox instead"
|
149
217
|
)
|
150
|
-
if "multiple" in
|
151
|
-
raise
|
218
|
+
if "multiple" not in field.attrs:
|
219
|
+
raise ValueError("only <select multiple> support unselect")
|
220
|
+
|
152
221
|
for option in self._formfields[fieldname].by_node_name("option"):
|
153
222
|
if option.text == value.strip():
|
154
|
-
|
223
|
+
values = self._formdata.popall(fieldname)
|
224
|
+
if value not in values:
|
225
|
+
raise ValueError(f'"{value}" not selected in "{fieldname}"')
|
226
|
+
for val in values:
|
227
|
+
if val != value:
|
228
|
+
self._formdata[fieldname] = val
|
155
229
|
break
|
156
230
|
else:
|
157
231
|
raise ValueError(f'No option {value} in <select name="{fieldname}">')
|
158
232
|
|
159
233
|
def button(self, text: str, position: int = 0) -> "WebForm":
|
160
234
|
buttons = self._form.get_all_by_text(text, node_name="button")
|
161
|
-
|
235
|
+
if position >= len(buttons):
|
236
|
+
pos = ""
|
237
|
+
if position > 0:
|
238
|
+
pos = f" at position {position}"
|
239
|
+
raise ValueError(f'Button "{text}" not found{pos}')
|
162
240
|
button = buttons[position]
|
163
241
|
if "name" in button.attrs:
|
164
242
|
self._formdata[button.attrs["name"]] = button.attrs.get("value", "")
|
165
243
|
return self
|
166
244
|
|
167
245
|
def submit(self, follow_redirects: bool = True) -> "WebResponse":
|
168
|
-
headers = {}
|
246
|
+
headers: dict[str, str] = {}
|
169
247
|
target = (
|
170
248
|
self._form.attrs.get("hx-post")
|
171
249
|
or self._form.attrs.get("post")
|
@@ -199,12 +277,12 @@ class WebResponse:
|
|
199
277
|
return self._response.status_code
|
200
278
|
|
201
279
|
@property
|
202
|
-
def is_redirect(self) ->
|
280
|
+
def is_redirect(self) -> bool:
|
203
281
|
return 300 <= self._response.status_code < 400
|
204
282
|
|
205
283
|
@property
|
206
284
|
def content_type(self) -> str:
|
207
|
-
return self._response.headers
|
285
|
+
return self._response.headers.get("content-type", "").split(";").pop(0)
|
208
286
|
|
209
287
|
@property
|
210
288
|
def headers(self) -> httpx.Headers:
|
@@ -246,28 +324,17 @@ class WebResponse:
|
|
246
324
|
return self.html.by_node_name(node_name, attrs=attrs)
|
247
325
|
|
248
326
|
|
249
|
-
CookieTypes = httpx._types.CookieTypes # type: ignore
|
250
|
-
Cookies = httpx._models.Cookies # type: ignore
|
251
|
-
|
252
|
-
|
253
327
|
class Session(dict[str, Any]):
|
254
328
|
def __init__(self, client: "WebTestClient"):
|
255
329
|
self.client = client
|
256
|
-
if client.session_serializer is None:
|
257
|
-
raise RuntimeError(
|
258
|
-
"WebTestClient has not been initialize with the app settings, "
|
259
|
-
"can't decode session"
|
260
|
-
)
|
261
|
-
|
262
330
|
self.srlz = client.session_serializer
|
263
|
-
settings = self.client.settings
|
264
|
-
assert settings is not None
|
265
|
-
self.settings = settings
|
331
|
+
self.settings = self.client.settings
|
266
332
|
data: Mapping[str, Any]
|
267
|
-
|
333
|
+
cookie_name = self.settings.session_cookie_name
|
334
|
+
self.has_session = cookie_name in self.client.cookies
|
268
335
|
if self.has_session:
|
269
336
|
data, error = self.srlz.deserialize(
|
270
|
-
self.client.cookies[
|
337
|
+
self.client.cookies[cookie_name].encode("utf-8")
|
271
338
|
)
|
272
339
|
if error:
|
273
340
|
self.has_session = False
|
@@ -279,8 +346,6 @@ class Session(dict[str, Any]):
|
|
279
346
|
super().__setitem__(__key, __value)
|
280
347
|
settings = self.settings
|
281
348
|
data = self.serialize()
|
282
|
-
from http.cookiejar import Cookie
|
283
|
-
|
284
349
|
self.client.cookies.jar.set_cookie(
|
285
350
|
Cookie(
|
286
351
|
version=0,
|
@@ -330,21 +395,17 @@ class WebTestClient:
|
|
330
395
|
app, base_url=f"http://{settings.domain_name}", cookies=cookies or {}
|
331
396
|
)
|
332
397
|
self.settings = settings
|
333
|
-
self.session_serializer: AbsractSessionSerializer
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
398
|
+
self.session_serializer: AbsractSessionSerializer = resolve(
|
399
|
+
settings.session_serializer
|
400
|
+
)(
|
401
|
+
settings.session_secret_key,
|
402
|
+
int(settings.session_duration.total_seconds()),
|
403
|
+
)
|
339
404
|
|
340
405
|
@property
|
341
406
|
def cookies(self) -> Cookies:
|
342
407
|
return self.testclient.cookies
|
343
408
|
|
344
|
-
@cookies.setter
|
345
|
-
def cookies(self, value: Cookies) -> None:
|
346
|
-
self.testclient.cookies = value
|
347
|
-
|
348
409
|
@property
|
349
410
|
def session(self) -> MutableMapping[str, Any]:
|
350
411
|
return Session(self)
|
@@ -403,7 +464,7 @@ class WebTestClient:
|
|
403
464
|
def post(
|
404
465
|
self,
|
405
466
|
url: str,
|
406
|
-
data:
|
467
|
+
data: MultiDict[str],
|
407
468
|
*,
|
408
469
|
headers: Mapping[str, Any] | None = None,
|
409
470
|
follow_redirects: bool = True,
|
fastlife/views/pydantic_form.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import Optional
|
2
2
|
|
3
|
-
from fastapi import Query, Response
|
3
|
+
from fastapi import Query, Request, Response
|
4
4
|
from pydantic.fields import FieldInfo
|
5
5
|
|
6
6
|
from fastlife import Configurator, configure
|
@@ -11,6 +11,7 @@ from fastlife.shared_utils.resolver import resolve_extended
|
|
11
11
|
async def show_widget(
|
12
12
|
typ: str,
|
13
13
|
reg: Registry,
|
14
|
+
request: Request,
|
14
15
|
title: Optional[str] = Query(None),
|
15
16
|
name: Optional[str] = Query(None),
|
16
17
|
token: Optional[str] = Query(None),
|
@@ -20,7 +21,9 @@ async def show_widget(
|
|
20
21
|
field = None
|
21
22
|
if title:
|
22
23
|
field = FieldInfo(title=title)
|
23
|
-
data = reg.renderer.pydantic_form(
|
24
|
+
data = reg.renderer(request).pydantic_form(
|
25
|
+
model_cls, None, name, token, removable, field
|
26
|
+
)
|
24
27
|
return Response(data, headers={"Content-Type": "text/html"})
|
25
28
|
|
26
29
|
|
@@ -1,7 +1,8 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: fastlifeweb
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.4.0
|
4
4
|
Summary: High-level web framework
|
5
|
+
Home-page: https://github.com/mardiros/fastlife
|
5
6
|
License: BSD-derived
|
6
7
|
Author: Guillaume Gauvrit
|
7
8
|
Author-email: guillaume@gauvr.it
|
@@ -20,12 +21,14 @@ Requires-Dist: beautifulsoup4[testing] (>=4.12.2,<5.0.0)
|
|
20
21
|
Requires-Dist: behave (>=1.2.6,<2.0.0)
|
21
22
|
Requires-Dist: fastapi (>=0.110.0,<0.111.0)
|
22
23
|
Requires-Dist: itsdangerous (>=2.1.2,<3.0.0)
|
23
|
-
Requires-Dist: jinjax (>=0.
|
24
|
+
Requires-Dist: jinjax (>=0.32,<0.33)
|
24
25
|
Requires-Dist: markupsafe (>=2.1.3,<3.0.0)
|
26
|
+
Requires-Dist: multidict (>=6.0.5,<7.0.0)
|
25
27
|
Requires-Dist: pydantic (>=2.3.0,<3.0.0)
|
26
28
|
Requires-Dist: pydantic-settings (>=2.0.3,<3.0.0)
|
27
29
|
Requires-Dist: python-multipart (>=0.0.6,<0.0.7)
|
28
30
|
Requires-Dist: venusian (>=3.0.0,<4.0.0)
|
31
|
+
Project-URL: Repository, https://github.com/mardiros/fastlife
|
29
32
|
Description-Content-Type: text/markdown
|
30
33
|
|
31
34
|
# Fastlife
|
@@ -44,5 +47,3 @@ Under heavy development.
|
|
44
47
|
|
45
48
|
The package is available on pypi with the name fastlifeweb.
|
46
49
|
|
47
|
-
The name fastlife is squatted and I am tired of PEP 541 requests.
|
48
|
-
|
@@ -0,0 +1,69 @@
|
|
1
|
+
fastlife/__init__.py,sha256=ewfV5kR3Pq7Bzan_Wnq__LYGzXgk2CJaamxhyMyhaCI,312
|
2
|
+
fastlife/configurator/__init__.py,sha256=2EPjM1o5iHJIViPwgJjaPQS3pMhE-9dik_mm53eX2DY,91
|
3
|
+
fastlife/configurator/base.py,sha256=2ahvTudLmD99YQjnIeGN5JDPCSl3k-mauu7bsSEB5RE,216
|
4
|
+
fastlife/configurator/configurator.py,sha256=6BaB7SR24Q4Qvs8NrCpatRkkZiPXf9mKLID6RxOKxDg,5740
|
5
|
+
fastlife/configurator/registry.py,sha256=1sOicKvwIvLbrzRk9z8yb65YUXxxagJK9AK-2gGDpOQ,1463
|
6
|
+
fastlife/configurator/settings.py,sha256=ftv5MkNXeyBrvcqxnt2WKtLuzo7ge2_BNx1gX4CcSOE,1489
|
7
|
+
fastlife/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
+
fastlife/request/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
fastlife/request/form_data.py,sha256=gKXo92ZwsMX6UpMkf4BlNYDiOfwxyzDzItc_lpplAzY,3642
|
10
|
+
fastlife/security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
+
fastlife/security/csrf.py,sha256=47epJVJtr5X6j-Hog54WCGOoiRLQQHvgBU71iqR1N0A,1025
|
12
|
+
fastlife/security/policy.py,sha256=5jV5nypy5O8XPFFRJ_bzG8Ltk5xcPWclkz23qiG1_I8,509
|
13
|
+
fastlife/session/__init__.py,sha256=OnzRCYRzc1lw9JB0UdKi-aRLPNT2n8mM8kwY1P4w7uU,838
|
14
|
+
fastlife/session/middleware.py,sha256=JgXdBlxlm9zIEgXcidbBrMAp5wJVPsZWtvCLVDk5h2s,3049
|
15
|
+
fastlife/session/serializer.py,sha256=qpVnHQjYTxw3aOnoEOKIjOFJg2z45KjiX5sipWk2gws,1458
|
16
|
+
fastlife/shared_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
+
fastlife/shared_utils/infer.py,sha256=_hmGzu84VlZAkdw_owkW8eHknULqH3MLDBlXj7LkEsc,466
|
18
|
+
fastlife/shared_utils/resolver.py,sha256=wXQQTB4jf86m4qENhMOkHkWpLJj_T4-_eND_ItTLnTE,1410
|
19
|
+
fastlife/templates/A.jinja,sha256=q71nu4Rq874LG6SykCKv8W-EZeX13NMF0AsLc9FFAP0,677
|
20
|
+
fastlife/templates/Button.jinja,sha256=535UIK4Prunj4f0YZXBmCI0rfOiTr5GJTQkM0XDmtNA,1137
|
21
|
+
fastlife/templates/Checkbox.jinja,sha256=EbKJ9KmfexegcocxeMtoG1kt-x4bP8Tq3odh8prbJoQ,366
|
22
|
+
fastlife/templates/CsrfToken.jinja,sha256=X2-H0VmukyUV448blh9M8rhr_gN82ar51TnRAwfV3OY,59
|
23
|
+
fastlife/templates/Form.jinja,sha256=cfXWtFWCcnxdIOayR3_XWoY1PpQATiyQDqkY0Vg91g0,329
|
24
|
+
fastlife/templates/H1.jinja,sha256=fetjIhZvgw5gm6xJhl_-cnHvrPwuLYE4S1rVYgbqNl8,196
|
25
|
+
fastlife/templates/H2.jinja,sha256=z022lvv3PO_g-ZxWuAiKmBOaFZ3u8Kbzd0jkuWNsOS0,196
|
26
|
+
fastlife/templates/H3.jinja,sha256=BmSznvHOCAT8569hf-lOh0qlK3yHAPdO3KCOLD7BaPE,195
|
27
|
+
fastlife/templates/H4.jinja,sha256=5H31nKNB-_QgYs-aupTVx-hamcHhWTNns8iXW4IWqqE,195
|
28
|
+
fastlife/templates/H5.jinja,sha256=bmqrG0I9VOTbK9iq0jQhAuoYuy_vlPiRqnyA1TGvuyo,193
|
29
|
+
fastlife/templates/H6.jinja,sha256=PI1jAlgmEuEoAeoSy0bYCs0LT-8j_XTqauMTOWRGlgU,191
|
30
|
+
fastlife/templates/Hidden.jinja,sha256=nOGfkWwhXckJE2O4wL5IXNKB5dvU0HbmdWCTECxEFHs,120
|
31
|
+
fastlife/templates/Input.jinja,sha256=YlImqjxjCJjjHAekYmUDUyHloNWEVlddeF0Ea7A_C6w,638
|
32
|
+
fastlife/templates/Label.jinja,sha256=m71vGDUi2HzzA5d9L3TQhdEXYKHcp6LXP6PE0-bx44w,170
|
33
|
+
fastlife/templates/Option.jinja,sha256=YlgBayJj94kSXK0mlGkMxTmHjTBr8T-UzvQmTcANK0Q,121
|
34
|
+
fastlife/templates/P.jinja,sha256=xEcHIv9dJRpELu_SdqQcftvKrU8z1i_BHTEVO5Mu5dU,164
|
35
|
+
fastlife/templates/Radio.jinja,sha256=51I5n1yjWQ_uLZfzuUUf3C8ngo-KT4dPw29-pjP9uSU,723
|
36
|
+
fastlife/templates/Select.jinja,sha256=6Rw9A51JbSTprgNLz8A8E_UKfsLFf26eqdhwLnaMms4,427
|
37
|
+
fastlife/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
|
+
fastlife/templates/pydantic_form/Boolean.jinja,sha256=XE3NM4vhwQwRUIbjv10t9dI70MzWhicyQ_l6FAOs8-k,298
|
39
|
+
fastlife/templates/pydantic_form/Dropdown.jinja,sha256=JBkQp7LYtz6vvW6MyAXyW-6UDZ_xY0Fgd4mpDCQA-wM,500
|
40
|
+
fastlife/templates/pydantic_form/Hidden.jinja,sha256=n6CbTSwZr2E_oY8TO2WPbnrLHBaWfe_CXVCYOYmCfts,83
|
41
|
+
fastlife/templates/pydantic_form/Hint.jinja,sha256=O0ZsAQnATcG0a_qLQfrwM6VZHmAw3k1W33WYlEBUas8,123
|
42
|
+
fastlife/templates/pydantic_form/Model.jinja,sha256=wxEKEO8Kktxkrz-LZ9m_v_NPjKV-C8RFQ9wyEyrRKsI,449
|
43
|
+
fastlife/templates/pydantic_form/Sequence.jinja,sha256=eA8GYhJC1KokWbU3zqmqCIuG8mR-yhvlEAzt0ds2RTM,1380
|
44
|
+
fastlife/templates/pydantic_form/Text.jinja,sha256=t8fZTGm7EOrc8JsVlnqRAkAfQfKDDZQk4xXlLAgXCAQ,402
|
45
|
+
fastlife/templates/pydantic_form/Union.jinja,sha256=Ss4dwNoHqmdAa4O7cvS2vwuxBPspQINBxq4hnkm_GVY,950
|
46
|
+
fastlife/templates/pydantic_form/Widget.jinja,sha256=8raoMjtO4ARBfbz8EG-HKT112KkrWG82BbUfbXpAmZs,287
|
47
|
+
fastlife/templating/__init__.py,sha256=QdrTmxt-K7UcJ_o9LY1n-QZAvk5foct5MNFt02zXr2w,234
|
48
|
+
fastlife/templating/binding.py,sha256=n-MDg98Bne49BmWWWCopZsI6ef7h6PIdcszM_pRutYA,1378
|
49
|
+
fastlife/templating/renderer/__init__.py,sha256=UJUX3T9VYjPQUhS5Enz3P6OtwftimKoGGpoQEpewVFA,181
|
50
|
+
fastlife/templating/renderer/abstract.py,sha256=eS4ArmR2hc5-svrzDbRz7eeXpUbXf7wklPZT6VDsgVM,818
|
51
|
+
fastlife/templating/renderer/jinjax.py,sha256=y-CN5qvAj86zKQIj6nUtNw_WyGqH5b9Je9Ro3R9ZT1I,3206
|
52
|
+
fastlife/templating/renderer/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
53
|
+
fastlife/templating/renderer/widgets/base.py,sha256=_MMtrhYvtQgX1EQNku0NSBYwhCDvQ5y8TjnCC2b4CAw,2769
|
54
|
+
fastlife/templating/renderer/widgets/boolean.py,sha256=bk9bExUDp73is6tvbpC28ploIVjyMecFsxPN8NxnOd8,468
|
55
|
+
fastlife/templating/renderer/widgets/dropdown.py,sha256=o3BfD9gDiRPsCPB93xCZSYRo50LRAb_tZOmK4x7zkzY,901
|
56
|
+
fastlife/templating/renderer/widgets/factory.py,sha256=uEYaxHYygLQ-5eWWjsOlvPM6GmhHW7Nu_w-1l2HRihA,10335
|
57
|
+
fastlife/templating/renderer/widgets/hidden.py,sha256=2fsbTQKsACV0JVYpCjXaQAV7VnQTIBPCi4lJPdWCRHc,308
|
58
|
+
fastlife/templating/renderer/widgets/model.py,sha256=obZNgUiTWsMf24ge-KPSay7S3rkFn3kdQlEBbR-r-14,950
|
59
|
+
fastlife/templating/renderer/widgets/sequence.py,sha256=x6o1L_hOh3WRlW16ZQaeO6H_qtnIitALuK-w7ck0RAw,1347
|
60
|
+
fastlife/templating/renderer/widgets/text.py,sha256=mlW8LrRmj-aEMp8QzZOURhns6mfbV7jsOMQrsYZcU3Q,819
|
61
|
+
fastlife/templating/renderer/widgets/union.py,sha256=GntHssMjcgpD6S5h0JVr9_aWy3pSbMhYZ9QU-ugBH-Y,1689
|
62
|
+
fastlife/testing/__init__.py,sha256=KgTlRI0g8z7HRpL7mD5QgI__LT9Y4QDSzKMlxJG3wNk,67
|
63
|
+
fastlife/testing/testclient.py,sha256=JhWgruKDeIn0QFmEAXKhUXXsZpTpPi_JWIHhWbWIXg0,16404
|
64
|
+
fastlife/views/__init__.py,sha256=nn4B_8YTbTmhGPvSd20yyKK_9Dh1Pfh_Iq7z6iK8-CE,154
|
65
|
+
fastlife/views/pydantic_form.py,sha256=TyZbVfhOGy3en1a7o4wcRp11War7sqVHxyEjOsRMht0,1092
|
66
|
+
fastlifeweb-0.4.0.dist-info/LICENSE,sha256=F75xSseSKMwqzFj8rswYU6NWS3VoWOc_gY3fJYf9_LI,1504
|
67
|
+
fastlifeweb-0.4.0.dist-info/METADATA,sha256=w-g1uz8vo-bHjLyfqKzeQI6tZL2pJEJPaXSMp4X4-RY,1833
|
68
|
+
fastlifeweb-0.4.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
69
|
+
fastlifeweb-0.4.0.dist-info/RECORD,,
|
@@ -1,63 +0,0 @@
|
|
1
|
-
fastlife/__init__.py,sha256=ewfV5kR3Pq7Bzan_Wnq__LYGzXgk2CJaamxhyMyhaCI,312
|
2
|
-
fastlife/configurator/__init__.py,sha256=2EPjM1o5iHJIViPwgJjaPQS3pMhE-9dik_mm53eX2DY,91
|
3
|
-
fastlife/configurator/base.py,sha256=2ahvTudLmD99YQjnIeGN5JDPCSl3k-mauu7bsSEB5RE,216
|
4
|
-
fastlife/configurator/configurator.py,sha256=6BaB7SR24Q4Qvs8NrCpatRkkZiPXf9mKLID6RxOKxDg,5740
|
5
|
-
fastlife/configurator/registry.py,sha256=VBwKWPZROzE0aQgQdqVjurLAwkh9VxpwvaKzain6Nxk,1449
|
6
|
-
fastlife/configurator/settings.py,sha256=RrTE-T7CieXwg-WI5Q1eGZA8PbawJLmLxX7puX4dHbQ,1387
|
7
|
-
fastlife/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
fastlife/request/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
-
fastlife/request/form_data.py,sha256=gKXo92ZwsMX6UpMkf4BlNYDiOfwxyzDzItc_lpplAzY,3642
|
10
|
-
fastlife/security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
-
fastlife/security/csrf.py,sha256=47epJVJtr5X6j-Hog54WCGOoiRLQQHvgBU71iqR1N0A,1025
|
12
|
-
fastlife/security/policy.py,sha256=5jV5nypy5O8XPFFRJ_bzG8Ltk5xcPWclkz23qiG1_I8,509
|
13
|
-
fastlife/session/__init__.py,sha256=OnzRCYRzc1lw9JB0UdKi-aRLPNT2n8mM8kwY1P4w7uU,838
|
14
|
-
fastlife/session/middleware.py,sha256=JgXdBlxlm9zIEgXcidbBrMAp5wJVPsZWtvCLVDk5h2s,3049
|
15
|
-
fastlife/session/serializer.py,sha256=qpVnHQjYTxw3aOnoEOKIjOFJg2z45KjiX5sipWk2gws,1458
|
16
|
-
fastlife/shared_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
-
fastlife/shared_utils/infer.py,sha256=_hmGzu84VlZAkdw_owkW8eHknULqH3MLDBlXj7LkEsc,466
|
18
|
-
fastlife/shared_utils/resolver.py,sha256=wXQQTB4jf86m4qENhMOkHkWpLJj_T4-_eND_ItTLnTE,1410
|
19
|
-
fastlife/templates/A.jinja,sha256=sQov2Hze4NfpmQ3FOYHeXugOb_SZw6ncvDZNyCxy0HI,481
|
20
|
-
fastlife/templates/Button.jinja,sha256=KK3AztRIvBXZh2jUXMrBiz80XEt9s9STfBiVKR_1FvA,1064
|
21
|
-
fastlife/templates/Checkbox.jinja,sha256=SZJYgijSr9rGBSLZC4DXyHpoFNLnC1QyvgpUUkbi9xE,98
|
22
|
-
fastlife/templates/CsrfToken.jinja,sha256=CZrkuKJNIpcsZ3yBvQ4csUcBSHu2xJ13q11DI5VAgcI,80
|
23
|
-
fastlife/templates/Form.jinja,sha256=Z-YrJioBlxSkh-xKDcXmBA7sV2vkzSzMqSjQFEe5AGU,147
|
24
|
-
fastlife/templates/H1.jinja,sha256=jQb4mtR_kipxrwN7cH6Ha9otNP9r1SJhPJF6RiXu-Bw,151
|
25
|
-
fastlife/templates/H2.jinja,sha256=WGyjUhuh2UL-iGGhHLwCeHTMGMEEewZ1683VZxIhMfY,151
|
26
|
-
fastlife/templates/Hidden.jinja,sha256=nOGfkWwhXckJE2O4wL5IXNKB5dvU0HbmdWCTECxEFHs,120
|
27
|
-
fastlife/templates/Input.jinja,sha256=2GQ-7a9woZaz3JRghe-E09p5sP7q1B3wU9ZWsPVee54,612
|
28
|
-
fastlife/templates/Label.jinja,sha256=QVw9R9Wf5vV51dsdLaJUxv6hV2AiURdkGSRJ2-RgZ9Y,147
|
29
|
-
fastlife/templates/Option.jinja,sha256=zxY0l5cBgyv37fEo5jldtYvQoQNNIvtzQV1MLu-4reU,65
|
30
|
-
fastlife/templates/Radio.jinja,sha256=RNqN2RkekqOXIne9b1PhuOV_fZSCWD2Ws8fYeBvBucQ,654
|
31
|
-
fastlife/templates/Select.jinja,sha256=DVheZlrxrcQGClyE5g44V9JInkPcV13v4cUGHNEbiWs,407
|
32
|
-
fastlife/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
33
|
-
fastlife/templates/pydantic_form/Boolean.jinja,sha256=OLgifXvyqDB2T3w8V6oNZCa1DO5G6WgNe-0jB8lQAE0,279
|
34
|
-
fastlife/templates/pydantic_form/Dropdown.jinja,sha256=DKP_vcC89W4PLQL2QwzUiPiDx94gBre5fYejRn_qtGM,539
|
35
|
-
fastlife/templates/pydantic_form/Hidden.jinja,sha256=n6CbTSwZr2E_oY8TO2WPbnrLHBaWfe_CXVCYOYmCfts,83
|
36
|
-
fastlife/templates/pydantic_form/Model.jinja,sha256=tvaK6rnGzonBsRtyi-jxtxRVRpyC3tM0FgIS5ZLjIQo,493
|
37
|
-
fastlife/templates/pydantic_form/Sequence.jinja,sha256=2HDlTmmsd87WEIn3WSYOrC4MePHAybgS_64j8cbJVrI,1409
|
38
|
-
fastlife/templates/pydantic_form/Text.jinja,sha256=TrxKR-xLeBC8Bw1KyBj22YaJysLhdF-6N6LeT_oZous,503
|
39
|
-
fastlife/templates/pydantic_form/Union.jinja,sha256=W5r7KHIL2A_2Vc8Z4xtwTQzeVBEkY1wVqzMMLvmvG60,1003
|
40
|
-
fastlife/templates/pydantic_form/Widget.jinja,sha256=8raoMjtO4ARBfbz8EG-HKT112KkrWG82BbUfbXpAmZs,287
|
41
|
-
fastlife/templating/__init__.py,sha256=RKqAsVyy0mS5qiujpmRbbe-FL1exf46Zo71_0QJwmrA,220
|
42
|
-
fastlife/templating/binding.py,sha256=XlABwvd1UFt6ymbcqLOR_MXz6HlXkwpdlIiKhAgD5F0,1907
|
43
|
-
fastlife/templating/renderer/__init__.py,sha256=ndygjyodU5F8EVzBLVvXq5fLpnPo5lTyk6yia79RHJY,156
|
44
|
-
fastlife/templating/renderer/abstract.py,sha256=qVQ3d7gyesKx6Pz25XN0-NuI2088oKvkOUjGHiT1ALk,801
|
45
|
-
fastlife/templating/renderer/jinjax.py,sha256=dfdaq3KuZXA1Jnmny_cIzcVzLXvr9ESqcgQIrLRlaQ0,2379
|
46
|
-
fastlife/templating/renderer/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
47
|
-
fastlife/templating/renderer/widgets/base.py,sha256=EnztAzopgEJMQMNf3xyOlf9P3i4pZzq15uSK5bf9wfg,2446
|
48
|
-
fastlife/templating/renderer/widgets/boolean.py,sha256=RVp2jLeVR3f6JHl-9yBDZHcr-p2qufw0NVm12D_62aU,454
|
49
|
-
fastlife/templating/renderer/widgets/dropdown.py,sha256=TuNxww-2yqTM3pdqG_gMYD3r9BWVxbhniFBx2l7Gfg8,891
|
50
|
-
fastlife/templating/renderer/widgets/factory.py,sha256=oz_qKiMgTmPmE8mQSXY8aLgPc6u4tUArTJtJ2y66vbo,9626
|
51
|
-
fastlife/templating/renderer/widgets/hidden.py,sha256=PP_mOR2cd9LQURHDrfJ3b85pR3F1SEzsv7n_UhUq-dA,317
|
52
|
-
fastlife/templating/renderer/widgets/model.py,sha256=t0MatCCA6pUsilcQ3ZTyK9a2LtWTbFzdrBFyQ3sqv6k,943
|
53
|
-
fastlife/templating/renderer/widgets/sequence.py,sha256=7nHl8je6oWfwn0jbHLau_S_vF-pbB_Alzjtwv5I4ejg,1355
|
54
|
-
fastlife/templating/renderer/widgets/text.py,sha256=_bmr6FMMFW_oZZdZa_4TH3DfcBpAjOdzm2a5yoonW7o,782
|
55
|
-
fastlife/templating/renderer/widgets/union.py,sha256=VKfjikIujNATxEslPTVydwzA8EOu_l_sPlOgK_cGcrc,1658
|
56
|
-
fastlife/testing/__init__.py,sha256=KgTlRI0g8z7HRpL7mD5QgI__LT9Y4QDSzKMlxJG3wNk,67
|
57
|
-
fastlife/testing/testclient.py,sha256=7aYCHSd0EjsmN4zMboDEh3-xcAZdw7LTvtovaDGZGrg,13780
|
58
|
-
fastlife/views/__init__.py,sha256=nn4B_8YTbTmhGPvSd20yyKK_9Dh1Pfh_Iq7z6iK8-CE,154
|
59
|
-
fastlife/views/pydantic_form.py,sha256=5UymAhbhxsNbs_kjSKI5DEk_jeiCAgtbJofYG_ukcSA,1038
|
60
|
-
fastlifeweb-0.3.1.dist-info/LICENSE,sha256=F75xSseSKMwqzFj8rswYU6NWS3VoWOc_gY3fJYf9_LI,1504
|
61
|
-
fastlifeweb-0.3.1.dist-info/METADATA,sha256=uQeIQW_FI5D-pzVE6GkWSJEXDbPIEdbWPIg83GQx448,1748
|
62
|
-
fastlifeweb-0.3.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
63
|
-
fastlifeweb-0.3.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|