Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReadOnlyDict/List pickle compatibility and serialization tests #737

Merged
merged 13 commits into from
Oct 16, 2020
Prev Previous commit
Next Next commit
ReadOnlyContainer: Remove self.message attribute
  • Loading branch information
shwang committed Oct 15, 2020
commit fe6c4663308a2ae3c9f8de06b7d0466c53f4ff61
27 changes: 10 additions & 17 deletions sacred/config/custom_containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,14 @@ def revelation(self):


class ReadOnlyContainer:
def __init__(self, message=None):
self.__message = message or "This container is read-only!"

def __reduce__(self):
return self.__class__, (self.__copy__(), self.__message)
return self.__class__, (self.__copy__(),)

def _readonly(self, *args, **kwargs):
raise SacredError(self.__message, filter_traceback="always")
raise SacredError(
"The configuration is read-only in a captured function!",
filter_traceback="always",
)


class ReadOnlyDict(ReadOnlyContainer, dict):
Expand All @@ -187,8 +187,7 @@ class ReadOnlyDict(ReadOnlyContainer, dict):
__setitem__ = ReadOnlyContainer._readonly
__delitem__ = ReadOnlyContainer._readonly

def __init__(self, d, message=None):
ReadOnlyContainer.__init__(self, message)
def __init__(self, d):
dict.__init__(self, d)
shwang marked this conversation as resolved.
Show resolved Hide resolved

def __copy__(self):
Expand All @@ -213,8 +212,7 @@ class ReadOnlyList(ReadOnlyContainer, list):
__setitem__ = ReadOnlyContainer._readonly
__delitem__ = ReadOnlyContainer._readonly

def __init__(self, lst, message=None):
ReadOnlyContainer.__init__(self, message)
def __init__(self, lst):
list.__init__(self, lst)

def __copy__(self):
Expand All @@ -225,22 +223,17 @@ def __deepcopy__(self, memo):
return copy.deepcopy(lst, memo=memo)


def make_read_only(o, error_message=None):
def make_read_only(o):
"""Makes objects read-only.

Converts every `list` and `dict` into `ReadOnlyList` and `ReadOnlyDict` in
a nested structure of `list`s, `dict`s and `tuple`s. Does not modify `o`
but returns the converted structure.
"""
if type(o) == dict:
return ReadOnlyDict(
{k: make_read_only(v, error_message) for k, v in o.items()},
message=error_message,
)
return ReadOnlyDict({k: make_read_only(v) for k, v in o.items()})
elif type(o) == list:
return ReadOnlyList(
[make_read_only(v, error_message) for v in o], message=error_message
)
return ReadOnlyList([make_read_only(v) for v in o])
elif type(o) == tuple:
return tuple(map(make_read_only, o))
else:
Expand Down
4 changes: 2 additions & 2 deletions tests/test_config/test_readonly_containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def _check_read_only_dict(d):
# Check serialization
_check_serializable(d)

raises_dict = pytest.raises(SacredError, match="This container is read-only")
raises_dict = pytest.raises(SacredError, match="read-only")

if len(d) > 0:
# Test removal of entries and overwrite an already present entry
Expand Down Expand Up @@ -96,7 +96,7 @@ def _check_read_only_list(lst):
# Check serialization
_check_serializable(lst)

raises_list = pytest.raises(SacredError, match="This container is read-only")
raises_list = pytest.raises(SacredError, match="read-only")

if len(lst):
with raises_list:
Expand Down