-
Notifications
You must be signed in to change notification settings - Fork 16
/
dispatchers.py
98 lines (72 loc) · 3.26 KB
/
dispatchers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
from __future__ import unicode_literals
from collections import defaultdict
from django.core.exceptions import ImproperlyConfigured
from chamber.utils.transaction import (
on_success, OnSuccessHandler, OneTimeOnSuccessHandler, InstanceOneTimeOnSuccessHandler
)
from .signals import dispatcher_post_save
class BaseDispatcher(object):
"""
Base dispatcher class that can be subclassed to call a handler based on a change in some a SmartModel.
If you subclass, be sure the __call__ method does not change signature.
"""
signal = None
def _validate_init_params(self):
if not callable(self.handler):
raise ImproperlyConfigured('Registered handler must be a callable.')
def __init__(self, handler, signal=None):
self.handler = handler
self._validate_init_params()
self._connected = defaultdict(list)
self._signal = signal if signal is not None else self.signal
def connect(self, sender):
self._signal.connect(self, sender=sender)
def __call__(self, instance, **kwargs):
"""
`instance` ... instance of the SmartModel where the handler is being called
Some dispatchers require additional params to evaluate the handler can be dispatched,
these are hidden in args and kwargs.
"""
if self._can_dispatch(instance, **kwargs):
self.handler(instance=instance, **kwargs)
def _can_dispatch(self, instance, *args, **kwargs):
raise NotImplementedError
class PropertyDispatcher(BaseDispatcher):
"""
Use this class to register a handler to dispatch during save if the given property evaluates to True.
"""
def _validate_init_params(self):
"""
No validation is done as it would require to pass the whole model to the dispatcher.
If the property is not defined, a clear error is shown at runtime.
"""
pass
def __init__(self, handler, property_name, signal=None):
self.property_name = property_name
super(PropertyDispatcher, self).__init__(handler, signal)
def _can_dispatch(self, instance, **kwargs):
return getattr(instance, self.property_name)
class CreatedDispatcher(BaseDispatcher):
"""
Calls registered handler if and only if an instance of the model is being created.
"""
def _can_dispatch(self, instance, change, **kwargs):
return not change
class StateDispatcher(BaseDispatcher):
"""
Use this class to register a handler for transition of a model to a certain state.
"""
def _validate_init_params(self):
super(StateDispatcher, self)._validate_init_params()
if self.field_value not in {value for value, _ in self.enum.choices}:
raise ImproperlyConfigured('Enum of FieldDispatcher does not contain {}.'.format(self.field_value))
def __init__(self, handler, enum, field, field_value, signal=None):
self.enum = enum
self.field = field
self.field_value = field_value
super(StateDispatcher, self).__init__(handler, signal=signal)
def _can_dispatch(self, instance, change, changed_fields, *args, **kwargs):
return (
self.field.get_attname() in changed_fields and
getattr(instance, self.field.get_attname()) == self.field_value
)