Skip to content
This repository has been archived by the owner on May 28, 2018. It is now read-only.

Commit

Permalink
Improve docs
Browse files Browse the repository at this point in the history
  • Loading branch information
kmmbvnr committed Nov 2, 2016
1 parent dee5eae commit 0f01143
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 12 deletions.
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ universal=1

[pep257]
add-ignore = D100,D104,D105
match-dir= (?!south_migrations)
4 changes: 2 additions & 2 deletions viewflow/nodes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
from .view import Start, View


__all__ = [
__all__ = (
'End', 'StartFunction', 'Function', 'Handler',
'If', 'AbstractJob', 'Join', 'StartSignal', 'Signal',
'Split', 'Switch', 'Start', 'View'
]
)
7 changes: 6 additions & 1 deletion viewflow/nodes/end.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ class End(mixins.TaskDescriptionMixin,
mixins.CancelViewMixin,
mixins.PerformViewMixin,
Event):
"""End of the flow.
If no other parallel activities exists, finishes the whole
process.
"""

task_type = 'END'
activation_class = EndActivation

def __init__(self, **kwargs):
def __init__(self, **kwargs): # noqa D102
super(End, self).__init__(**kwargs)

def _outgoing(self):
Expand Down
40 changes: 33 additions & 7 deletions viewflow/nodes/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@


class HandlerActivation(Activation):
"""
Handler Activation.
Executes a callback immediately.
"""

def execute(self):
"""Run the callback."""
self.flow_task.handler(self)

@Activation.status.transition(source=STATUS.NEW)
def perform(self):
"""Perform the callback within current exception propagation strategy."""
with self.exception_guard():
self.task.started = now()

Expand All @@ -27,16 +35,12 @@ def perform(self):

@Activation.status.transition(source=STATUS.ERROR)
def retry(self):
"""
Retry the next node calculation and activation
"""
"""Retry the next node calculation and activation."""
self.perform.original()

@Activation.status.transition(source=[STATUS.ERROR, STATUS.DONE], target=STATUS.NEW)
def undo(self):
"""
Undo the task
"""
"""Undo the task."""
super(HandlerActivation, self).undo.original()

@Activation.status.transition(source=STATUS.DONE, conditions=[all_leading_canceled])
Expand Down Expand Up @@ -70,14 +74,36 @@ class Handler(mixins.TaskDescriptionMixin,
mixins.CancelViewMixin,
mixins.PerformViewMixin,
Event):
"""
Callback executed synchronously on a task activation.
Example::
class MyFlow(Flow):
calc_total = (
flow.Handler(this.calc_order_total)
)
...
def calc_order_total(self, activation):
total = [
sum(item.price)
for item in activation.process.items.all()
]
activation.process.total_amount = total
activation.process.save()
"""

task_type = 'FUNC'
activation_class = HandlerActivation

def __init__(self, handler, **kwargs):
def __init__(self, handler, **kwargs): # noqa D102
self.handler = handler
super(Handler, self).__init__(**kwargs)

def ready(self):
"""Resolve internal `this`-referencies."""
if isinstance(self.handler, ThisObject):
self.handler = getattr(self.flow_class.instance, self.handler.name)
26 changes: 24 additions & 2 deletions viewflow/nodes/ifgate.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@


class IfActivation(AbstractGateActivation):
def __init__(self, **kwargs):
"""Condifinally activate one of outgoing nodes."""

def __init__(self, **kwargs): # noqa D102
self.condition_result = None
super(IfActivation, self).__init__(**kwargs)

def calculate_next(self):
"""Calculate node to activate."""
self.condition_result = self.flow_task.condition(self)

@Activation.status.super()
def activate_next(self):
"""Condifinally activate one of outgoing nodes."""
if self.condition_result:
self.flow_task._on_true.activate(prev_activation=self, token=self.task.token)
else:
Expand All @@ -26,11 +30,27 @@ class If(mixins.TaskDescriptionMixin,
mixins.CancelViewMixin,
mixins.PerformViewMixin,
Gateway):
"""If gateway, activate one of outgoing node.
Example::
class MyFlow(Flow):
check_approve = (
flow.If(lambda activation: activation.process.is_approved)
.Then(this.send_message)
.Else(this.end_rejected)
)
"""

