shep

Multi-state key stores using bit masks for python3
git clone git://git.defalsify.org/shep.git
Log | Files | Refs | LICENSE

commit ade8582528250a4966ffbfae246215595e7809db
parent 488687a8d85c23b60dfd10e924eb1ec8cf113b77
Author: lash <dev@holbrook.no>
Date:   Fri,  4 Feb 2022 22:15:51 +0000

Add replace method, remove force option, remove purge

Diffstat:
MCHANGELOG | 5+++++
Mshep/persist.py | 31+++++++++++++++++--------------
Mshep/state.py | 27+++++++++++----------------
Mshep/store/file.py | 22+++++++++-------------
Mtests/test_file.py | 25++++++++++++++-----------
Mtests/test_item.py | 26--------------------------
Mtests/test_store.py | 10+---------
7 files changed, 57 insertions(+), 89 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -1,3 +1,8 @@ +- 0.0.18 + * Eliminate key error when list run on empty valid state + * Add replace content method + * Remove force option from put + * Remove purge - 0.0.17 * Add reverse lookup method for name to state property - 0.0.16 diff --git a/shep/persist.py b/shep/persist.py @@ -16,13 +16,13 @@ class PersistedState(State): self.__stores[k] = self.__store_factory(k) - def put(self, key, contents=None, state=None, force=False): - to_state = super(PersistedState, self).put(key, state=state, contents=contents, force=force) + def put(self, key, contents=None, state=None): + to_state = super(PersistedState, self).put(key, state=state, contents=contents) k = self.name(to_state) self.__ensure_store(k) - self.__stores[k].add(key, contents, force=force) + self.__stores[k].add(key, contents) def set(self, key, or_state): @@ -75,15 +75,6 @@ class PersistedState(State): return to_state - def purge(self, key): - state = self.state(key) - k = self.name(state) - -# self.__ensure_store(k) - self.__stores[k].remove(key) - super(PersistedState, self).purge(key) - - def sync(self, state): k = self.name(state) @@ -97,11 +88,16 @@ class PersistedState(State): pass - def path(self, state, key=None): + def list(self, state): k = self.name(state) - self.__ensure_store(k) + #return self.__stores[k].list(state) + return super(PersistedState, self).list(state) + + def path(self, state, key=None): + k = self.name(state) + self.__ensure_store(k) return self.__stores[k].path(key=key) @@ -109,3 +105,10 @@ class PersistedState(State): from_state = self.state(key) to_state = super(PersistedState, self).next(key) return self.__movestore(key, from_state, to_state) + + + def replace(self, key, contents): + super(PersistedState, self).replace(key, contents) + state = self.state(key) + k = self.name(state) + return self.__stores[k].replace(key, contents) diff --git a/shep/state.py b/shep/state.py @@ -60,6 +60,7 @@ class State: if v > self.__limit: raise OverflowError(v) + def __check_value(self, v): v = self.__check_valid(v) self.__check_limit(v) @@ -210,7 +211,7 @@ class State: return to_state - def set(self, key, or_state): + def set(self, key, or_state, content=None): if not self.__is_pure(or_state): raise ValueError('can only apply using single bit states') @@ -245,18 +246,6 @@ class State: return self.__move(key, current_state, to_state) - def purge(self, key): - current_state = self.__keys_reverse.get(key) - if current_state == None: - raise StateItemNotFound(key) - del self.__keys_reverse[key] - current_state_list = self.__keys.get(current_state) - - idx = self.__state_list_index(key, current_state_list) - - current_state_list.pop(idx) - - def state(self, key): state = self.__keys_reverse.get(key) if state == None: @@ -269,9 +258,10 @@ class State: def list(self, state): - if self.__reverse.get(state) == None: - raise StateInvalid(state) - return self.__keys[state] + try: + return self.__keys[state] + except KeyError: + return [] def sync(self, state): @@ -303,3 +293,8 @@ class State: from_state = self.state(key) new_state = self.peek(key) return self.__move(key, from_state, new_state) + + + def replace(self, key, contents): + self.state(key) + self.__contents[key] = contents diff --git a/shep/store/file.py b/shep/store/file.py @@ -9,20 +9,8 @@ class SimpleFileStore: os.makedirs(self.__path, exist_ok=True) - def add(self, k, contents=None, force=False): + def add(self, k, contents=None): fp = os.path.join(self.__path, k) - have_file = False - try: - os.stat(fp) - have_file = True - except FileNotFoundError: - pass - - if have_file: - if not force: - raise FileExistsError(fp) - if contents == None: - raise FileExistsError('will not overwrite empty content on existing file {}. Use rm then add instead'.format(fp)) if contents == None: contents = '' @@ -63,6 +51,14 @@ class SimpleFileStore: return os.path.join(self.__path, key) + def replace(self, key, contents): + fp = os.path.join(self.__path, key) + os.stat(fp) + f = open(fp, 'w') + r = f.write(contents) + f.close() + + class SimpleFileStoreFactory: def __init__(self, path): diff --git a/tests/test_file.py b/tests/test_file.py @@ -38,17 +38,8 @@ class TestStateReport(unittest.TestCase): with self.assertRaises(StateItemExists): self.states.put('abcd', state=self.states.FOO) - with self.assertRaises(FileExistsError): - self.states.put('abcd', state=self.states.FOO, force=True) - - self.states.put('abcd', contents='foo', state=self.states.FOO, force=True) - self.assertEqual(self.states.get('abcd'), 'foo') - - with self.assertRaises(FileExistsError): - self.states.put('abcd', state=self.states.FOO, force=True) - - self.states.put('abcd', contents='bar', state=self.states.FOO, force=True) - self.assertEqual(self.states.get('abcd'), 'bar') + with self.assertRaises(StateItemExists): #FileExistsError): + self.states.put('abcd', state=self.states.FOO) def test_list(self): @@ -167,5 +158,17 @@ class TestStateReport(unittest.TestCase): os.stat(fp) + def test_replace(self): + self.states.put('abcd') + self.states.replace('abcd', 'foo') + self.assertEqual(self.states.get('abcd'), 'foo') + + fp = os.path.join(self.d, 'NEW', 'abcd') + f = open(fp, 'r') + r = f.read() + f.close() + self.assertEqual(r, 'foo') + + if __name__ == '__main__': unittest.main() diff --git a/tests/test_item.py b/tests/test_item.py @@ -65,15 +65,6 @@ class TestStateItems(unittest.TestCase): self.assertEqual(self.states.state(item), self.states.XYZZY) - def test_item_purge(self): - item = b'foo' - self.states.put(item, state=self.states.BAZ) - self.assertEqual(self.states.state(item), self.states.BAZ) - self.states.purge(item) - with self.assertRaises(StateItemNotFound): - self.states.state(item) - - def test_item_get(self): item = b'foo' self.states.put(item, state=self.states.BAZ, contents='bar') @@ -116,22 +107,5 @@ class TestStateItems(unittest.TestCase): self.states.unset(item, self.states.FOO) # bit not set - def test_item_force(self): - item = b'foo' - self.states.put(item, state=self.states.XYZZY) - - contents = 'xyzzy' - self.states.put(item, state=self.states.XYZZY, contents=contents, force=True) - self.assertEqual(self.states.get(item), 'xyzzy') - - contents = None - self.states.put(item, state=self.states.XYZZY, contents=contents, force=True) - self.assertEqual(self.states.get(item), 'xyzzy') - - contents = 'plugh' - self.states.put(item, state=self.states.XYZZY, contents=contents, force=True) - self.assertEqual(self.states.get(item), 'plugh') - - if __name__ == '__main__': unittest.main() diff --git a/tests/test_store.py b/tests/test_store.py @@ -21,7 +21,7 @@ class MockStore: self.for_state = 0 - def add(self, k, contents=None, force=False): + def add(self, k, contents=None): self.v[k] = contents @@ -72,14 +72,6 @@ class TestStateItems(unittest.TestCase): self.assertIsNone(self.mockstore.v.get(item)) - def test_persist_purge(self): - item = b'foo' - self.states.put(item, self.states.FOO, True) - self.states.purge(item) - self.assertEqual(self.mockstore.for_state, self.states.name(self.states.FOO)) - self.assertIsNone(self.mockstore.v.get(item)) - - def test_persist_move_new(self): item = b'foo' self.states.put(item)