Kanban example
This commit is contained in:
		
							parent
							
								
									d074174f37
								
							
						
					
					
						commit
						9f71401bb5
					
				
							
								
								
									
										64
									
								
								example/kanban.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								example/kanban.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
			
		||||
from shep.state import State
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# we don't like "NEW" as the default label for a new item in the queue, so we change it to BACKLOG
 | 
			
		||||
State.set_default_state('backlog')
 | 
			
		||||
 | 
			
		||||
# define all the valid states
 | 
			
		||||
st = State(5)
 | 
			
		||||
st.add('pending')
 | 
			
		||||
st.add('blocked')
 | 
			
		||||
st.add('doing')
 | 
			
		||||
st.add('review')
 | 
			
		||||
st.add('finished')
 | 
			
		||||
 | 
			
		||||
# define a couple of states that give a bit more context to progress; something is blocked before starting development or something is blocked during development...
 | 
			
		||||
st.alias('startblock', st.BLOCKED, st.PENDING)
 | 
			
		||||
st.alias('doingblock', st.BLOCKED, st.DOING)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# create the foo key which will forever languish in backlog
 | 
			
		||||
k = 'foo'
 | 
			
		||||
st.put(k)
 | 
			
		||||
foo_state = st.state(k)
 | 
			
		||||
foo_state_name = st.name(foo_state)
 | 
			
		||||
foo_contents_r = st.get('foo')
 | 
			
		||||
print('{} {} {}'.format(k, foo_state_name, foo_contents_r))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Create bar->baz and advance it from backlog to pending
 | 
			
		||||
k = 'bar'
 | 
			
		||||
bar_contents = 'baz'
 | 
			
		||||
st.put(k, contents=bar_contents)
 | 
			
		||||
 | 
			
		||||
st.next(k)
 | 
			
		||||
bar_state = st.state(k)
 | 
			
		||||
bar_state_name = st.name(bar_state)
 | 
			
		||||
bar_contents_r = st.get('bar')
 | 
			
		||||
print('{} {} {}'.format(k, bar_state_name, bar_contents_r))
 | 
			
		||||
 | 
			
		||||
# Create inky->pinky and move to doing then doing-blocked
 | 
			
		||||
k = 'inky'
 | 
			
		||||
inky_contents = 'pinky'
 | 
			
		||||
st.put(k, contents=inky_contents)
 | 
			
		||||
inky_state = st.state(k)
 | 
			
		||||
st.move(k, st.DOING)
 | 
			
		||||
st.set(k, st.BLOCKED)
 | 
			
		||||
inky_state = st.state(k)
 | 
			
		||||
inky_state_name = st.name(inky_state)
 | 
			
		||||
inky_contents_r = st.get('inky')
 | 
			
		||||
print('{} {} {}'.format(k, inky_state_name, bar_contents_r))
 | 
			
		||||
 | 
			
		||||
# then replace the content
 | 
			
		||||
# note that replace could potentially mean some VCS below
 | 
			
		||||
inky_new_contents = 'blinky'
 | 
			
		||||
st.replace(k, inky_new_contents)
 | 
			
		||||
inky_contents_r = st.get('inky')
 | 
			
		||||
print('{} {} {}'.format(k, inky_state_name, inky_contents_r))
 | 
			
		||||
 | 
			
		||||
# so now move to review
 | 
			
		||||
st.move(k, st.REVIEW)
 | 
			
		||||
inky_state = st.state(k)
 | 
			
		||||
inky_state_name = st.name(inky_state)
 | 
			
		||||
print('{} {} {}'.format(k, inky_state_name, inky_contents_r))
 | 
			
		||||
 | 
			
		||||