task_type = 'IF'
activation_class = IfActivation

def __init__(self, cond, **kwargs):
"""
Instantiate If gate node.
:param cond: Callable[activation] -> bool
"""
super(If, self).__init__(**kwargs)
self._condition = cond
self._on_true = None
Expand All @@ -45,15 +65,17 @@ def _resolve(self, resolver):
self._on_false = resolver.get_implementation(self._on_false)

def Then(self, node):
"""Node activated if condition is True."""
result = copy(self)
result._on_true = node
return result

def Else(self, node):
"""Node activated if condition is False."""
result = copy(self)
result._on_false = node
return result

@property
def condition(self):
def condition(self): # noqa D012
return self._condition
63 changes: 63 additions & 0 deletions viewflow/nodes/signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,50 @@ class StartSignal(mixins.TaskDescriptionMixin,
mixins.UndoViewMixin,
mixins.CancelViewMixin,
Event):
"""
Start flow on a django signal receive.
Example::
class MyFlow(Flow):
start = (
flow.StartSignal(
post_save, this.start_flow,
sender=MyModelCls)
.Next(this.approve)
)
...
@flow_start_signal
def start_flow(self, activation, **signal_kwargs):
activation.prepare()
activation.done()
"""

task_type = 'START'
activation_class = StartActivation

def __init__(self, signal, receiver, sender=None, **kwargs):
"""
Instantiate a StartSignal task.
:param signal: A django signal to connect
:param receiver: Callable[activation, **kwargs]
:param sender: Optional signal sender
"""
self.signal = signal
self.receiver = receiver
self.sender = sender

super(StartSignal, self).__init__(**kwargs)

def on_signal(self, sender, **signal_kwargs):
"""Signal handler."""
return self.receiver(sender=sender, flow_task=self, **signal_kwargs)

def ready(self):
"""Resolve internal `this`-referencies. and subscribe to the signal."""
if isinstance(self.receiver, ThisObject):
self.receiver = getattr(self.flow_class.instance, self.receiver.name)

Expand All @@ -39,11 +68,43 @@ class Signal(mixins.TaskDescriptionMixin,
mixins.UndoViewMixin,
mixins.CancelViewMixin,
Event):
"""
Execute a callback on a django signal receive.
Example::
class MyFlow(Flow):
wait_for_receipt = (
flow.Signal(
post_create, this.receipt_created,
sender=MyModelCls)
.Next(this.approve)
...
def receipt_created(self, activation, **signal_kwargs):
activation.prepare()
activation.process.receipt = signal_kwargs['instance']
activation.done()
"""

task_type = 'FUNC'
activation_class = FuncActivation

def __init__(self, signal, receiver, sender=None, task_loader=None, allow_skip=False, **kwargs):
"""
Instantiate a Signal task.
:param signal: A django signal to connect
:param receiver: Callable[activation, **kwargs]
:param sender: Optional signal sender
:param task_loader: Callable[**kwargs] -> Task
:param allow_skip: If True task_loader can return None if
signal could be skipped.
You can skip a `task_loader` if the signal going to be
sent with Task instance.
"""
self.signal = signal
self.receiver = receiver
self.sender = sender
Expand All @@ -52,6 +113,7 @@ def __init__(self, signal, receiver, sender=None, task_loader=None, allow_skip=F
super(Signal, self).__init__(**kwargs)

def on_signal(self, sender, **signal_kwargs):
"""Signal handler."""
if self.task_loader is None:
if 'task' not in signal_kwargs:
raise FlowRuntimeError('{} have no task_loader and got signal without task instance', self.name)
Expand All @@ -66,6 +128,7 @@ def on_signal(self, sender, **signal_kwargs):
return self.receiver(sender=sender, task=task, **signal_kwargs)

def ready(self):
"""Resolve internal `this`-referencies. and subscribe to the signal."""
if isinstance(self.receiver, ThisObject):
self.receiver = getattr(self.flow_class.instance, self.receiver.name)
if isinstance(self.task_loader, ThisObject):
Expand Down

0 comments on commit 0f01143

Please sign in to comment.