fh-pydantic-form 0.2.4__py3-none-any.whl → 0.2.5__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.
Potentially problematic release.
This version of fh-pydantic-form might be problematic. Click here for more details.
- fh_pydantic_form/form_parser.py +40 -17
- {fh_pydantic_form-0.2.4.dist-info → fh_pydantic_form-0.2.5.dist-info}/METADATA +1 -1
- {fh_pydantic_form-0.2.4.dist-info → fh_pydantic_form-0.2.5.dist-info}/RECORD +5 -5
- {fh_pydantic_form-0.2.4.dist-info → fh_pydantic_form-0.2.5.dist-info}/WHEEL +0 -0
- {fh_pydantic_form-0.2.4.dist-info → fh_pydantic_form-0.2.5.dist-info}/licenses/LICENSE +0 -0
fh_pydantic_form/form_parser.py
CHANGED
|
@@ -7,6 +7,8 @@ from typing import (
|
|
|
7
7
|
Optional,
|
|
8
8
|
Tuple,
|
|
9
9
|
Union,
|
|
10
|
+
get_origin,
|
|
11
|
+
get_args,
|
|
10
12
|
)
|
|
11
13
|
|
|
12
14
|
from fh_pydantic_form.type_helpers import (
|
|
@@ -33,17 +35,16 @@ def _identify_list_fields(model_class) -> Dict[str, Dict[str, Any]]:
|
|
|
33
35
|
list_fields = {}
|
|
34
36
|
for field_name, field_info in model_class.model_fields.items():
|
|
35
37
|
annotation = getattr(field_info, "annotation", None)
|
|
36
|
-
if
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
38
|
+
if annotation is not None:
|
|
39
|
+
# Handle Optional[List[...]] by unwrapping the Optional
|
|
40
|
+
base_ann = _get_underlying_type_if_optional(annotation)
|
|
41
|
+
if get_origin(base_ann) is list:
|
|
42
|
+
item_type = get_args(base_ann)[0]
|
|
43
|
+
list_fields[field_name] = {
|
|
44
|
+
"item_type": item_type,
|
|
45
|
+
"is_model_type": hasattr(item_type, "model_fields"),
|
|
46
|
+
"field_info": field_info, # Store for later use if needed
|
|
47
|
+
}
|
|
47
48
|
return list_fields
|
|
48
49
|
|
|
49
50
|
|
|
@@ -128,9 +129,14 @@ def _parse_non_list_fields(
|
|
|
128
129
|
# Get the nested model class (unwrap Optional if needed)
|
|
129
130
|
nested_model_class = _get_underlying_type_if_optional(annotation)
|
|
130
131
|
|
|
131
|
-
# Parse the nested model - pass the base_prefix
|
|
132
|
+
# Parse the nested model - pass the base_prefix and exclude_fields
|
|
132
133
|
nested_value = _parse_nested_model_field(
|
|
133
|
-
field_name,
|
|
134
|
+
field_name,
|
|
135
|
+
form_data,
|
|
136
|
+
nested_model_class,
|
|
137
|
+
field_info,
|
|
138
|
+
base_prefix,
|
|
139
|
+
exclude_fields,
|
|
134
140
|
)
|
|
135
141
|
|
|
136
142
|
# Only assign if we got a non-None value or the field is not optional
|
|
@@ -270,6 +276,7 @@ def _parse_nested_model_field(
|
|
|
270
276
|
nested_model_class,
|
|
271
277
|
field_info,
|
|
272
278
|
parent_prefix: str = "",
|
|
279
|
+
exclude_fields: Optional[List[str]] = None,
|
|
273
280
|
) -> Optional[Dict[str, Any]]:
|
|
274
281
|
"""
|
|
275
282
|
Parse a nested Pydantic model field from form data.
|
|
@@ -351,6 +358,7 @@ def _parse_nested_model_field(
|
|
|
351
358
|
form_data,
|
|
352
359
|
nested_list_defs,
|
|
353
360
|
current_prefix, # ← prefix for this nested model
|
|
361
|
+
exclude_fields, # Pass through exclude_fields
|
|
354
362
|
)
|
|
355
363
|
# Merge without clobbering keys already set in step 1
|
|
356
364
|
for lf_name, lf_val in list_results.items():
|
|
@@ -432,6 +440,7 @@ def _parse_list_fields(
|
|
|
432
440
|
form_data: Dict[str, Any],
|
|
433
441
|
list_field_defs: Dict[str, Dict[str, Any]],
|
|
434
442
|
base_prefix: str = "",
|
|
443
|
+
exclude_fields: Optional[List[str]] = None,
|
|
435
444
|
) -> Dict[str, List[Any]]:
|
|
436
445
|
"""
|
|
437
446
|
Parse list fields from form data by analyzing keys and reconstructing ordered lists.
|
|
@@ -440,10 +449,13 @@ def _parse_list_fields(
|
|
|
440
449
|
form_data: Dictionary containing form field data
|
|
441
450
|
list_field_defs: Dictionary of list field definitions
|
|
442
451
|
base_prefix: Prefix to use when looking up field names in form_data
|
|
452
|
+
exclude_fields: Optional list of field names to exclude from parsing
|
|
443
453
|
|
|
444
454
|
Returns:
|
|
445
455
|
Dictionary with parsed list fields
|
|
446
456
|
"""
|
|
457
|
+
exclude_fields = exclude_fields or []
|
|
458
|
+
|
|
447
459
|
# Skip if no list fields defined
|
|
448
460
|
if not list_field_defs:
|
|
449
461
|
return {}
|
|
@@ -525,9 +537,18 @@ def _parse_list_fields(
|
|
|
525
537
|
if items: # Only add if items were found
|
|
526
538
|
final_lists[field_name] = items
|
|
527
539
|
|
|
528
|
-
#
|
|
529
|
-
|
|
530
|
-
|
|
540
|
+
# Ensure every rendered list field appears in final_lists
|
|
541
|
+
for field_name, field_def in list_field_defs.items():
|
|
542
|
+
# Skip list fields the UI never showed (those in exclude_fields)
|
|
543
|
+
if field_name in exclude_fields:
|
|
544
|
+
continue
|
|
545
|
+
|
|
546
|
+
# When user supplied ≥1 item we already captured it
|
|
547
|
+
if field_name in final_lists:
|
|
548
|
+
continue
|
|
549
|
+
|
|
550
|
+
# User submitted form with zero items → honour intent with empty list
|
|
551
|
+
final_lists[field_name] = []
|
|
531
552
|
|
|
532
553
|
return final_lists
|
|
533
554
|
|
|
@@ -560,7 +581,9 @@ def _parse_model_list_item(
|
|
|
560
581
|
)
|
|
561
582
|
# 2. Parse inner lists
|
|
562
583
|
result.update(
|
|
563
|
-
_parse_list_fields(
|
|
584
|
+
_parse_list_fields(
|
|
585
|
+
form_data, nested_list_defs, base_prefix=item_prefix, exclude_fields=[]
|
|
586
|
+
)
|
|
564
587
|
)
|
|
565
588
|
return result
|
|
566
589
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fh-pydantic-form
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: a library to turn any pydantic BaseModel object into a fasthtml/monsterui input form
|
|
5
5
|
Project-URL: Homepage, https://github.com/Marcura/fh-pydantic-form
|
|
6
6
|
Project-URL: Repository, https://github.com/Marcura/fh-pydantic-form
|
|
@@ -2,14 +2,14 @@ fh_pydantic_form/__init__.py,sha256=luxohu6NgZDC0nhSIyw5lJGP2A8JQ51Ge1Ga7DYDkF8,
|
|
|
2
2
|
fh_pydantic_form/constants.py,sha256=-N9wzkibFNn-V6cO8iWTQ7_xBvwSr2hBdq-m3apmW4M,169
|
|
3
3
|
fh_pydantic_form/defaults.py,sha256=Pwv46v7e43cykx4Pt01e4nw-6FBkHmPvTZK36ZTZqgA,6068
|
|
4
4
|
fh_pydantic_form/field_renderers.py,sha256=VYvAmLsLhQttlg97g2KGg-VNlS4ohxrPN1O906EJM6I,54984
|
|
5
|
-
fh_pydantic_form/form_parser.py,sha256=
|
|
5
|
+
fh_pydantic_form/form_parser.py,sha256=mAsE5pE7A27k7zgHg4UD-P3HHQj9FmZneK_z68jLHbo,26117
|
|
6
6
|
fh_pydantic_form/form_renderer.py,sha256=cPd7NbaPOZC8cTvhEZOsy8sf5fH6FomrsR_r6KAFF54,34573
|
|
7
7
|
fh_pydantic_form/list_path.py,sha256=AA8bmDmaYy4rlGIvQOOZ0fP2tgcimNUB2Re5aVGnYc8,5182
|
|
8
8
|
fh_pydantic_form/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
fh_pydantic_form/registry.py,sha256=sufK-85ST3rc3Vu0XmjjjdTqTAqgHr_ZbMGU0xRgTK8,4996
|
|
10
10
|
fh_pydantic_form/type_helpers.py,sha256=FH4yl5FW1KNKvfHzs8TKQinFTC-MUgqDvRTVfPHs1LM,6815
|
|
11
11
|
fh_pydantic_form/ui_style.py,sha256=aIWDWbPBUAQ73nPC5AHZi5cnqA0SIp9ISWwsxFdXXdE,3776
|
|
12
|
-
fh_pydantic_form-0.2.
|
|
13
|
-
fh_pydantic_form-0.2.
|
|
14
|
-
fh_pydantic_form-0.2.
|
|
15
|
-
fh_pydantic_form-0.2.
|
|
12
|
+
fh_pydantic_form-0.2.5.dist-info/METADATA,sha256=0xo0GN6Vj50q9Qb4vQufOaqAs8Fn1w3a3h58elpBbqA,26356
|
|
13
|
+
fh_pydantic_form-0.2.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
+
fh_pydantic_form-0.2.5.dist-info/licenses/LICENSE,sha256=AOi2eNK3D2aDycRHfPRiuACZ7WPBsKHTV2tTYNl7cls,577
|
|
15
|
+
fh_pydantic_form-0.2.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|