Skip to content

Commit afaec95

Browse files
committed
Merge branch 'v1.1.0' into json-dumps
# Conflicts: # eip712_structs/struct.py # tests/test_encode_data.py
2 parents 9fa1b09 + 2ae3c3a commit afaec95

File tree

3 files changed

+96
-2
lines changed

3 files changed

+96
-2
lines changed

eip712_structs/struct.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,45 @@ def from_message(cls, message_dict: dict) -> 'StructTuple':
258258

259259
return result
260260

261+
@classmethod
262+
def _assert_key_is_member(cls, key):
263+
member_names = {tup[0] for tup in cls.get_members()}
264+
if key not in member_names:
265+
raise KeyError(f'"{key}" is not defined for this struct.')
266+
267+
@classmethod
268+
def _assert_property_type(cls, key, value):
269+
"""Eagerly check for a correct member type"""
270+
members = dict(cls.get_members())
271+
typ = members[key]
272+
273+
if isinstance(typ, type) and issubclass(typ, EIP712Struct):
274+
# We expect an EIP712Struct instance. Assert that's true, and check the struct signature too.
275+
if not isinstance(value, EIP712Struct) or value._encode_type(False) != typ._encode_type(False):
276+
raise ValueError(f'Given value is of type {type(value)}, but we expected {typ}')
277+
else:
278+
# Since it isn't a nested struct, its an EIP712Type
279+
try:
280+
typ.encode_value(value)
281+
except Exception as e:
282+
raise ValueError(f'The python type {type(value)} does not appear '
283+
f'to be supported for data type {typ}.') from e
284+
285+
def __getitem__(self, key):
286+
"""Provide access directly to the underlying value dictionary"""
287+
self._assert_key_is_member(key)
288+
return self.values.__getitem__(key)
289+
290+
def __setitem__(self, key, value):
291+
"""Provide access directly to the underlying value dictionary"""
292+
self._assert_key_is_member(key)
293+
self._assert_property_type(key, value)
294+
295+
return self.values.__setitem__(key, value)
296+
297+
def __delitem__(self, _):
298+
raise TypeError('Deleting entries from an EIP712Struct is not allowed.')
299+
261300
def __eq__(self, other):
262301
if not other:
263302
# Null check

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88

99
NAME = 'eip712-structs'
10-
VERSION = '1.0.1'
10+
VERSION = '1.1.0'
1111

1212
install_requirements = [
1313
'eth-utils>=1.4.0',

tests/test_encode_data.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,6 @@ class Foo(EIP712Struct):
196196
foo_copy = Foo(s='hello world')
197197
foo_2 = Foo(s='blah')
198198

199-
200199
assert foo != None
201200
assert foo != 'unrelated type'
202201
assert foo == foo
@@ -231,3 +230,59 @@ class Bar(EIP712Struct):
231230
s = String()
232231
bar = Bar(s='hello world')
233232
assert bar != foo
233+
234+
235+
def test_value_access():
236+
class Foo(EIP712Struct):
237+
s = String()
238+
b = Bytes(32)
239+
240+
test_str = 'hello world'
241+
test_bytes = os.urandom(32)
242+
foo = Foo(s=test_str, b=test_bytes)
243+
244+
assert foo['s'] == test_str
245+
assert foo['b'] == test_bytes
246+
247+
test_bytes_2 = os.urandom(32)
248+
foo['b'] = test_bytes_2
249+
250+
assert foo['b'] == test_bytes_2
251+
252+
with pytest.raises(KeyError):
253+
foo['x'] = 'unacceptable'
254+
255+
# Check behavior when accessing a member that wasn't defined for the struct.
256+
with pytest.raises(KeyError):
257+
foo['x']
258+
# Lets cheat a lil bit for robustness- add an invalid 'x' member to the value dict, and check the error still raises
259+
foo.values['x'] = 'test'
260+
with pytest.raises(KeyError):
261+
foo['x']
262+
foo.values.pop('x')
263+
264+
with pytest.raises(ValueError):
265+
foo['s'] = b'unacceptable'
266+
with pytest.raises(ValueError):
267+
# Bytes do accept strings, but it has to be hex formatted.
268+
foo['b'] = 'unacceptable'
269+
270+
# Test behavior when attempting to set nested structs as values
271+
class Bar(EIP712Struct):
272+
s = String()
273+
f = Foo
274+
275+
class Baz(EIP712Struct):
276+
s = String()
277+
baz = Baz(s=test_str)
278+
279+
bar = Bar(s=test_str)
280+
bar['f'] = foo
281+
assert bar['f'] == foo
282+
283+
with pytest.raises(ValueError):
284+
# Expects a Foo type, so should throw an error
285+
bar['f'] = baz
286+
287+
with pytest.raises(TypeError):
288+
del foo['s']

0 commit comments

Comments
 (0)