@@ -251,6 +251,45 @@ def from_message(cls, message_dict: dict) -> 'StructTuple':
251251
252252 return result
253253
254+ @classmethod
255+ def _assert_key_is_member (cls , key ):
256+ member_names = {tup [0 ] for tup in cls .get_members ()}
257+ if key not in member_names :
258+ raise KeyError (f'"{ key } " is not defined for this struct.' )
259+
260+ @classmethod
261+ def _assert_property_type (cls , key , value ):
262+ """Eagerly check for a correct member type"""
263+ members = dict (cls .get_members ())
264+ typ = members [key ]
265+
266+ if isinstance (typ , type ) and issubclass (typ , EIP712Struct ):
267+ # We expect an EIP712Struct instance. Assert that's true, and check the struct signature too.
268+ if not isinstance (value , EIP712Struct ) or value ._encode_type (False ) != typ ._encode_type (False ):
269+ raise ValueError (f'Given value is of type { type (value )} , but we expected { typ } ' )
270+ else :
271+ # Since it isn't a nested struct, its an EIP712Type
272+ try :
273+ typ .encode_value (value )
274+ except Exception as e :
275+ raise ValueError (f'The python type { type (value )} does not appear '
276+ f'to be supported for data type { typ } .' ) from e
277+
278+ def __getitem__ (self , key ):
279+ """Provide access directly to the underlying value dictionary"""
280+ self ._assert_key_is_member (key )
281+ return self .values .__getitem__ (key )
282+
283+ def __setitem__ (self , key , value ):
284+ """Provide access directly to the underlying value dictionary"""
285+ self ._assert_key_is_member (key )
286+ self ._assert_property_type (key , value )
287+
288+ return self .values .__setitem__ (key , value )
289+
290+ def __delitem__ (self , _ ):
291+ raise TypeError ('Deleting entries from an EIP712Struct is not allowed.' )
292+
254293
255294class StructTuple (NamedTuple ):
256295 message : EIP712Struct
0 commit comments