@@ -479,52 +479,55 @@ def structure_attrs_fromdict(
479
479
480
480
def _structure_list (self , obj , cl ):
481
481
"""Convert an iterable to a potentially generic list."""
482
- if self . extended_validation :
483
- errors = {}
484
- if is_bare ( cl ) or cl . __args__ [ 0 ] is Any :
485
- res = [ e for e in obj ]
486
- else :
487
- elem_type = cl . __args__ [ 0 ]
488
- handler = self . _structure_func . dispatch ( elem_type )
482
+ if is_bare ( cl ) or cl . __args__ [ 0 ] is Any :
483
+ res = [ e for e in obj ]
484
+ else :
485
+ elem_type = cl . __args__ [ 0 ]
486
+ handler = self . _structure_func . dispatch ( elem_type )
487
+ if self . extended_validation :
488
+ errors = []
489
489
res = []
490
490
ix = 0 # Avoid `enumerate` for performance.
491
491
for e in obj :
492
492
try :
493
493
res .append (handler (e , elem_type ))
494
494
except Exception as e :
495
- errors [ix ] = e
495
+ e .__note__ = f"Structuring iterable @ index { ix } "
496
+ errors .append (e )
496
497
finally :
497
498
ix += 1
498
- if errors :
499
- raise IterableValidationError (errors )
500
- else :
501
- if is_bare (cl ) or cl .__args__ [0 ] is Any :
502
- res = [e for e in obj ]
499
+ if errors :
500
+ raise IterableValidationError (f"While structuring { cl .__name__ } " , errors , cl )
503
501
else :
504
- elem_type = cl .__args__ [0 ]
505
- handler = self ._structure_func .dispatch (elem_type )
506
502
res = [handler (e , elem_type ) for e in obj ]
507
503
return res
508
504
509
- def _structure_set (self , obj , cl ):
505
+ def _structure_set (self , obj , cl , structure_to = set ):
510
506
"""Convert an iterable into a potentially generic set."""
511
507
if is_bare (cl ) or cl .__args__ [0 ] is Any :
512
- return set (obj )
508
+ return structure_to (obj )
509
+ elem_type = cl .__args__ [0 ]
510
+ handler = self ._structure_func .dispatch (elem_type )
511
+ if self .extended_validation :
512
+ errors = []
513
+ res = set ()
514
+ for e in obj :
515
+ try :
516
+ res .add (handler (e , elem_type ))
517
+ except Exception as exc :
518
+ exc .__note__ = f"Structuring { structure_to .__name__ } @ element { e !r} "
519
+ errors .append (exc )
520
+ if errors :
521
+ raise IterableValidationError (f"While structuring { cl .__name__ } " , errors , cl )
522
+ return res if structure_to is set else structure_to (res )
523
+ elif structure_to is set :
524
+ return {handler (e , elem_type ) for e in obj }
513
525
else :
514
- elem_type = cl .__args__ [0 ]
515
- return {
516
- self ._structure_func .dispatch (elem_type )(e , elem_type )
517
- for e in obj
518
- }
526
+ return structure_to ([handler (e , elem_type ) for e in obj ])
519
527
520
528
def _structure_frozenset (self , obj , cl ):
521
529
"""Convert an iterable into a potentially generic frozenset."""
522
- if is_bare (cl ) or cl .__args__ [0 ] is Any :
523
- return frozenset (obj )
524
- else :
525
- elem_type = cl .__args__ [0 ]
526
- dispatch = self ._structure_func .dispatch
527
- return frozenset (dispatch (elem_type )(e , elem_type ) for e in obj )
530
+ return self ._structure_set (obj , cl , structure_to = frozenset )
528
531
529
532
def _structure_dict (self , obj , cl ):
530
533
"""Convert a mapping into a potentially generic dict."""
@@ -562,7 +565,7 @@ def _structure_union(self, obj, union):
562
565
return handler (obj , union )
563
566
564
567
def _structure_tuple (self , obj , tup : Type [T ]):
565
- """Deal with converting to a tuple."""
568
+ """Deal with structuring into a tuple."""
566
569
if tup in (Tuple , tuple ):
567
570
tup_params = None
568
571
else :
@@ -575,7 +578,20 @@ def _structure_tuple(self, obj, tup: Type[T]):
575
578
# We're dealing with a homogenous tuple, Tuple[int, ...]
576
579
tup_type = tup_params [0 ]
577
580
conv = self ._structure_func .dispatch (tup_type )
578
- return tuple (conv (e , tup_type ) for e in obj )
581
+ if self .extended_validation :
582
+ errors = []
583
+ res = []
584
+ for ix , e in enumerate (obj ):
585
+ try :
586
+ res .append (conv (e , tup_type ))
587
+ except Exception as exc :
588
+ exc .__note__ = f"Structuring tuple @ index { ix } "
589
+ errors .append (exc )
590
+ if errors :
591
+ raise IterableValidationError (f"While structuring { tup .__name__ } " , errors , tup )
592
+ return tuple (res )
593
+ else :
594
+ return tuple (conv (e , tup_type ) for e in obj )
579
595
else :
580
596
# We're dealing with a heterogenous tuple.
581
597
return tuple (
0 commit comments