commit 10f8617babdc82190866b4ca1bf508348c9864e0
parent e94f366d3cc31007ac843af103e1431f85b1bfcd
Author: lash <dev@holbrook.no>
Date: Tue, 1 Feb 2022 07:47:07 +0000
Add cumulative bit changes
Diffstat:
5 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
@@ -1,3 +1,5 @@
+- 0.0.8
+ * Add single bit transition to aliases
- 0.0.7
* Add content for keys
- 0.0.6
diff --git a/setup.cfg b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = shep
-version = 0.0.7
+version = 0.0.8
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
@@ -172,7 +172,11 @@ class State:
if new_state == None:
raise StateInvalid(to_state)
- current_state_list = self.__keys.get(current_state)
+ self.__move(key, current_state, to_state)
+
+
+ def __move(self, key, from_state, to_state):
+ current_state_list = self.__keys.get(from_state)
if current_state_list == None:
raise StateCorruptionError(current_state)
@@ -186,12 +190,46 @@ class State:
current_state_list.pop(idx)
+ def set(self, key, or_state):
+ if not self.__is_pure(or_state):
+ raise ValueError('can only apply using single bit states')
+
+ current_state = self.__keys_reverse.get(key)
+ if current_state == None:
+ raise StateItemNotFound(key)
+
+ to_state = current_state | or_state
+ new_state = self.__reverse.get(to_state)
+ if new_state == None:
+ raise StateInvalid('resulting to state is unknown: {}'.format(to_state))
+
+ self.__move(key, current_state, to_state)
+
+
+ def unset(self, key, not_state):
+ if not self.__is_pure(not_state):
+ raise ValueError('can only apply using single bit states')
+
+ current_state = self.__keys_reverse.get(key)
+ if current_state == None:
+ raise StateItemNotFound(key)
+
+ to_state = current_state & (~not_state)
+ if to_state == current_state:
+ raise ValueError('invalid change for state {}: {}'.format(key, not_state))
+
+ new_state = self.__reverse.get(to_state)
+ if new_state == None:
+ raise StateInvalid('resulting to state is unknown: {}'.format(to_state))
+
+ 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)
diff --git a/tests/test_item.py b/tests/test_item.py
@@ -82,5 +82,39 @@ class TestStateItems(unittest.TestCase):
self.assertEqual(v, 'bar')
+ def test_item_set(self):
+ item = b'foo'
+ self.states.put(item, self.states.FOO)
+ self.states.set(item, self.states.BAR)
+ self.assertEqual(self.states.state(item), self.states.PLUGH)
+
+
+ def test_item_set_invalid(self):
+ item = b'foo'
+ self.states.put(item, self.states.FOO)
+ with self.assertRaises(StateInvalid):
+ self.states.set(item, self.states.BAZ)
+
+ item = b'bar'
+ self.states.put(item, self.states.BAR)
+ with self.assertRaises(ValueError):
+ self.states.set(item, self.states.XYZZY)
+
+
+ def test_item_set_invalid(self):
+ item = b'foo'
+ self.states.put(item, self.states.XYZZY)
+ self.states.unset(item, self.states.BAZ)
+ self.assertEqual(self.states.state(item), self.states.BAR)
+
+ item = b'bar'
+ self.states.put(item, self.states.XYZZY)
+ with self.assertRaises(ValueError):
+ self.states.unset(item, self.states.PLUGH)
+
+ with self.assertRaises(ValueError):
+ self.states.unset(item, self.states.FOO) # bit not set
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/tests/test_state.py b/tests/test_state.py
@@ -74,6 +74,7 @@ class TestState(unittest.TestCase):
states.add('bar')
with self.assertRaises(StateInvalid):
states.alias('baz', 5)
+
if __name__ == '__main__':