@@ -251,12 +251,40 @@ 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+
254278 def __getitem__ (self , key ):
255279 """Provide access directly to the underlying value dictionary"""
280+ self ._assert_key_is_member (key )
256281 return self .values .__getitem__ (key )
257282
258283 def __setitem__ (self , key , value ):
259284 """Provide access directly to the underlying value dictionary"""
285+ self ._assert_key_is_member (key )
286+ self ._assert_property_type (key , value )
287+
260288 return self .values .__setitem__ (key , value )
261289
262290 def __delete__ (self , instance ):
0 commit comments