fastlifeweb 0.16.3__py3-none-any.whl → 0.17.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/adapters/jinjax/renderer.py +49 -25
- fastlife/adapters/jinjax/widget_factory/__init__.py +1 -0
- fastlife/adapters/jinjax/widget_factory/base.py +38 -0
- fastlife/adapters/jinjax/widget_factory/bool_builder.py +43 -0
- fastlife/adapters/jinjax/widget_factory/emailstr_builder.py +46 -0
- fastlife/adapters/jinjax/widget_factory/enum_builder.py +47 -0
- fastlife/adapters/jinjax/widget_factory/factory.py +165 -0
- fastlife/adapters/jinjax/widget_factory/literal_builder.py +52 -0
- fastlife/adapters/jinjax/widget_factory/model_builder.py +64 -0
- fastlife/adapters/jinjax/widget_factory/secretstr_builder.py +47 -0
- fastlife/adapters/jinjax/widget_factory/sequence_builder.py +58 -0
- fastlife/adapters/jinjax/widget_factory/set_builder.py +80 -0
- fastlife/adapters/jinjax/widget_factory/simpletype_builder.py +47 -0
- fastlife/adapters/jinjax/widget_factory/union_builder.py +90 -0
- fastlife/adapters/jinjax/widgets/base.py +6 -4
- fastlife/adapters/jinjax/widgets/checklist.py +1 -1
- fastlife/adapters/jinjax/widgets/dropdown.py +7 -7
- fastlife/adapters/jinjax/widgets/hidden.py +2 -0
- fastlife/adapters/jinjax/widgets/model.py +4 -1
- fastlife/adapters/jinjax/widgets/sequence.py +3 -2
- fastlife/adapters/jinjax/widgets/text.py +9 -10
- fastlife/adapters/jinjax/widgets/union.py +9 -7
- fastlife/components/Form.jinja +12 -0
- fastlife/config/configurator.py +23 -24
- fastlife/config/exceptions.py +4 -1
- fastlife/config/openapiextra.py +1 -0
- fastlife/config/resources.py +26 -27
- fastlife/config/settings.py +2 -0
- fastlife/config/views.py +3 -1
- fastlife/middlewares/reverse_proxy/x_forwarded.py +22 -15
- fastlife/middlewares/session/middleware.py +2 -2
- fastlife/middlewares/session/serializer.py +6 -5
- fastlife/request/form.py +7 -6
- fastlife/request/form_data.py +2 -6
- fastlife/routing/route.py +3 -1
- fastlife/routing/router.py +1 -0
- fastlife/security/csrf.py +2 -1
- fastlife/security/policy.py +2 -1
- fastlife/services/locale_negociator.py +2 -1
- fastlife/services/policy.py +3 -2
- fastlife/services/templates.py +2 -1
- fastlife/services/translations.py +15 -8
- fastlife/shared_utils/infer.py +4 -3
- fastlife/shared_utils/resolver.py +64 -4
- fastlife/templates/binding.py +2 -1
- fastlife/testing/__init__.py +1 -0
- fastlife/testing/dom.py +140 -0
- fastlife/testing/form.py +204 -0
- fastlife/testing/session.py +67 -0
- fastlife/testing/testclient.py +7 -390
- fastlife/views/pydantic_form.py +4 -4
- {fastlifeweb-0.16.3.dist-info → fastlifeweb-0.17.0.dist-info}/METADATA +6 -6
- {fastlifeweb-0.16.3.dist-info → fastlifeweb-0.17.0.dist-info}/RECORD +55 -40
- fastlife/adapters/jinjax/widgets/factory.py +0 -525
- {fastlifeweb-0.16.3.dist-info → fastlifeweb-0.17.0.dist-info}/LICENSE +0 -0
- {fastlifeweb-0.16.3.dist-info → fastlifeweb-0.17.0.dist-info}/WHEEL +0 -0
@@ -1,525 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Transform.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import secrets
|
6
|
-
from collections.abc import MutableSequence, Sequence
|
7
|
-
from decimal import Decimal
|
8
|
-
from enum import Enum
|
9
|
-
from inspect import isclass
|
10
|
-
from types import NoneType
|
11
|
-
from typing import Any, Literal, Mapping, Type, cast, get_origin
|
12
|
-
from uuid import UUID
|
13
|
-
|
14
|
-
from markupsafe import Markup
|
15
|
-
from pydantic import BaseModel, EmailStr, SecretStr, ValidationError
|
16
|
-
from pydantic.fields import FieldInfo
|
17
|
-
|
18
|
-
from fastlife.adapters.jinjax.widgets.base import Widget
|
19
|
-
from fastlife.adapters.jinjax.widgets.boolean import BooleanWidget
|
20
|
-
from fastlife.adapters.jinjax.widgets.checklist import Checkable, ChecklistWidget
|
21
|
-
from fastlife.adapters.jinjax.widgets.dropdown import DropDownWidget
|
22
|
-
from fastlife.adapters.jinjax.widgets.hidden import HiddenWidget
|
23
|
-
from fastlife.adapters.jinjax.widgets.model import ModelWidget
|
24
|
-
from fastlife.adapters.jinjax.widgets.sequence import SequenceWidget
|
25
|
-
from fastlife.adapters.jinjax.widgets.text import TextWidget
|
26
|
-
from fastlife.adapters.jinjax.widgets.union import UnionWidget
|
27
|
-
from fastlife.request.form import FormModel
|
28
|
-
from fastlife.services.templates import AbstractTemplateRenderer
|
29
|
-
from fastlife.shared_utils.infer import is_complex_type, is_union
|
30
|
-
|
31
|
-
|
32
|
-
class WidgetFactory:
|
33
|
-
"""
|
34
|
-
Form builder for pydantic model.
|
35
|
-
|
36
|
-
:param renderer: template engine to render widget.
|
37
|
-
:param token: reuse a token.
|
38
|
-
"""
|
39
|
-
|
40
|
-
def __init__(self, renderer: AbstractTemplateRenderer, token: str | None = None):
|
41
|
-
self.renderer = renderer
|
42
|
-
self.token = token or secrets.token_urlsafe(4).replace("_", "-")
|
43
|
-
|
44
|
-
def get_markup(
|
45
|
-
self,
|
46
|
-
model: FormModel[Any],
|
47
|
-
*,
|
48
|
-
removable: bool = False,
|
49
|
-
field: FieldInfo | None = None,
|
50
|
-
) -> Markup:
|
51
|
-
return self.get_widget(
|
52
|
-
model.model.__class__,
|
53
|
-
model.form_data,
|
54
|
-
model.errors,
|
55
|
-
prefix=model.prefix,
|
56
|
-
removable=removable,
|
57
|
-
field=field,
|
58
|
-
).to_html(self.renderer)
|
59
|
-
|
60
|
-
def get_widget(
|
61
|
-
self,
|
62
|
-
base: Type[Any],
|
63
|
-
form_data: Mapping[str, Any],
|
64
|
-
form_errors: Mapping[str, Any],
|
65
|
-
*,
|
66
|
-
prefix: str,
|
67
|
-
removable: bool,
|
68
|
-
field: FieldInfo | None = None,
|
69
|
-
) -> Widget[Any]:
|
70
|
-
return self.build(
|
71
|
-
base,
|
72
|
-
value=form_data.get(prefix, {}),
|
73
|
-
form_errors=form_errors,
|
74
|
-
name=prefix,
|
75
|
-
removable=removable,
|
76
|
-
field=field,
|
77
|
-
)
|
78
|
-
|
79
|
-
def build(
|
80
|
-
self,
|
81
|
-
typ: Type[Any],
|
82
|
-
*,
|
83
|
-
name: str = "",
|
84
|
-
value: Any,
|
85
|
-
removable: bool,
|
86
|
-
form_errors: Mapping[str, Any],
|
87
|
-
field: FieldInfo | None = None,
|
88
|
-
) -> Widget[Any]:
|
89
|
-
if field and field.metadata:
|
90
|
-
for widget in field.metadata:
|
91
|
-
if isclass(widget) and issubclass(widget, Widget):
|
92
|
-
return cast(
|
93
|
-
Widget[Any],
|
94
|
-
widget(
|
95
|
-
name,
|
96
|
-
value=value,
|
97
|
-
removable=removable,
|
98
|
-
title=field.title if field else "",
|
99
|
-
hint=field.description if field else None,
|
100
|
-
aria_label=(
|
101
|
-
field.json_schema_extra.get("aria_label") # type:ignore
|
102
|
-
if field and field.json_schema_extra
|
103
|
-
else None
|
104
|
-
),
|
105
|
-
token=self.token,
|
106
|
-
error=form_errors.get(name),
|
107
|
-
),
|
108
|
-
)
|
109
|
-
|
110
|
-
type_origin = get_origin(typ)
|
111
|
-
if type_origin:
|
112
|
-
if is_union(typ):
|
113
|
-
return self.build_union(name, typ, field, value, form_errors, removable)
|
114
|
-
|
115
|
-
if (
|
116
|
-
type_origin is Sequence
|
117
|
-
or type_origin is MutableSequence
|
118
|
-
or type_origin is list
|
119
|
-
):
|
120
|
-
return self.build_sequence(
|
121
|
-
name, typ, field, value, form_errors, removable
|
122
|
-
)
|
123
|
-
|
124
|
-
if type_origin is Literal:
|
125
|
-
return self.build_literal(
|
126
|
-
name, typ, field, value, form_errors, removable
|
127
|
-
)
|
128
|
-
|
129
|
-
if type_origin is set:
|
130
|
-
return self.build_set(name, typ, field, value, form_errors, removable)
|
131
|
-
|
132
|
-
if issubclass(typ, Enum): # if it raises here, the type_origin is unknown
|
133
|
-
return self.build_enum(name, typ, field, value, form_errors, removable)
|
134
|
-
|
135
|
-
if issubclass(typ, BaseModel): # if it raises here, the type_origin is unknown
|
136
|
-
return self.build_model(
|
137
|
-
name, typ, field, value or {}, form_errors, removable
|
138
|
-
)
|
139
|
-
|
140
|
-
if issubclass(typ, bool):
|
141
|
-
return self.build_boolean(
|
142
|
-
name, typ, field, value or False, form_errors, removable
|
143
|
-
)
|
144
|
-
|
145
|
-
if issubclass(typ, EmailStr): # type: ignore
|
146
|
-
return self.build_emailtype(
|
147
|
-
name, typ, field, value or "", form_errors, removable
|
148
|
-
)
|
149
|
-
|
150
|
-
if issubclass(typ, SecretStr):
|
151
|
-
return self.build_secretstr(
|
152
|
-
name, typ, field, value or "", form_errors, removable
|
153
|
-
)
|
154
|
-
|
155
|
-
if issubclass(typ, (int, str, float, Decimal, UUID)):
|
156
|
-
return self.build_simpletype(
|
157
|
-
name, typ, field, value or "", form_errors, removable
|
158
|
-
)
|
159
|
-
|
160
|
-
raise NotImplementedError(f"{typ} not implemented") # coverage: ignore
|
161
|
-
|
162
|
-
def build_model(
|
163
|
-
self,
|
164
|
-
field_name: str,
|
165
|
-
typ: Type[BaseModel],
|
166
|
-
field: FieldInfo | None,
|
167
|
-
value: Mapping[str, Any],
|
168
|
-
form_errors: Mapping[str, Any],
|
169
|
-
removable: bool,
|
170
|
-
) -> Widget[Any]:
|
171
|
-
ret: dict[str, Any] = {}
|
172
|
-
for key, child_field in typ.model_fields.items():
|
173
|
-
child_key = f"{field_name}.{key}" if field_name else key
|
174
|
-
if child_field.exclude:
|
175
|
-
continue
|
176
|
-
if child_field.annotation is None:
|
177
|
-
raise ValueError( # coverage: ignore
|
178
|
-
f"Missing annotation for {child_field} in {child_key}"
|
179
|
-
)
|
180
|
-
ret[key] = self.build(
|
181
|
-
child_field.annotation,
|
182
|
-
name=child_key,
|
183
|
-
field=child_field,
|
184
|
-
value=value.get(key),
|
185
|
-
form_errors=form_errors,
|
186
|
-
removable=False,
|
187
|
-
)
|
188
|
-
return ModelWidget(
|
189
|
-
field_name,
|
190
|
-
value=list(ret.values()),
|
191
|
-
removable=removable,
|
192
|
-
title=field.title if field and field.title else "",
|
193
|
-
hint=field.description if field else None,
|
194
|
-
aria_label=(
|
195
|
-
field.json_schema_extra.get("aria_label") # type:ignore
|
196
|
-
if field and field.json_schema_extra
|
197
|
-
else None
|
198
|
-
),
|
199
|
-
token=self.token,
|
200
|
-
error=form_errors.get(field_name),
|
201
|
-
nested=field is not None,
|
202
|
-
)
|
203
|
-
|
204
|
-
def build_union(
|
205
|
-
self,
|
206
|
-
field_name: str,
|
207
|
-
field_type: Type[Any],
|
208
|
-
field: FieldInfo | None,
|
209
|
-
value: Any,
|
210
|
-
form_errors: Mapping[str, Any],
|
211
|
-
removable: bool,
|
212
|
-
) -> Widget[Any]:
|
213
|
-
types: list[Type[Any]] = []
|
214
|
-
# required = True
|
215
|
-
for typ in field_type.__args__: # type: ignore
|
216
|
-
if typ is NoneType:
|
217
|
-
# required = False
|
218
|
-
continue
|
219
|
-
types.append(typ) # type: ignore
|
220
|
-
|
221
|
-
if (
|
222
|
-
not removable
|
223
|
-
and len(types) == 1
|
224
|
-
# if the optional type is a complex type,
|
225
|
-
and not is_complex_type(types[0])
|
226
|
-
):
|
227
|
-
return self.build(
|
228
|
-
types[0],
|
229
|
-
name=field_name,
|
230
|
-
field=field,
|
231
|
-
value=value,
|
232
|
-
form_errors=form_errors,
|
233
|
-
removable=False,
|
234
|
-
)
|
235
|
-
child = None
|
236
|
-
if value:
|
237
|
-
for typ in types:
|
238
|
-
try:
|
239
|
-
typ(**value)
|
240
|
-
except ValidationError:
|
241
|
-
pass
|
242
|
-
else:
|
243
|
-
child = self.build(
|
244
|
-
typ,
|
245
|
-
name=field_name,
|
246
|
-
field=field,
|
247
|
-
value=value,
|
248
|
-
form_errors=form_errors,
|
249
|
-
removable=False,
|
250
|
-
)
|
251
|
-
|
252
|
-
widget = UnionWidget(
|
253
|
-
field_name,
|
254
|
-
# we assume those types are BaseModel
|
255
|
-
value=child,
|
256
|
-
children_types=types, # type: ignore
|
257
|
-
title=field.title if field else "",
|
258
|
-
hint=field.description if field else None,
|
259
|
-
aria_label=(
|
260
|
-
field.json_schema_extra.get("aria_label") # type:ignore
|
261
|
-
if field and field.json_schema_extra
|
262
|
-
else None
|
263
|
-
),
|
264
|
-
token=self.token,
|
265
|
-
removable=removable,
|
266
|
-
error=form_errors.get(field_name),
|
267
|
-
)
|
268
|
-
|
269
|
-
return widget
|
270
|
-
|
271
|
-
def build_sequence(
|
272
|
-
self,
|
273
|
-
field_name: str,
|
274
|
-
field_type: Type[Any],
|
275
|
-
field: FieldInfo | None,
|
276
|
-
value: Sequence[Any] | None,
|
277
|
-
form_errors: Mapping[str, Any],
|
278
|
-
removable: bool,
|
279
|
-
) -> Widget[Any]:
|
280
|
-
typ = field_type.__args__[0] # type: ignore
|
281
|
-
value = value or []
|
282
|
-
items = [
|
283
|
-
self.build(
|
284
|
-
typ, # type: ignore
|
285
|
-
name=f"{field_name}.{idx}",
|
286
|
-
value=v,
|
287
|
-
field=field,
|
288
|
-
form_errors=form_errors,
|
289
|
-
removable=True,
|
290
|
-
)
|
291
|
-
for idx, v in enumerate(value)
|
292
|
-
]
|
293
|
-
return SequenceWidget(
|
294
|
-
field_name,
|
295
|
-
title=field.title if field else "",
|
296
|
-
hint=field.description if field else None,
|
297
|
-
aria_label=(
|
298
|
-
field.json_schema_extra.get("aria_label") # type:ignore
|
299
|
-
if field and field.json_schema_extra
|
300
|
-
else None
|
301
|
-
),
|
302
|
-
value=items,
|
303
|
-
item_type=typ, # type: ignore
|
304
|
-
token=self.token,
|
305
|
-
removable=removable,
|
306
|
-
error=form_errors.get(field_name),
|
307
|
-
)
|
308
|
-
|
309
|
-
def build_set(
|
310
|
-
self,
|
311
|
-
field_name: str,
|
312
|
-
field_type: Type[Any],
|
313
|
-
field: FieldInfo | None,
|
314
|
-
value: Sequence[Any] | None,
|
315
|
-
form_errors: Mapping[str, Any],
|
316
|
-
removable: bool,
|
317
|
-
) -> Widget[Any]:
|
318
|
-
choice_wrapper = field_type.__args__[0]
|
319
|
-
choices = []
|
320
|
-
choice_wrapper_origin = get_origin(choice_wrapper)
|
321
|
-
if choice_wrapper_origin:
|
322
|
-
if choice_wrapper_origin is Literal:
|
323
|
-
litchoice: list[str] = choice_wrapper.__args__ # type: ignore
|
324
|
-
choices = [
|
325
|
-
Checkable(
|
326
|
-
label=c,
|
327
|
-
value=c,
|
328
|
-
checked=c in value if value else False, # type: ignore
|
329
|
-
name=field_name,
|
330
|
-
token=self.token,
|
331
|
-
error=form_errors.get(f"{field_name}-{c}"),
|
332
|
-
)
|
333
|
-
for c in litchoice
|
334
|
-
]
|
335
|
-
|
336
|
-
else:
|
337
|
-
raise NotImplementedError
|
338
|
-
elif issubclass(choice_wrapper, Enum):
|
339
|
-
choices = [
|
340
|
-
Checkable(
|
341
|
-
label=e.value,
|
342
|
-
value=e.name,
|
343
|
-
checked=e.name in value if value else False, # type: ignore
|
344
|
-
name=field_name,
|
345
|
-
token=self.token,
|
346
|
-
error=form_errors.get(f"{field_name}-{e.name}"),
|
347
|
-
)
|
348
|
-
for e in choice_wrapper
|
349
|
-
]
|
350
|
-
else:
|
351
|
-
raise NotImplementedError
|
352
|
-
|
353
|
-
return ChecklistWidget(
|
354
|
-
field_name,
|
355
|
-
title=field.title if field else "",
|
356
|
-
hint=field.description if field else None,
|
357
|
-
aria_label=(
|
358
|
-
field.json_schema_extra.get("aria_label") # type:ignore
|
359
|
-
if field and field.json_schema_extra
|
360
|
-
else None
|
361
|
-
),
|
362
|
-
token=self.token,
|
363
|
-
value=choices,
|
364
|
-
removable=removable,
|
365
|
-
error=form_errors.get(field_name),
|
366
|
-
)
|
367
|
-
|
368
|
-
def build_boolean(
|
369
|
-
self,
|
370
|
-
field_name: str,
|
371
|
-
field_type: Type[Any],
|
372
|
-
field: FieldInfo | None,
|
373
|
-
value: bool,
|
374
|
-
form_errors: Mapping[str, Any],
|
375
|
-
removable: bool,
|
376
|
-
) -> Widget[Any]:
|
377
|
-
return BooleanWidget(
|
378
|
-
field_name,
|
379
|
-
removable=removable,
|
380
|
-
title=field.title if field else "",
|
381
|
-
hint=field.description if field else None,
|
382
|
-
aria_label=(
|
383
|
-
field.json_schema_extra.get("aria_label") # type:ignore
|
384
|
-
if field and field.json_schema_extra
|
385
|
-
else None
|
386
|
-
),
|
387
|
-
token=self.token,
|
388
|
-
value=value,
|
389
|
-
error=form_errors.get(field_name),
|
390
|
-
)
|
391
|
-
|
392
|
-
def build_emailtype(
|
393
|
-
self,
|
394
|
-
field_name: str,
|
395
|
-
field_type: Type[Any],
|
396
|
-
field: FieldInfo | None,
|
397
|
-
value: str | int | float,
|
398
|
-
form_errors: Mapping[str, Any],
|
399
|
-
removable: bool,
|
400
|
-
) -> Widget[Any]:
|
401
|
-
return TextWidget(
|
402
|
-
field_name,
|
403
|
-
input_type="email",
|
404
|
-
placeholder=str(field.examples[0]) if field and field.examples else None,
|
405
|
-
removable=removable,
|
406
|
-
title=field.title if field else "",
|
407
|
-
hint=field.description if field else None,
|
408
|
-
aria_label=(
|
409
|
-
field.json_schema_extra.get("aria_label") # type:ignore
|
410
|
-
if field and field.json_schema_extra
|
411
|
-
else None
|
412
|
-
),
|
413
|
-
token=self.token,
|
414
|
-
value=str(value),
|
415
|
-
error=form_errors.get(field_name),
|
416
|
-
)
|
417
|
-
|
418
|
-
def build_secretstr(
|
419
|
-
self,
|
420
|
-
field_name: str,
|
421
|
-
field_type: Type[Any],
|
422
|
-
field: FieldInfo | None,
|
423
|
-
value: SecretStr | str,
|
424
|
-
form_errors: Mapping[str, Any],
|
425
|
-
removable: bool,
|
426
|
-
) -> Widget[Any]:
|
427
|
-
return TextWidget(
|
428
|
-
field_name,
|
429
|
-
input_type="password",
|
430
|
-
placeholder=str(field.examples[0]) if field and field.examples else None,
|
431
|
-
removable=removable,
|
432
|
-
title=field.title if field else "",
|
433
|
-
hint=field.description if field else None,
|
434
|
-
aria_label=(
|
435
|
-
field.json_schema_extra.get("aria_label") # type:ignore
|
436
|
-
if field and field.json_schema_extra
|
437
|
-
else None
|
438
|
-
),
|
439
|
-
token=self.token,
|
440
|
-
value=value.get_secret_value() if isinstance(value, SecretStr) else value,
|
441
|
-
error=form_errors.get(field_name),
|
442
|
-
)
|
443
|
-
|
444
|
-
def build_literal(
|
445
|
-
self,
|
446
|
-
field_name: str,
|
447
|
-
field_type: Type[Any], # a literal actually
|
448
|
-
field: FieldInfo | None,
|
449
|
-
value: str | int | float,
|
450
|
-
form_errors: Mapping[str, Any],
|
451
|
-
removable: bool,
|
452
|
-
) -> Widget[Any]:
|
453
|
-
choices: list[str] = field_type.__args__ # type: ignore
|
454
|
-
if len(choices) == 1:
|
455
|
-
return HiddenWidget(
|
456
|
-
field_name,
|
457
|
-
value=choices[0],
|
458
|
-
token=self.token,
|
459
|
-
)
|
460
|
-
return DropDownWidget(
|
461
|
-
field_name,
|
462
|
-
options=choices,
|
463
|
-
removable=removable,
|
464
|
-
title=field.title if field else "",
|
465
|
-
hint=field.description if field else None,
|
466
|
-
aria_label=(
|
467
|
-
field.json_schema_extra.get("aria_label") # type:ignore
|
468
|
-
if field and field.json_schema_extra
|
469
|
-
else None
|
470
|
-
),
|
471
|
-
token=self.token,
|
472
|
-
value=str(value),
|
473
|
-
error=form_errors.get(field_name),
|
474
|
-
)
|
475
|
-
|
476
|
-
def build_enum(
|
477
|
-
self,
|
478
|
-
field_name: str,
|
479
|
-
field_type: Type[Any], # an enum subclass
|
480
|
-
field: FieldInfo | None,
|
481
|
-
value: str | int | float,
|
482
|
-
form_errors: Mapping[str, Any],
|
483
|
-
removable: bool,
|
484
|
-
) -> Widget[Any]:
|
485
|
-
options = [(item.name, item.value) for item in field_type] # type: ignore
|
486
|
-
return DropDownWidget(
|
487
|
-
field_name,
|
488
|
-
options=options, # type: ignore
|
489
|
-
removable=removable,
|
490
|
-
title=field.title if field else "",
|
491
|
-
hint=field.description if field else None,
|
492
|
-
aria_label=(
|
493
|
-
field.json_schema_extra.get("aria_label") # type:ignore
|
494
|
-
if field and field.json_schema_extra
|
495
|
-
else None
|
496
|
-
),
|
497
|
-
token=self.token,
|
498
|
-
value=str(value),
|
499
|
-
error=form_errors.get(field_name),
|
500
|
-
)
|
501
|
-
|
502
|
-
def build_simpletype(
|
503
|
-
self,
|
504
|
-
field_name: str,
|
505
|
-
field_type: Type[Any],
|
506
|
-
field: FieldInfo | None,
|
507
|
-
value: str | int | float,
|
508
|
-
form_errors: Mapping[str, Any],
|
509
|
-
removable: bool,
|
510
|
-
) -> Widget[Any]:
|
511
|
-
return TextWidget(
|
512
|
-
field_name,
|
513
|
-
placeholder=str(field.examples[0]) if field and field.examples else None,
|
514
|
-
title=field.title if field else "",
|
515
|
-
hint=field.description if field else None,
|
516
|
-
aria_label=(
|
517
|
-
field.json_schema_extra.get("aria_label") # type:ignore
|
518
|
-
if field and field.json_schema_extra
|
519
|
-
else None
|
520
|
-
),
|
521
|
-
removable=removable,
|
522
|
-
token=self.token,
|
523
|
-
value=str(value),
|
524
|
-
error=form_errors.get(field_name),
|
525
|
-
)
|
File without changes
|
File without changes
|