Add item lifetime controller interface
This commit is contained in:
parent
d2bca51342
commit
0eaf032b89
@ -1,3 +1,5 @@
|
|||||||
|
- 0.0.4
|
||||||
|
* Add item lifetime control
|
||||||
- 0.0.3
|
- 0.0.3
|
||||||
* Split match to 2-element tuple, returning complex value and simple values separately
|
* Split match to 2-element tuple, returning complex value and simple values separately
|
||||||
- 0.0.2
|
- 0.0.2
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = shep
|
name = shep
|
||||||
version = 0.0.3
|
version = 0.0.4
|
||||||
description = Multi-state key value stores using bitmaskings
|
description = Multi-state key value stores using bitmaskings
|
||||||
author = Louis Holbrook
|
author = Louis Holbrook
|
||||||
author_email = dev@holbrook.no
|
author_email = dev@holbrook.no
|
||||||
|
@ -4,3 +4,15 @@ class StateExists(Exception):
|
|||||||
|
|
||||||
class StateInvalid(Exception):
|
class StateInvalid(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class StateItemExists(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class StateItemNotFound(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class StateCorruptionError(RuntimeError):
|
||||||
|
pass
|
||||||
|
@ -1,22 +1,23 @@
|
|||||||
# standard imports
|
|
||||||
import enum
|
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from shep.error import (
|
from shep.error import (
|
||||||
StateExists,
|
StateExists,
|
||||||
StateInvalid,
|
StateInvalid,
|
||||||
|
StateItemExists,
|
||||||
|
StateItemNotFound,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class State:
|
class State:
|
||||||
|
|
||||||
def __init__(self, bits, logger=None, store=None):
|
def __init__(self, bits, logger=None, store_factory=None):
|
||||||
self.__bits = bits
|
self.__bits = bits
|
||||||
self.__limit = (1 << bits) - 1
|
self.__limit = (1 << bits) - 1
|
||||||
self.__c = 0
|
self.__c = 0
|
||||||
self.__reverse = {}
|
self.__reverse = {}
|
||||||
self.__logger = logger
|
|
||||||
self.__store = store
|
self.NEW = 0
|
||||||
|
self.__items = {self.NEW: []}
|
||||||
|
self.__items_reverse = {}
|
||||||
|
|
||||||
|
|
||||||
def __is_pure(self, v):
|
def __is_pure(self, v):
|
||||||
@ -28,9 +29,13 @@ class State:
|
|||||||
return c == v
|
return c == v
|
||||||
|
|
||||||
|
|
||||||
def __check_name(self, k):
|
def __check_name_valid(self, k):
|
||||||
if not k.isalpha():
|
if not k.isalpha():
|
||||||
raise ValueError('only alpha')
|
raise ValueError('only alpha')
|
||||||
|
|
||||||
|
def __check_name(self, k):
|
||||||
|
self.__check_name_valid(k)
|
||||||
|
|
||||||
k = k.upper()
|
k = k.upper()
|
||||||
try:
|
try:
|
||||||
getattr(self, k)
|
getattr(self, k)
|
||||||
@ -67,6 +72,31 @@ class State:
|
|||||||
self.__c += 1
|
self.__c += 1
|
||||||
|
|
||||||
|
|
||||||
|
def __check_item(self, item):
|
||||||
|
if self.__items_reverse.get(item) != None:
|
||||||
|
raise StateItemExists(item)
|
||||||
|
|
||||||
|
|
||||||
|
def __add_state_list(self, state, item):
|
||||||
|
if self.__items.get(state) == None:
|
||||||
|
self.__items[state] = []
|
||||||
|
self.__items[state].append(item)
|
||||||
|
self.__items_reverse[item] = state
|
||||||
|
|
||||||
|
|
||||||
|
def __state_list_index(self, item, state_list):
|
||||||
|
idx = -1
|
||||||
|
try:
|
||||||
|
idx = state_list.index(item)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if idx == -1:
|
||||||
|
raise StateCorruptionError() # should have state int here as value
|
||||||
|
|
||||||
|
return idx
|
||||||
|
|
||||||
|
|
||||||
def add(self, k):
|
def add(self, k):
|
||||||
v = 1 << self.__c
|
v = 1 << self.__c
|
||||||
k = self.__check_name(k)
|
k = self.__check_name(k)
|
||||||
@ -111,3 +141,56 @@ class State:
|
|||||||
c <<= 1
|
c <<= 1
|
||||||
|
|
||||||
return (alias, r,)
|
return (alias, r,)
|
||||||
|
|
||||||
|
|
||||||
|
def put(self, item, state=None):
|
||||||
|
if state == None:
|
||||||
|
state = self.NEW
|
||||||
|
elif self.__reverse.get(state) == None:
|
||||||
|
raise StateInvalid(state)
|
||||||
|
self.__check_item(item)
|
||||||
|
self.__add_state_list(state, item)
|
||||||
|
|
||||||
|
|
||||||
|
def move(self, item, to_state):
|
||||||
|
current_state = self.__items_reverse.get(item)
|
||||||
|
if current_state == None:
|
||||||
|
raise StateItemNotFound(item)
|
||||||
|
|
||||||
|
new_state = self.__reverse.get(to_state)
|
||||||
|
if new_state == None:
|
||||||
|
raise StateInvalid(to_state)
|
||||||
|
|
||||||
|
current_state_list = self.__items.get(current_state)
|
||||||
|
if current_state_list == None:
|
||||||
|
raise StateCorruptionError(current_state)
|
||||||
|
|
||||||
|
idx = self.__state_list_index(item, current_state_list)
|
||||||
|
|
||||||
|
new_state_list = self.__items.get(to_state)
|
||||||
|
if current_state_list == None:
|
||||||
|
raise StateCorruptionError(to_state)
|
||||||
|
|
||||||
|
self.__add_state_list(to_state, item)
|
||||||
|
current_state_list.pop(idx)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def purge(self, item):
|
||||||
|
current_state = self.__items_reverse.get(item)
|
||||||
|
if current_state == None:
|
||||||
|
raise StateItemNotFound(item)
|
||||||
|
del self.__items_reverse[item]
|
||||||
|
|
||||||
|
current_state_list = self.__items.get(current_state)
|
||||||
|
|
||||||
|
idx = self.__state_list_index(item, current_state_list)
|
||||||
|
|
||||||
|
current_state_list.pop(idx)
|
||||||
|
|
||||||
|
|
||||||
|
def state(self, item):
|
||||||
|
state = self.__items_reverse.get(item)
|
||||||
|
if state == None:
|
||||||
|
raise StateItemNotFound(item)
|
||||||
|
return state
|
||||||
|
79
tests/test_item.py
Normal file
79
tests/test_item.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# standard imports
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from shep import State
|
||||||
|
from shep.error import (
|
||||||
|
StateExists,
|
||||||
|
StateItemExists,
|
||||||
|
StateInvalid,
|
||||||
|
StateItemNotFound,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestStateItems(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.states = State(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_put(self):
|
||||||
|
item = b'foo'
|
||||||
|
|
||||||
|
# put in initial (no) state
|
||||||
|
self.states.put(item)
|
||||||
|
|
||||||
|
with self.assertRaises(StateItemExists):
|
||||||
|
self.states.put(item)
|
||||||
|
|
||||||
|
with self.assertRaises(StateItemExists):
|
||||||
|
self.states.put(item, self.states.BAZ)
|
||||||
|
|
||||||
|
|
||||||
|
def test_item_state(self):
|
||||||
|
item = b'foo'
|
||||||
|
self.states.put(item, self.states.XYZZY)
|
||||||
|
self.assertEqual(self.states.state(item), self.states.XYZZY)
|
||||||
|
|
||||||
|
|
||||||
|
def test_item_move(self):
|
||||||
|
item = b'foo'
|
||||||
|
self.states.put(item, self.states.FOO)
|
||||||
|
self.states.move(item, self.states.BAR)
|
||||||
|
self.assertEqual(self.states.state(item), self.states.BAR)
|
||||||
|
|
||||||
|
|
||||||
|
def test_item_move_from_alias(self):
|
||||||
|
item = b'foo'
|
||||||
|
self.states.put(item, self.states.FOO)
|
||||||
|
self.states.move(item, self.states.XYZZY)
|
||||||
|
self.assertEqual(self.states.state(item), self.states.XYZZY)
|
||||||
|
self.states.move(item, self.states.BAR)
|
||||||
|
self.assertEqual(self.states.state(item), self.states.BAR)
|
||||||
|
|
||||||
|
|
||||||
|
def test_item_move_from_new(self):
|
||||||
|
item = b'foo'
|
||||||
|
self.states.put(item)
|
||||||
|
self.assertEqual(self.states.state(item), self.states.NEW)
|
||||||
|
self.states.move(item, self.states.XYZZY)
|
||||||
|
self.assertEqual(self.states.state(item), self.states.XYZZY)
|
||||||
|
|
||||||
|
|
||||||
|
def test_item_purge(self):
|
||||||
|
item = b'foo'
|
||||||
|
self.states.put(item, self.states.BAZ)
|
||||||
|
self.assertEqual(self.states.state(item), self.states.BAZ)
|
||||||
|
self.states.purge(item)
|
||||||
|
with self.assertRaises(StateItemNotFound):
|
||||||
|
self.states.state(item)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
Loading…
Reference in New Issue
Block a user