Skip to content

Commit

Permalink
Support inheritance override for handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
kmmbvnr committed Jan 7, 2021
1 parent 8a2362e commit f9c576c
Show file tree
Hide file tree
Showing 15 changed files with 72 additions and 46 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
Changelog
=========

1.8.0 2021-01-07
----------------

* Clean Django 4.0 warnings
* Allow flow.Handler redifinition with inheritance


1.7.0 2020-11-18
----------------

Expand Down
8 changes: 5 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ http://viewflow.io.
- Viewflow 1.1.x compatible with Django 1.8/1.9/1.10/1.11 (supported till Django 1.8 lifetime/April 2018)
- Viewflow 1.2.x compatible with Django 1.11/2.0 (supported till Django 1.11 lifetime/April 2020)
- Viewflow 1.3.x/1.4.x/1.5.x compatible with Django 1.11/2.0/2.1/2.2 (supported till Django 1.11 lifetime/April 2020)
- Viewflow 1.6.x compatible with Django 2.0/2.1/2.2/3.0/3.1
- Viewflow 1.6.x/1.7.x compatible with Django 2.0/2.1/2.2/3.0/3.1 (supported till Django 2.0 lifetime/December 2020)
- Viewflow 1.8.x compatible with Django 2.1/2.2/3.0/3.1

Introduction
============
Expand Down Expand Up @@ -124,7 +125,8 @@ Please see `FAQ <https://github.com/kmmbvnr/django-viewflow/wiki/Pro-FAQ>`_ for
Latest changelog
================

1.7.0 2020-11-18
1.8.0 2021-01-07
----------------

* Fix TaskQuerySet.user_queue filtering. Remove django 1.8 compatibility code
* Clean Django 4.0 warnings
* Allow flow.Handler redifinition with inheritance
4 changes: 2 additions & 2 deletions tests/test_flow_signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ def test_signal_ignore_activation(self):

start_test_signal = Signal()
start_ignorable_test_signal = Signal()
task_test_signal = Signal(providing_args=["process", "task"])
ignorable_test_signal = Signal(providing_args=["process", "ignore_me"])
task_test_signal = Signal()
ignorable_test_signal = Signal()


@flow.flow_start_signal
Expand Down
4 changes: 2 additions & 2 deletions tests/test_templatetags_base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import django

from django.db import models
from django.conf.urls import include, url
from django.urls import include, re_path
from django.contrib import admin
from django.contrib.auth.models import User
from django.test import TestCase
Expand Down Expand Up @@ -109,7 +109,7 @@ class TemplateTagProcessEntity(models.Model):


urlpatterns = [
url(r'^admin/', admin.site.urls)
re_path(r'^admin/', admin.site.urls)
]

try:
Expand Down
4 changes: 2 additions & 2 deletions tests/test_templatetags_viewflow.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.conf.urls import include, url
from django.urls import include, re_path
from django.contrib.auth.models import User
from django.http.request import QueryDict
from django.template import Template, Context
Expand Down Expand Up @@ -85,5 +85,5 @@ class TestTemplateTagsFlow(Flow):


urlpatterns = [
url(r'^test/', include((viewset.FlowViewSet(TestTemplateTagsFlow).urls, 'testtemplatetags'))),
re_path(r'^test/', include((viewset.FlowViewSet(TestTemplateTagsFlow).urls, 'testtemplatetags'))),
]
17 changes: 12 additions & 5 deletions tests/test_usecase_inheritance.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@

class BaseFlow(Flow):
start = flow.StartFunction().Next(this.end)
handle = flow.Handler(this.handler_execute)
end = flow.End()

def handler_execute(self, activation):
raise NotImplementedError


class FlowMixin(object):
notify_admins = flow.Handler(this.send_alert).Next(this.notify_users)
Expand All @@ -18,6 +22,9 @@ class ChildFlow(FlowMixin, BaseFlow):
alert = flow.Function(this.send_alert).Next(this.notify_admins)
notify_users = FlowMixin.notify_users.Next(this.end)

def handler_execute(self, activation):
raise NotImplementedError

def send_alert(self, activation):
activation.prepare()
activation.done()
Expand All @@ -27,10 +34,6 @@ class Test(TestCase):
def test_base_flow_unchanged(self):
self.assertEqual(BaseFlow.start._next, BaseFlow.end)

def test_child_flow_got_base_nodes(self):
self.assertEqual(ChildFlow.end, BaseFlow.end)
self.assertEqual(ChildFlow._meta.node('end'), BaseFlow.end)

def test_child_flow_overides_base_node(self):
self.assertEqual(ChildFlow.alert._next, ChildFlow.notify_admins)
self.assertEqual(ChildFlow.notify_users._next, ChildFlow.end)
Expand All @@ -43,4 +46,8 @@ def test_child_flow_contains_all_urls(self):
'notify_admins__perform', 'notify_admins__cancel', 'notify_admins__undo',
'notify_admins__detail', 'notify_users__perform', 'notify_users__cancel',
'notify_users__undo', 'notify_users__detail', 'start__perform',
'start__cancel', 'start__undo', 'start__detail']))
'start__cancel', 'start__undo', 'start__detail',
'handle__cancel', 'handle__undo', 'handle__detail', 'handle__perform']))

def test_handle_proper_initialized(self):
self.assertEqual(ChildFlow.handle.handler, ChildFlow.instance.handler_execute)
4 changes: 2 additions & 2 deletions tests/test_views_actions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.conf.urls import include, url
from django.urls import include, re_path
from django.contrib.auth.models import User
from django.test import TestCase, RequestFactory
from django.urls import resolve
Expand Down Expand Up @@ -251,7 +251,7 @@ class ActionsTestFlow(Flow):


urlpatterns = [
url(r'^test/', include((viewset.FlowViewSet(ActionsTestFlow).urls, 'actionstest')))
re_path(r'^test/', include((viewset.FlowViewSet(ActionsTestFlow).urls, 'actionstest')))
]

try:
Expand Down
4 changes: 2 additions & 2 deletions tests/test_views_base.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.conf.urls import include, url
from django.urls import include, re_path
from django.contrib.auth.models import User
from django.test import TestCase, RequestFactory
from django.urls import resolve
Expand Down Expand Up @@ -97,7 +97,7 @@ class BaseViewTestFlow(Flow):


urlpatterns = [
url(r'^test/', include((viewset.FlowViewSet(BaseViewTestFlow).urls, 'baseviewtest')))
re_path(r'^test/', include((viewset.FlowViewSet(BaseViewTestFlow).urls, 'baseviewtest')))
]

try:
Expand Down
4 changes: 2 additions & 2 deletions tests/test_views_list.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.conf.urls import include, url
from django.urls import include, re_path
from django.contrib.auth.models import User
from django.test import TestCase, RequestFactory
from django.urls import resolve
Expand Down Expand Up @@ -112,7 +112,7 @@ class ListViewTestFlow(Flow):


urlpatterns = [
url(r'^test/', include((viewset.FlowViewSet(ListViewTestFlow).urls, 'listviewtest')))
re_path(r'^test/', include((viewset.FlowViewSet(ListViewTestFlow).urls, 'listviewtest')))
]

try:
Expand Down
4 changes: 2 additions & 2 deletions tests/test_views_start.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.conf.urls import include, url
from django.conf.urls import include, re_path
from django.contrib.auth.models import User
from django.db import models
from django.test import TestCase, RequestFactory
Expand Down Expand Up @@ -77,7 +77,7 @@ class StartViewFlowEntity(models.Model):


urlpatterns = [
url(r'^test/', include((viewset.FlowViewSet(StartViewTestFlow).urls, 'startviewtest')))
re_path(r'^test/', include((viewset.FlowViewSet(StartViewTestFlow).urls, 'startviewtest')))
]

try:
Expand Down
4 changes: 2 additions & 2 deletions tests/test_views_task.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.urls import resolve
from django.conf.urls import include, url
from django.conf.urls import include, re_path
from django.db import models
from django.contrib.auth.models import User
from django.test import TestCase, RequestFactory
Expand Down Expand Up @@ -142,7 +142,7 @@ class TaskViewFlowEntity(models.Model):


urlpatterns = [
url(r'^test/', include((viewset.FlowViewSet(TaskViewTestFlow).urls, 'taskviewtest')))
re_path(r'^test/', include((viewset.FlowViewSet(TaskViewTestFlow).urls, 'taskviewtest')))
]

try:
Expand Down
6 changes: 2 additions & 4 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tox]
envlist =
py{36}-{dj20,dj21,dj22}
py{37}-{dj20,dj21,dj22,dj30,dj31}
py{36}-{dj22}
py{37}-{dj22,dj30,dj31}
py{38}-{dj30,dj31}
skipsdist = True

Expand Down Expand Up @@ -35,8 +35,6 @@ basepython =
py37: python3.7
py38: python3.8
deps =
dj20: Django==2.0.13
dj21: Django==2.1.15
dj22: Django==2.2.17
dj30: Django==3.0.11
dj31: Django==3.1.3
Expand Down
24 changes: 15 additions & 9 deletions viewflow/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from __future__ import unicode_literals

import re
from copy import copy
from collections import defaultdict
from textwrap import dedent
from six import with_metaclass
Expand All @@ -23,7 +24,7 @@ def __init__(self, nodes): # noqa

def get_implementation(self, link):
if isinstance(link, Node):
return link
return self.nodes.get(link.name)
elif isinstance(link, ThisObject):
node = self.nodes.get(link.name)
if not node:
Expand Down Expand Up @@ -102,19 +103,24 @@ class FlowMetaClass(type):

def __new__(cls, class_name, bases, attrs):
"""Construct new flow class."""
new_class = super(FlowMetaClass, cls).__new__(cls, class_name, bases, attrs)

# singleton instance
new_class.instance = FlowInstanceDescriptor()

# set up flow tasks
nodes = {}

for base_class in bases:
for name, attr in base_class.__dict__.items():
if isinstance(attr, Node):
nodes[name] = attr
nodes.update({name: attr for name, attr in attrs.items()
if isinstance(attr, Node)})
nodes[name] = copy(attr)

for name, attr in attrs.items():
if isinstance(attr, Node):
nodes[name] = copy(attr)

attrs.update(nodes)

new_class = super(FlowMetaClass, cls).__new__(cls, class_name, bases, attrs)

# singleton instance
new_class.instance = FlowInstanceDescriptor()

for name, node in nodes.items():
node.name = name
Expand Down
16 changes: 10 additions & 6 deletions viewflow/nodes/func.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,20 @@ class MyFlow(Flow):
MyFlow.shipment_received_handler.run(task=task)
"""
self.func = func
self.task_loader = task_loader
self._func = func
self._task_loader = task_loader
super(Function, self).__init__(**kwargs)

def ready(self):
"""Resolve internal `this`-references."""
if isinstance(self.func, ThisObject):
self.func = getattr(self.flow_class.instance, self.func.name)
if isinstance(self.task_loader, ThisObject):
self.task_loader = getattr(self.flow_class.instance, self.task_loader.name)
if isinstance(self._func, ThisObject):
self.func = getattr(self.flow_class.instance, self._func.name)
else:
self.func = self._func
if isinstance(self._task_loader, ThisObject):
self._task_loader = getattr(self.flow_class.instance, self._task_loader.name)
else:
self.task_loader = self._task_loader

def run(self, *args, **kwargs):
"""Execute the function task."""
Expand Down
8 changes: 5 additions & 3 deletions viewflow/nodes/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,12 @@ def calc_order_total(self, activation):
activation_class = HandlerActivation

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

def ready(self):
"""Resolve internal `this`-references."""
if isinstance(self.handler, ThisObject):
self.handler = getattr(self.flow_class.instance, self.handler.name)
if isinstance(self._handler, ThisObject):
self.handler = getattr(self.flow_class.instance, self._handler.name)
else:
self.handler = self._handler

0 comments on commit f9c576c

Please sign in to comment.