@ -19,18 +19,27 @@ class State:
 | 
			
		||||
    :param logger: Standard library logging instance to output to
 | 
			
		||||
    :type logger: logging.Logger
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    base_state_name = 'NEW'
 | 
			
		||||
 | 
			
		||||
    def __init__(self, bits, logger=None):
 | 
			
		||||
        self.__bits = bits
 | 
			
		||||
        self.__limit = (1 << bits) - 1
 | 
			
		||||
        self.__c = 0
 | 
			
		||||
        self.NEW = 0
 | 
			
		||||
        setattr(self, self.base_state_name, 0)
 | 
			
		||||
        #self.NEW = 0
 | 
			
		||||
 | 
			
		||||
        self.__reverse = {0: self.NEW}
 | 
			
		||||
        self.__keys = {self.NEW: []}
 | 
			
		||||
        self.__reverse = {0: getattr(self, self.base_state_name)}
 | 
			
		||||
        self.__keys = {getattr(self, self.base_state_name): []}
 | 
			
		||||
        self.__keys_reverse = {}
 | 
			
		||||
        self.__contents = {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def set_default_state(cls, state_name):
 | 
			
		||||
        cls.base_state_name = state_name.upper()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    # return true if v is a single-bit state
 | 
			
		||||
    def __is_pure(self, v):
 | 
			
		||||
        if v == 0:
 | 
			
		||||
@ -197,7 +206,7 @@ class State:
 | 
			
		||||
        :return: State name
 | 
			
		||||
        """
 | 
			
		||||
        if v == None or v == 0:
 | 
			
		||||
            return 'NEW'
 | 
			
		||||
            return self.base_state_name
 | 
			
		||||
        k = self.__reverse.get(v)
 | 
			
		||||
        if k == None:
 | 
			
		||||
            raise StateInvalid(v)
 | 
			
		||||
@ -252,13 +261,13 @@ class State:
 | 
			
		||||
    def put(self, key, state=None, contents=None):
 | 
			
		||||
        """Add a key to an existing state.
 | 
			
		||||
        
 | 
			
		||||
        If no state it specified, the default state attribute "NEW" will be used.
 | 
			
		||||
        If no state it specified, the default state attribute State.base_state_name will be used.
 | 
			
		||||
        
 | 
			
		||||
        Contents may be supplied as value to pair with the given key. Contents may be changed later by calling the `replace` method.
 | 
			
		||||
        
 | 
			
		||||
        :param key: Content key to add
 | 
			
		||||
        :type key: str
 | 
			
		||||
        :param state: Initial state for the put. If not given, initial state will be NEW
 | 
			
		||||
        :param state: Initial state for the put. If not given, initial state will be State.base_state_name
 | 
			
		||||
        :type state: int
 | 
			
		||||
        :param contents: Contents to associate with key. A valie of None should be recognized as an undefined value as opposed to a zero-length value throughout any backend
 | 
			
		||||
        :type contents: str
 | 
			
		||||
@ -268,7 +277,7 @@ class State:
 | 
			
		||||
        :return: Resulting state that key is put under (should match the input state)
 | 
			
		||||
        """
 | 
			
		||||
        if state == None:
 | 
			
		||||
            state = self.NEW
 | 
			
		||||
            state = getattr(self, self.base_state_name)
 | 
			
		||||
        elif self.__reverse.get(state) == None:
 | 
			
		||||
            raise StateInvalid(state)
 | 
			
		||||
        self.__check_key(key)
 | 
			
		||||
@ -351,13 +360,13 @@ class State:
 | 
			
		||||
    def unset(self, key, not_state):
 | 
			
		||||
        """Unset a single bit, moving to a pure or alias state.
 | 
			
		||||
        
 | 
			
		||||
        The resulting state cannot be NEW (0).
 | 
			
		||||
        The resulting state cannot be State.base_state_name (0).
 | 
			
		||||
         
 | 
			
		||||
        :param key: Content key to modify state for
 | 
			
		||||
        :type key: str
 | 
			
		||||
        :param or_state: Atomic stat to add
 | 
			
		||||
        :type or_state: int
 | 
			
		||||
        :raises ValueError: State is not a single bit state, or attempts to revert to NEW
 | 
			
		||||
        :raises ValueError: State is not a single bit state, or attempts to revert to State.base_state_name
 | 
			
		||||
        :raises StateItemNotFound: Content key is not registered
 | 
			
		||||
        :raises StateInvalid: Resulting state after addition of atomic state is unknown
 | 
			
		||||
        :rtype: int
 | 
			
		||||
@ -374,8 +383,8 @@ class State:
 | 
			
		||||
        if to_state == current_state:
 | 
			
		||||
            raise ValueError('invalid change for state {}: {}'.format(key, not_state))
 | 
			
		||||
 | 
			
		||||
        if to_state == self.NEW:
 | 
			
		||||
            raise ValueError('State {} for {} cannot be reverted to NEW'.format(current_state, key))
 | 
			
		||||
        if to_state == getattr(self, self.base_state_name):
 | 
			
		||||
            raise ValueError('State {} for {} cannot be reverted to {}'.format(current_state, key, self.base_state_name))
 | 
			
		||||
 | 
			
		||||
        new_state = self.__reverse.get(to_state)
 | 
			
		||||
        if new_state == None:
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user