Optional allow undefined alias states

This commit is contained in:
lash 2022-03-16 16:49:00 +00:00
parent d68286ee6c
commit af8ce95e22
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
5 changed files with 68 additions and 14 deletions

View File

@ -1,6 +1,7 @@
- 0.1.1
* Add optional, pluggable verifier to protect state transition
* Add change method for atomic simultaneous set and unset
* Optional, pluggable verifier to protect state transition
* Change method for atomic simultaneous set and unset
* Optionally allow undefined composite states
- 0.1.0
* Release version bump
- 0.0.19:

View File

@ -1,3 +1,6 @@
# standard imports
import datetime
# local imports
from .state import State
from .error import StateItemExists
@ -95,6 +98,8 @@ class PersistedState(State):
self.__stores[k_to].add(key, contents)
self.__stores[k_from].remove(key)
self.register_modify(key)
return to_state
@ -119,6 +124,8 @@ class PersistedState(State):
self.__stores[k_to].add(key, contents)
self.__stores[k_from].remove(key)
self.register_modify(key)
return to_state
@ -192,3 +199,9 @@ class PersistedState(State):
state = self.state(key)
k = self.name(state)
return self.__stores[k].replace(key, contents)
def modified(self, key):
state = self.state(key)
k = self.name(state)
return self.__stores[k].modified(key)

View File

@ -30,7 +30,7 @@ class State:
base_state_name = 'NEW'
def __init__(self, bits, logger=None, verifier=None):
def __init__(self, bits, logger=None, verifier=None, check_alias=True):
self.__bits = bits
self.__limit = (1 << bits) - 1
self.__c = 0
@ -40,8 +40,9 @@ class State:
self.__keys = {getattr(self, self.base_state_name): []}
self.__keys_reverse = {}
self.__contents = {}
self.__change = {}
self.modified_last = {}
self.verifier = verifier
self.check_alias = check_alias
@classmethod
@ -135,7 +136,6 @@ class State:
if not self.__is_pure(state) or state == 0:
self.__keys[state].append(item)
c = 1
import sys
for i in range(self.__bits):
part = c & state
if part > 0:
@ -215,6 +215,18 @@ class State:
return l
def elements(self, v):
r = []
if v == None or v == 0:
return self.base_state_name
c = 1
for i in range(1, self.__bits):
if v & c > 0:
r.append(self.name(c))
c <<= 1
return '*' + ','.join(r)
def name(self, v):
"""Retrieve that string representation of the state attribute represented by the given state integer value.
@ -224,11 +236,14 @@ class State:
:rtype: str
:return: State name
"""
if v == None or v == 0:
return self.base_state_name
k = self.__reverse.get(v)
if k == None:
raise StateInvalid(v)
if self.check_alias:
raise StateInvalid(v)
else:
k = self.elements(v)
elif v == None or v == 0:
return self.base_state_name
return k
@ -379,7 +394,7 @@ class State:
to_state = current_state | or_state
new_state = self.__reverse.get(to_state)
if new_state == None:
if new_state == None and self.check_alias:
raise StateInvalid('resulting to state is unknown: {}'.format(to_state))
return self.__move(key, current_state, to_state)
@ -558,8 +573,8 @@ class State:
def modified(self, key):
return self.__change[key]
return self.modified_last[key]
def register_modify(self, key):
self.__change[key] = datetime.datetime.now().timestamp()
self.modified_last[key] = datetime.datetime.now().timestamp()

View File

@ -106,7 +106,7 @@ class SimpleFileStore:
def modified(self, k):
path = self.path(k)
st = os.stat(path)
return float(st.st_ctime())
return st.st_ctime
def register_modify(self, k):

View File

@ -1,5 +1,6 @@
# standard imports
import unittest
import logging
# local imports
from shep import State
@ -8,6 +9,9 @@ from shep.error import (
StateInvalid,
)
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
class TestState(unittest.TestCase):
@ -81,7 +85,29 @@ class TestState(unittest.TestCase):
states.add('bar')
with self.assertRaises(StateInvalid):
states.alias('baz', 5)
def test_alias_invalid(self):
states = State(3)
states.add('foo')
states.add('bar')
states.put('abcd')
states.set('abcd', states.FOO)
with self.assertRaises(StateInvalid):
states.set('abcd', states.BAR)
def test_alias_invalid_ignore(self):
states = State(3, check_alias=False)
states.add('foo')
states.add('bar')
states.put('abcd')
states.set('abcd', states.FOO)
states.set('abcd', states.BAR)
v = states.state('abcd')
s = states.name(v)
self.assertEqual(s, '*FOO,BAR')
def test_peek(self):
states = State(3)
@ -106,7 +132,6 @@ class TestState(unittest.TestCase):
self.assertEqual(states.from_name('foo'), states.FOO)
def test_change(self):
states = State(3)
states.add('foo')