summaryrefslogtreecommitdiff
path: root/src/mailman/workflows/base.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/mailman/workflows/base.py (renamed from src/mailman/app/workflow.py)82
1 files changed, 35 insertions, 47 deletions
diff --git a/src/mailman/app/workflow.py b/src/mailman/workflows/base.py
index 92b78c184..8153bf77d 100644
--- a/src/mailman/app/workflow.py
+++ b/src/mailman/workflows/base.py
@@ -22,9 +22,12 @@ import json
import logging
from collections import deque
-from mailman.interfaces.workflow import IWorkflowStateManager
+
+from mailman.interfaces.workflows import IWorkflow, IWorkflowStateManager
+from mailman.utilities.modules import abstract_component
from public import public
from zope.component import getUtility
+from zope.interface import implementer
COMMASPACE = ', '
@@ -32,38 +35,27 @@ log = logging.getLogger('mailman.error')
@public
+@abstract_component
+@implementer(IWorkflow)
class Workflow:
"""Generic workflow."""
- SAVE_ATTRIBUTES = ()
- INITIAL_STATE = None
+ initial_state = None
+ save_attributes = ()
def __init__(self):
self.token = None
self._next = deque()
- self.push(self.INITIAL_STATE)
+ self.push(self.initial_state)
self.debug = False
self._count = 0
- @property
- def name(self):
- return self.__class__.__name__
-
def __iter__(self):
+ """See `IWorkflow`."""
return self
- def push(self, step):
- self._next.append(step)
-
- def _pop(self):
- name = self._next.popleft()
- step = getattr(self, '_step_{}'.format(name))
- self._count += 1
- if self.debug: # pragma: nocover
- print('[{:02d}] -> {}'.format(self._count, name), file=sys.stderr)
- return name, step
-
def __next__(self):
+ """See `IWorkflow`."""
try:
name, step = self._pop()
return step()
@@ -73,13 +65,20 @@ class Workflow:
log.exception('deque: {}'.format(COMMASPACE.join(self._next)))
raise
- def run_thru(self, stop_after):
- """Run the state machine through and including the given step.
+ def push(self, step):
+ """See `IWorkflow`."""
+ self._next.append(step)
+
+ def _pop(self):
+ name = self._next.pop()
+ step = getattr(self, '_step_{}'.format(name))
+ self._count += 1
+ if self.debug: # pragma: nocover
+ print('[{:02d}] -> {}'.format(self._count, name), file=sys.stderr)
+ return name, step
- :param stop_after: Name of method, sans prefix to run the
- state machine through. In other words, the state machine runs
- until the named method completes.
- """
+ def run_thru(self, stop_after):
+ """See `IWorkflow`."""
results = []
while True:
try:
@@ -93,12 +92,7 @@ class Workflow:
return results
def run_until(self, stop_before):
- """Trun the state machine until (not including) the given step.
-
- :param stop_before: Name of method, sans prefix that the
- state machine is run until the method is reached. Unlike
- `run_thru()` the named method is not run.
- """
+ """See `IWorkflow`."""
results = []
while True:
try:
@@ -116,35 +110,29 @@ class Workflow:
return results
def save(self):
+ """See `IWorkflow`."""
assert self.token, 'Workflow token must be set'
state_manager = getUtility(IWorkflowStateManager)
- data = {attr: getattr(self, attr) for attr in self.SAVE_ATTRIBUTES}
- # Note: only the next step is saved, not the whole stack. This is not
- # an issue in practice, since there's never more than a single step in
- # the queue anyway. If we want to support more than a single step in
- # the queue *and* want to support state saving/restoring, change this
- # method and the restore() method.
+ data = {attr: getattr(self, attr) for attr in self.save_attributes}
+ # Save the workflow stack.
if len(self._next) == 0:
- step = None
- elif len(self._next) == 1:
- step = self._next[0]
+ steps = '[]'
else:
- raise AssertionError(
- "Can't save a workflow state with more than one step "
- "in the queue")
- state_manager.save(self.token, step, json.dumps(data))
+ steps = json.dumps(list(self._next))
+ state_manager.save(self.token, steps, json.dumps(data))
def restore(self):
+ """See `IWorkflow`."""
state_manager = getUtility(IWorkflowStateManager)
state = state_manager.restore(self.token)
if state is None:
# The token doesn't exist in the database.
raise LookupError(self.token)
self._next.clear()
- if state.step:
- self._next.append(state.step)
+ if state.steps:
+ self._next.extend(json.loads(state.steps))
data = json.loads(state.data)
- for attr in self.SAVE_ATTRIBUTES:
+ for attr in self.save_attributes:
try:
setattr(self, attr, data[attr])
except KeyError: