Add generic persistence wrapper
This commit is contained in:
parent
0eaf032b89
commit
3ffb3b08aa
48
shep/persist.py
Normal file
48
shep/persist.py
Normal file
@ -0,0 +1,48 @@
|
||||
# local imports
|
||||
from .state import State
|
||||
|
||||
|
||||
class PersistedState(State):
|
||||
|
||||
def __init__(self, factory, bits, logger=None):
|
||||
super(PersistedState, self).__init__(bits, logger=logger)
|
||||
self.__store_factory = factory
|
||||
self.__stores = {}
|
||||
|
||||
|
||||
def __ensure_store(self, k):
|
||||
if self.__stores.get(k) == None:
|
||||
self.__stores[k] = self.__store_factory(k)
|
||||
|
||||
|
||||
def put(self, item, state=None):
|
||||
k = self.name(state)
|
||||
self.__ensure_store(k)
|
||||
self.__stores[k].add(item)
|
||||
|
||||
super(PersistedState, self).put(item, state=state)
|
||||
|
||||
|
||||
def move(self, item, to_state):
|
||||
k_to = self.name(to_state)
|
||||
|
||||
from_state = self.state(item)
|
||||
k_from = self.name(from_state)
|
||||
|
||||
self.__ensure_store(k_to)
|
||||
self.__ensure_store(k_from)
|
||||
|
||||
self.__stores[k_to].add(item)
|
||||
self.__stores[k_from].remove(item)
|
||||
|
||||
super(PersistedState, self).move(item, to_state)
|
||||
|
||||
|
||||
def purge(self, item):
|
||||
state = self.state(item)
|
||||
k = self.name(state)
|
||||
|
||||
self.__ensure_store(k)
|
||||
|
||||
self.__stores[k].remove(item)
|
||||
super(PersistedState, self).purge(item)
|
@ -9,13 +9,13 @@ from shep.error import (
|
||||
|
||||
class State:
|
||||
|
||||
def __init__(self, bits, logger=None, store_factory=None):
|
||||
def __init__(self, bits, logger=None):
|
||||
self.__bits = bits
|
||||
self.__limit = (1 << bits) - 1
|
||||
self.__c = 0
|
||||
self.__reverse = {}
|
||||
|
||||
self.NEW = 0
|
||||
|
||||
self.__reverse = {0: self.NEW}
|
||||
self.__items = {self.NEW: []}
|
||||
self.__items_reverse = {}
|
||||
|
||||
@ -124,6 +124,15 @@ class State:
|
||||
return l
|
||||
|
||||
|
||||
def name(self, v):
|
||||
if v == None:
|
||||
return self.NEW
|
||||
k = self.__reverse.get(v)
|
||||
if k == None:
|
||||
raise StateInvalid(v)
|
||||
return k
|
||||
|
||||
|
||||
def match(self, v, pure=False):
|
||||
alias = None
|
||||
if not pure:
|
||||
@ -175,7 +184,6 @@ class State:
|
||||
current_state_list.pop(idx)
|
||||
|
||||
|
||||
|
||||
def purge(self, item):
|
||||
current_state = self.__items_reverse.get(item)
|
||||
if current_state == None:
|
||||
|
@ -74,6 +74,5 @@ class TestStateItems(unittest.TestCase):
|
||||
self.states.state(item)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
84
tests/test_store.py
Normal file
84
tests/test_store.py
Normal file
@ -0,0 +1,84 @@
|
||||
# standard imports
|
||||
import unittest
|
||||
|
||||
# local imports
|
||||
from shep.persist import PersistedState
|
||||
from shep.error import (
|
||||
StateExists,
|
||||
StateItemExists,
|
||||
StateInvalid,
|
||||
StateItemNotFound,
|
||||
)
|
||||
|
||||
class MockStore:
|
||||
|
||||
def __init__(self):
|
||||
self.v = {}
|
||||
self.for_state = 0
|
||||
|
||||
|
||||
def add(self, k):
|
||||
self.v[k] = True
|
||||
|
||||
|
||||
def remove(self, k):
|
||||
del self.v[k]
|
||||
|
||||
|
||||
class TestStateItems(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.mockstore = MockStore()
|
||||
|
||||
def mockstore_factory(v):
|
||||
self.mockstore.for_state = v
|
||||
return self.mockstore
|
||||
|
||||
self.states = PersistedState(mockstore_factory, 4)
|
||||
self.states.add('foo')
|
||||
self.states.add('bar')
|
||||
self.states.add('baz')
|
||||
self.states.alias('xyzzy', self.states.BAZ | self.states.BAR)
|
||||
self.states.alias('plugh', self.states.FOO | self.states.BAR)
|
||||
|
||||
|
||||
def test_persist_new(self):
|
||||
item = b'foo'
|
||||
self.states.put(item)
|
||||
self.assertTrue(self.mockstore.v.get(item))
|
||||
|
||||
|
||||
def test_persist_move(self):
|
||||
item = b'foo'
|
||||
self.states.put(item, self.states.FOO)
|
||||
self.states.move(item, self.states.XYZZY)
|
||||
self.assertEqual(self.mockstore.for_state, self.states.name(self.states.XYZZY))
|
||||
|
||||
|
||||
def test_persist_move(self):
|
||||
item = b'foo'
|
||||
self.states.put(item, self.states.FOO)
|
||||
self.states.move(item, self.states.XYZZY)
|
||||
self.assertEqual(self.mockstore.for_state, self.states.name(self.states.XYZZY))
|
||||
# TODO: cant check the add because remove happens after remove, need better mock
|
||||
self.assertIsNone(self.mockstore.v.get(item))
|
||||
|
||||
|
||||
def test_persist_purge(self):
|
||||
item = b'foo'
|
||||
self.states.put(item, self.states.FOO)
|
||||
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)
|
||||
self.states.move(item, self.states.BAZ)
|
||||
self.assertEqual(self.mockstore.for_state, self.states.name(self.states.BAZ))
|
||||
self.assertIsNone(self.mockstore.v.get(item))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Reference in New Issue
Block a user