Optional allow undefined alias states
This commit is contained in:
parent
d68286ee6c
commit
af8ce95e22
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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):
|
||||
|
@ -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')
|
||||
|
Loading…
Reference in New Issue
Block a user