@@ -625,6 +625,16 @@ def dump_engine_object(v: Any) -> Any:
625625 secs = int (total_secs )
626626 nanos = int ((total_secs - secs ) * 1e9 )
627627 return {"secs" : secs , "nanos" : nanos }
628+ elif is_namedtuple_type (type (v )):
629+ # Handle NamedTuple objects specifically to use dict format
630+ field_names = list (getattr (type (v ), "_fields" , ()))
631+ result = {}
632+ for name in field_names :
633+ val = getattr (v , name )
634+ result [name ] = dump_engine_object (val ) # Include all values, including None
635+ if hasattr (v , "kind" ) and "kind" not in result :
636+ result ["kind" ] = v .kind
637+ return result
628638 elif hasattr (v , "__dict__" ): # for dataclass-like objects
629639 s = {}
630640 for k , val in v .__dict__ .items ():
@@ -712,32 +722,27 @@ def load_engine_object(expected_type: Any, v: Any) -> Any:
712722 if isinstance (variant , AnalyzedStructType ):
713723 struct_type = variant .struct_type
714724 if dataclasses .is_dataclass (struct_type ):
725+ if not isinstance (v , Mapping ):
726+ raise ValueError (f"Expected dict for dataclass, got { type (v )} " )
715727 # Drop auxiliary discriminator "kind" if present
716- src = dict (v ) if isinstance (v , Mapping ) else v
717- if isinstance (src , Mapping ):
718- init_kwargs : dict [str , Any ] = {}
719- field_types = {f .name : f .type for f in dataclasses .fields (struct_type )}
720- for name , f_type in field_types .items ():
721- if name in src :
722- init_kwargs [name ] = load_engine_object (f_type , src [name ])
723- # Construct with defaults for missing fields
724- return struct_type (** init_kwargs )
728+ dc_init_kwargs : dict [str , Any ] = {}
729+ field_types = {f .name : f .type for f in dataclasses .fields (struct_type )}
730+ for name , f_type in field_types .items ():
731+ if name in v :
732+ dc_init_kwargs [name ] = load_engine_object (f_type , v [name ])
733+ return struct_type (** dc_init_kwargs )
725734 elif is_namedtuple_type (struct_type ):
726- # NamedTuple is dumped as list/tuple of items
735+ if not isinstance (v , Mapping ):
736+ raise ValueError (f"Expected dict for NamedTuple, got { type (v )} " )
737+ # Dict format (from dump/load functions)
727738 annotations = getattr (struct_type , "__annotations__" , {})
728739 field_names = list (getattr (struct_type , "_fields" , ()))
729- values : list [ Any ] = []
740+ nt_init_kwargs : dict [ str , Any ] = {}
730741 for name in field_names :
731742 f_type = annotations .get (name , Any )
732- # Assume v is a sequence aligned with fields
733- if isinstance (v , (list , tuple )):
734- idx = field_names .index (name )
735- values .append (load_engine_object (f_type , v [idx ]))
736- elif isinstance (v , Mapping ):
737- values .append (load_engine_object (f_type , v .get (name )))
738- else :
739- values .append (v )
740- return struct_type (* values )
743+ if name in v :
744+ nt_init_kwargs [name ] = load_engine_object (f_type , v [name ])
745+ return struct_type (** nt_init_kwargs )
741746 return v
742747
743748 # Union with discriminator support via "kind"
0 commit comments