Add verifier
This commit is contained in:
parent
9f71401bb5
commit
9ad005ae42
@ -1,3 +1,7 @@
|
||||
- 0.1.1
|
||||
* Add optional, pluggable verifier to protect state transition
|
||||
- 0.1.0
|
||||
* Release version bump
|
||||
- 0.0.19:
|
||||
* Enable alias with comma separated values
|
||||
- 0.0.18
|
||||
|
@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
name = shep
|
||||
version = 0.1.0rc1
|
||||
version = 0.1.1rc1
|
||||
description = Multi-state key stores using bit masks
|
||||
author = Louis Holbrook
|
||||
author_email = dev@holbrook.no
|
||||
|
@ -26,3 +26,9 @@ class StateCorruptionError(RuntimeError):
|
||||
"""An irrecoverable discrepancy between persisted state and memory state has occurred.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class StateTransitionInvalid(Exception):
|
||||
"""Raised if state transition verification fails
|
||||
"""
|
||||
pass
|
||||
|
@ -1,12 +1,18 @@
|
||||
# standard imports
|
||||
import re
|
||||
|
||||
# local imports
|
||||
from shep.error import (
|
||||
StateExists,
|
||||
StateInvalid,
|
||||
StateItemExists,
|
||||
StateItemNotFound,
|
||||
StateTransitionInvalid,
|
||||
)
|
||||
|
||||
|
||||
re_name = r'^[a-zA-Z_]+$'
|
||||
|
||||
class State:
|
||||
"""State is an in-memory bitmasked state store for key-value pairs, or even just keys alone.
|
||||
|
||||
@ -22,17 +28,17 @@ class State:
|
||||
|
||||
base_state_name = 'NEW'
|
||||
|
||||
def __init__(self, bits, logger=None):
|
||||
def __init__(self, bits, logger=None, verifier=None):
|
||||
self.__bits = bits
|
||||
self.__limit = (1 << bits) - 1
|
||||
self.__c = 0
|
||||
setattr(self, self.base_state_name, 0)
|
||||
#self.NEW = 0
|
||||
|
||||
self.__reverse = {0: getattr(self, self.base_state_name)}
|
||||
self.__keys = {getattr(self, self.base_state_name): []}
|
||||
self.__keys_reverse = {}
|
||||
self.__contents = {}
|
||||
self.verifier = verifier
|
||||
|
||||
|
||||
@classmethod
|
||||
@ -54,8 +60,8 @@ class State:
|
||||
|
||||
# validates a state name and return its canonical representation
|
||||
def __check_name_valid(self, k):
|
||||
if not k.isalpha():
|
||||
raise ValueError('only alpha')
|
||||
if not re.match(re_name, k):
|
||||
raise ValueError('only alpha and underscore')
|
||||
return k.upper()
|
||||
|
||||
|
||||
@ -323,6 +329,11 @@ class State:
|
||||
if current_state_list == None:
|
||||
raise StateCorruptionError(to_state)
|
||||
|
||||
if self.verifier != None:
|
||||
r = self.verifier(self, from_state, to_state)
|
||||
if r != None:
|
||||
raise StateTransitionInvalid('{} -> {}: {}'.format(from_state, to_state, r))
|
||||
|
||||
self.__add_state_list(to_state, key)
|
||||
current_state_list.pop(idx)
|
||||
|
||||
|
2
shep/verify.py
Normal file
2
shep/verify.py
Normal file
@ -0,0 +1,2 @@
|
||||
def default_checker(statestore, old, new):
|
||||
return None
|
@ -18,7 +18,6 @@ class TestState(unittest.TestCase):
|
||||
for k in [
|
||||
'f0o',
|
||||
'f oo',
|
||||
'f_oo',
|
||||
]:
|
||||
with self.assertRaises(ValueError):
|
||||
states.add(k)
|
||||
|
Loading…
Reference in New Issue
Block a user