From 721b9d36af1e0f6f8236dd705c3e3301c46d84cc Mon Sep 17 00:00:00 2001 From: Max Hutchinson Date: Tue, 29 Sep 2015 13:06:19 -0500 Subject: [PATCH 1/4] Adding "readonly" option to constructor to avoid writes. Read-only disables `__delitem__` and `__setitem__` and `__del__` --- chest/core.py | 12 ++++++++++++ chest/tests/test_core.py | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/chest/core.py b/chest/core.py index fa95d44..21b97c9 100644 --- a/chest/core.py +++ b/chest/core.py @@ -95,6 +95,7 @@ def __init__(self, data=None, path=None, available_memory=None, on_miss=_do_nothing, on_overflow=_do_nothing, open=open, open_many=_open_many, + readonly=False, mode='b'): # In memory storage self.inmem = data or dict() @@ -115,6 +116,9 @@ def __init__(self, data=None, path=None, available_memory=None, self.open = open self.open_many = open_many self._key_to_filename = key_to_filename + self.readonly = readonly + if (not self._explicitly_given_path) and self.readonly: + raise TypeError("Can't create an empty readonly chest") keyfile = os.path.join(self.path, '.keys') try: @@ -196,6 +200,9 @@ def _update_lru(self, key): self.heap[key] = self.counter def __delitem__(self, key): + if self.readonly: + raise TypeError("Can't delete from readonly chest") + if key in self.inmem: self.memory_usage -= nbytes(self.inmem[key]) del self.inmem[key] @@ -209,6 +216,9 @@ def __delitem__(self, key): del self._keys[key] def __setitem__(self, key, value): + if self.readonly: + raise TypeError("Can't assign in readonly chest") + with self.lock: if key in self._keys: del self[key] @@ -222,6 +232,8 @@ def __setitem__(self, key, value): self.shrink() def __del__(self): + if self.readonly: + return if self._explicitly_given_path: if os.path.exists(self.path): self.flush() diff --git a/chest/tests/test_core.py b/chest/tests/test_core.py index 544a6fb..647b9b9 100644 --- a/chest/tests/test_core.py +++ b/chest/tests/test_core.py @@ -458,3 +458,38 @@ def test_prefetch(): assert not raises(KeyError, lambda: c[1]) c.prefetch([1, 2]) assert not raises(KeyError, lambda: c[2]) + + +def test_readonly(): + with tmp_chest(path="here") as c1: + c1[0] = 0 + c1["foo"] = "bar" + c1.flush() + with tmp_chest(path="here", readonly=True) as c2: + assert c2[0] == 0 + assert c2["foo"] == "bar" + try: + c2[0] = 1 + assert False + except TypeError: + assert True + except: + assert False + try: + c2["spam"] = "eggs" + assert False + except TypeError: + assert True + except: + assert False + try: + del c2["foo"] + assert False + except TypeError: + assert True + except: + assert False + + +def test_readonly_nopath(): + assert raises(TypeError, lambda: Chest(readonly=True)) From e435e66b54e391c83ffdf7196dc801f8ec93ed15 Mon Sep 17 00:00:00 2001 From: Max Hutchinson Date: Tue, 29 Sep 2015 13:14:12 -0500 Subject: [PATCH 2/4] Be sure to delete the in-memory data. --- chest/core.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/chest/core.py b/chest/core.py index 21b97c9..a1d5b77 100644 --- a/chest/core.py +++ b/chest/core.py @@ -117,8 +117,6 @@ def __init__(self, data=None, path=None, available_memory=None, self.open_many = open_many self._key_to_filename = key_to_filename self.readonly = readonly - if (not self._explicitly_given_path) and self.readonly: - raise TypeError("Can't create an empty readonly chest") keyfile = os.path.join(self.path, '.keys') try: @@ -138,6 +136,9 @@ def __init__(self, data=None, path=None, available_memory=None, self._on_miss = on_miss self._on_overflow = on_overflow + if (not self._explicitly_given_path) and self.readonly: + raise TypeError("Can't create an empty readonly chest") + def __str__(self): return '' % self.path @@ -232,10 +233,8 @@ def __setitem__(self, key, value): self.shrink() def __del__(self): - if self.readonly: - return if self._explicitly_given_path: - if os.path.exists(self.path): + if os.path.exists(self.path) and not self.readonly: self.flush() else: with self.lock: From 62f7f74bed7c55a18c66fa92249e896e4ba850be Mon Sep 17 00:00:00 2001 From: Max Hutchinson Date: Tue, 29 Sep 2015 13:19:40 -0500 Subject: [PATCH 3/4] Coverage no longer supports python 3.2, but let's add 3.5 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c4e371c..6ebfbd6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,9 @@ language: python python: - "2.6" - "2.7" - - "3.2" - "3.3" - "3.4" + - "3.5" env: - PEP8_IGNORE="" From 42930168674c230d7d14108a118caa39a295eef2 Mon Sep 17 00:00:00 2001 From: Max Hutchinson Date: Tue, 29 Sep 2015 13:22:14 -0500 Subject: [PATCH 4/4] Maybe too soon for 3.5 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6ebfbd6..443574e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ python: - "2.7" - "3.3" - "3.4" - - "3.5" env: - PEP8_IGNORE=""