summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2017-06-29 23:51:47 +0200
committerJ08nY2017-08-07 18:18:00 +0200
commit8b09113eb40c39ada3dc902cb4e869c8f012c97d (patch)
tree099be05c5c8788eca12310ab3a2f950bd3d5c6a5
parent00f52639673dc4db32ac9302e2a70483492d621e (diff)
downloadmailman-8b09113eb40c39ada3dc902cb4e869c8f012c97d.tar.gz
mailman-8b09113eb40c39ada3dc902cb4e869c8f012c97d.tar.zst
mailman-8b09113eb40c39ada3dc902cb4e869c8f012c97d.zip
-rw-r--r--src/mailman/app/subscriptions.py4
-rw-r--r--src/mailman/app/tests/test_workflow.py12
-rw-r--r--src/mailman/config/configure.zcml4
-rw-r--r--src/mailman/interfaces/workflows.py (renamed from src/mailman/interfaces/workflow.py)63
-rw-r--r--src/mailman/model/tests/test_workflow.py2
-rw-r--r--src/mailman/model/workflows.py (renamed from src/mailman/model/workflow.py)2
-rw-r--r--src/mailman/workflows/__init__.py0
-rw-r--r--src/mailman/workflows/base.py (renamed from src/mailman/app/workflow.py)56
8 files changed, 98 insertions, 45 deletions
diff --git a/src/mailman/app/subscriptions.py b/src/mailman/app/subscriptions.py
index 0d8176ffb..dace9ccb6 100644
--- a/src/mailman/app/subscriptions.py
+++ b/src/mailman/app/subscriptions.py
@@ -24,7 +24,6 @@ from datetime import timedelta
from email.utils import formataddr
from enum import Enum
from mailman.app.membership import delete_member
-from mailman.app.workflow import Workflow
from mailman.core.i18n import _
from mailman.database.transaction import flush
from mailman.email.message import UserNotification
@@ -43,9 +42,10 @@ from mailman.interfaces.subscriptions import (
from mailman.interfaces.template import ITemplateLoader
from mailman.interfaces.user import IUser
from mailman.interfaces.usermanager import IUserManager
-from mailman.interfaces.workflow import IWorkflowStateManager
+from mailman.interfaces.workflows import IWorkflowStateManager
from mailman.utilities.datetime import now
from mailman.utilities.string import expand, wrap
+from mailman.workflows.base import Workflow
from public import public
from zope.component import getUtility
from zope.event import notify
diff --git a/src/mailman/app/tests/test_workflow.py b/src/mailman/app/tests/test_workflow.py
index e82001540..f242a73ec 100644
--- a/src/mailman/app/tests/test_workflow.py
+++ b/src/mailman/app/tests/test_workflow.py
@@ -20,15 +20,15 @@
import json
import unittest
-from mailman.app.workflow import Workflow
-from mailman.interfaces.workflow import IWorkflowStateManager
+from mailman.interfaces.workflows import IWorkflowStateManager
from mailman.testing.layers import ConfigLayer
+from mailman.workflows.base import Workflow
from zope.component import getUtility
class MyWorkflow(Workflow):
- INITIAL_STATE = 'first'
- SAVE_ATTRIBUTES = ('ant', 'bee', 'cat')
+ initial_state = 'first'
+ save_attributes = ('ant', 'bee', 'cat')
def __init__(self):
super().__init__()
@@ -51,7 +51,7 @@ class MyWorkflow(Workflow):
class DependentWorkflow(MyWorkflow):
- SAVE_ATTRIBUTES = ('ant', 'bee', 'cat', 'elf')
+ save_attributes = ('ant', 'bee', 'cat', 'elf')
def __init__(self):
super().__init__()
@@ -136,7 +136,7 @@ class TestWorkflow(unittest.TestCase):
def test_save_and_restore_dependant_attributes(self):
# Attributes must be restored in the order they are declared in
- # SAVE_ATTRIBUTES.
+ # save_attributes.
workflow = iter(DependentWorkflow())
workflow.elf = 6
workflow.save()
diff --git a/src/mailman/config/configure.zcml b/src/mailman/config/configure.zcml
index 2fd0c8788..da4eb36b6 100644
--- a/src/mailman/config/configure.zcml
+++ b/src/mailman/config/configure.zcml
@@ -135,8 +135,8 @@
/>
<utility
- provides="mailman.interfaces.workflow.IWorkflowStateManager"
- factory="mailman.model.workflow.WorkflowStateManager"
+ provides="mailman.interfaces.workflows.IWorkflowStateManager"
+ factory="mailman.model.workflows.WorkflowStateManager"
/>
</configure>
diff --git a/src/mailman/interfaces/workflow.py b/src/mailman/interfaces/workflows.py
index 5b3582b58..b110a481e 100644
--- a/src/mailman/interfaces/workflow.py
+++ b/src/mailman/interfaces/workflows.py
@@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License along with
# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
-"""Interfaces describing the state of a workflow."""
+"""Interfaces describing the a workflow, it's state and it's state manager."""
from public import public
from zope.interface import Attribute, Interface
@@ -65,3 +65,64 @@ class IWorkflowStateManager(Interface):
"""
count = Attribute('The number of saved workflows in the database.')
+
+
+@public
+class IWorkflow(Interface):
+ """A workflow."""
+
+ name = Attribute('The name of the workflow, must be unique.')
+ description = Attribute('A brief description of the workflow.')
+ initial_state = Attribute('The state in which the workflow starts.')
+ save_attributes = Attribute('The sequence of attributes of the workflow, '
+ 'which are saved.')
+
+ def __iter__():
+ """Return an iterator over the steps."""
+
+ def __next__():
+ """Run the next step from the queue.
+
+ :return: The result of the step run.
+ """
+
+ def push(step):
+ """Push a step to this workflows queue."""
+
+ def run_thru(stop_after):
+ """Run the state machine through and including the given 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_until(stop_before):
+ """Run 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.
+ """
+
+ def save():
+ """Save the workflow in it's current state.
+
+ Needs to have the `token` attribute set.
+ """
+
+ def restore():
+ """Restore the workflow from the database.
+
+ Needs to have the `token` attribute set.
+ """
+
+
+@public
+class ISubscriptionWorkflow(IWorkflow):
+ """A workflow used for subscription."""
+
+
+@public
+class IUnsubscriptionWorkflow(IWorkflow):
+ """A workflow used for unsubscription."""
diff --git a/src/mailman/model/tests/test_workflow.py b/src/mailman/model/tests/test_workflow.py
index 9cc5446b7..41c00efc0 100644
--- a/src/mailman/model/tests/test_workflow.py
+++ b/src/mailman/model/tests/test_workflow.py
@@ -19,7 +19,7 @@
import unittest
-from mailman.interfaces.workflow import IWorkflowStateManager
+from mailman.interfaces.workflows import IWorkflowStateManager
from mailman.testing.layers import ConfigLayer
from zope.component import getUtility
diff --git a/src/mailman/model/workflow.py b/src/mailman/model/workflows.py
index 3ca3412a6..587d3375e 100644
--- a/src/mailman/model/workflow.py
+++ b/src/mailman/model/workflows.py
@@ -20,7 +20,7 @@
from mailman.database.model import Model
from mailman.database.transaction import dbconnection
from mailman.database.types import SAUnicode
-from mailman.interfaces.workflow import IWorkflowState, IWorkflowStateManager
+from mailman.interfaces.workflows import IWorkflowState, IWorkflowStateManager
from public import public
from sqlalchemy import Column
from zope.interface import implementer
diff --git a/src/mailman/workflows/__init__.py b/src/mailman/workflows/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/mailman/workflows/__init__.py
diff --git a/src/mailman/app/workflow.py b/src/mailman/workflows/base.py
index 92b78c184..5988dfa43 100644
--- a/src/mailman/app/workflow.py
+++ b/src/mailman/workflows/base.py
@@ -22,7 +22,8 @@ import json
import logging
from collections import deque
-from mailman.interfaces.workflow import IWorkflowStateManager
+
+from mailman.interfaces.workflows import IWorkflowStateManager
from public import public
from zope.component import getUtility
@@ -35,24 +36,33 @@ log = logging.getLogger('mailman.error')
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 __next__(self):
+ """See `IWorkflow`."""
+ try:
+ name, step = self._pop()
+ return step()
+ except IndexError:
+ raise StopIteration
+ except:
+ log.exception('deque: {}'.format(COMMASPACE.join(self._next)))
+ raise
+
def push(self, step):
+ """See `IWorkflow`."""
self._next.append(step)
def _pop(self):
@@ -63,23 +73,8 @@ class Workflow:
print('[{:02d}] -> {}'.format(self._count, name), file=sys.stderr)
return name, step
- def __next__(self):
- try:
- name, step = self._pop()
- return step()
- except IndexError:
- raise StopIteration
- except:
- 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.
-
- :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.
- """
+ """See `IWorkflow`."""
results = []
while True:
try:
@@ -93,12 +88,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,9 +106,10 @@ 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}
+ 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
@@ -135,6 +126,7 @@ class Workflow:
state_manager.save(self.token, step, json.dumps(data))
def restore(self):
+ """See `IWorkflow`."""
state_manager = getUtility(IWorkflowStateManager)
state = state_manager.restore(self.token)
if state is None:
@@ -144,7 +136,7 @@ class Workflow:
if state.step:
self._next.append(state.step)
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: