shep

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

commit 52dffb80419d0ff368032a4c5426f878b9abf0e2
parent d915f17e2b7ee6a27aef51ab766b234a1366d4a3
Author: lash <dev@holbrook.no>
Date:   Sun,  6 Nov 2022 16:36:13 +0000

Remove sticky list alias, fix instance default state

Diffstat:
MCHANGELOG | 4++++
Msetup.cfg | 2+-
Mshep/state.py | 28+++++++++++++++++++---------
Mshep/store/file.py | 20+++++++++++++++++++-
Mtests/test_state.py | 36+++++++++++++++++++++++++++++++++++-
Mtests/test_verify.py | 2+-
6 files changed, 79 insertions(+), 13 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -1,3 +1,7 @@ +- 0.3.0 + * Clean up lingering keys in lists when moving from alias state + * Properly set default state when set through instantiation + * pass key to verifier (breaking change) - 0.2.10 * Add count active states method * Enable complete replace of NEW state on state instantiation diff --git a/setup.cfg b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = shep -version = 0.2.10 +version = 0.3.0 description = Multi-state key stores using bit masks author = Louis Holbrook author_email = dev@holbrook.no diff --git a/shep/state.py b/shep/state.py @@ -36,16 +36,20 @@ class State: self.__limit = (1 << bits) - 1 self.__c = 0 + self.__keys_reverse = {} + if default_state == None: default_state = self.base_state_name + else: + default_state = self.__check_name_valid(default_state) + self.base_state_name = default_state + self.__keys_reverse[default_state] = 0 setattr(self, default_state, 0) - self.__reverse = {0: getattr(self, default_state)} - self.__keys = {getattr(self, default_state): []} - self.__keys_reverse = {} - if default_state != self.base_state_name: - self.__keys_reverse[default_state] = 0 + self.__reverse = {0: default_state} + self.__keys = {0: []} + self.__contents = {} self.modified_last = {} self.verifier = verifier @@ -309,6 +313,8 @@ class State: :return: Numeric state value """ k = self.__check_name_valid(k) + if k == self.base_state_name: + return 0 return getattr(self, k) @@ -416,16 +422,19 @@ class State: raise StateCorruptionError(to_state) if self.verifier != None: - r = self.verifier(self, from_state, to_state) + r = self.verifier(self, key, from_state, to_state) if r != None: raise StateTransitionInvalid(r) - current_state_list.pop(idx) - + old_state = self.__keys_reverse.get(key) if self.event_callback != None: - old_state = self.__keys_reverse.get(key) self.event_callback(key, self.name(old_state), self.name(to_state)) + if old_state == 0: + current_state_list.pop(idx) + else: + for k in self.elements(from_state, numeric=True): + self.__keys[k].remove(key) self.__add_state_list(to_state, key) self.register_modify(key) @@ -542,6 +551,7 @@ class State: :rtype: any :returns: Content """ + print('contents {}'.format(self.__contents)) return self.__contents.get(key) diff --git a/shep/store/file.py b/shep/store/file.py @@ -1,6 +1,7 @@ # standard imports import os import re +import stat # local imports from .base import ( @@ -204,9 +205,26 @@ class SimpleFileStoreFactory(StoreFactory): r = [] for v in os.listdir(self.__path): if re.match(re_processedname, v): - r.append(v) + fp = os.path.join(self.__path, v) + st = os.stat(fp) + if stat.S_ISDIR(st.st_mode): + r.append(v) return r + def have(self, k): + lock_path = None + if self.__use_lock: + lock_path = os.path.join(self.__path, '.lock') + for d in self.ls(): + p = os.path.join(self.__path, d) + s = SimpleFileStore(p, binary=self.__binary, lock_path=lock_path) + try: + s.get(k) + except: + return False + return True + + def close(self): pass diff --git a/tests/test_state.py b/tests/test_state.py @@ -318,8 +318,42 @@ class TestState(unittest.TestCase): states = State(2, default_state='FOO') with self.assertRaises(StateItemNotFound): states.state('NEW') - getattr(states, 'FOO') + r = getattr(states, 'FOO') + self.assertEqual(r, 0) states.state('FOO') + states.put('bar') + r = states.list(states.FOO) + print(r) + self.assertEqual(len(r), 1) + + + def test_unset(self): + states = State(2) + states.add('one') + states.add('two') + states.alias('three', states.ONE, states.TWO) + states.put('foo', state=states.ONE) + states.set('foo', states.TWO) + r = states.list(states.ONE) + self.assertEqual(len(r), 1) + r = states.list(states.TWO) + self.assertEqual(len(r), 1) + r = states.unset('foo', states.ONE) + r = states.list(states.ONE) + self.assertEqual(len(r), 0) + r = states.list(states.TWO) + self.assertEqual(len(r), 1) + + + def test_move(self): + states = State(1) + states.add('one') + states.put('foo') + r = states.list(states.NEW) + self.assertEqual(len(r), 1) + states.move('foo', states.ONE) + r = states.list(states.NEW) + self.assertEqual(len(r), 0) if __name__ == '__main__': diff --git a/tests/test_verify.py b/tests/test_verify.py @@ -8,7 +8,7 @@ from shep.error import ( ) -def mock_verify(state, from_state, to_state): +def mock_verify(state, key, from_state, to_state): if from_state == state.FOO: if to_state == state.BAR: return 'bar cannot follow foo'