mirror of
https://github.com/bugsink/bugsink.git
synced 2026-02-12 00:38:56 -06:00
Organize event_listeners by purpose
This commit is contained in:
@@ -98,28 +98,22 @@ class PeriodCounter(object):
|
||||
is_new_period = _inc(self.counts[tl], tup[:tl], n, mx)
|
||||
|
||||
event_listeners_for_tl = self.event_listeners[tl]
|
||||
for ((nr_of_periods, gte_threshold), (wbt, wbf, ar, is_true)) in list(event_listeners_for_tl.items()):
|
||||
for ((nr_of_periods, gte_threshold), (wbt, wbf, purp, is_true)) in list(event_listeners_for_tl.items()):
|
||||
if is_true:
|
||||
if not is_new_period:
|
||||
continue # no new period means: never becomes false, because no old period becomes irrelevant
|
||||
|
||||
if not self._get_event_state(tup[:tl], tl, nr_of_periods, gte_threshold):
|
||||
if ar:
|
||||
del event_listeners_for_tl[(nr_of_periods, gte_threshold)]
|
||||
else:
|
||||
event_listeners_for_tl[(nr_of_periods, gte_threshold)] = (wbt, wbf, ar, False)
|
||||
event_listeners_for_tl[(nr_of_periods, gte_threshold)] = (wbt, wbf, purp, False)
|
||||
wbf()
|
||||
|
||||
else:
|
||||
if self._get_event_state(tup[:tl], tl, nr_of_periods, gte_threshold):
|
||||
if ar:
|
||||
del event_listeners_for_tl[(nr_of_periods, gte_threshold)]
|
||||
else:
|
||||
event_listeners_for_tl[(nr_of_periods, gte_threshold)] = (wbt, wbf, ar, True)
|
||||
event_listeners_for_tl[(nr_of_periods, gte_threshold)] = (wbt, wbf, purp, True)
|
||||
wbt()
|
||||
|
||||
def add_event_listener(self, period_name, nr_of_periods, gte_threshold, when_becomes_true=noop,
|
||||
when_becomes_false=noop, auto_remove=False, initial_event_state=None, tup=None):
|
||||
when_becomes_false=noop, purpose=None, initial_event_state=None, tup=None):
|
||||
# note: the 'events' here are not bugsink-events; but the more general concept of 'an event'; we may consider a
|
||||
# different name for this in the future because of that.
|
||||
|
||||
@@ -134,7 +128,18 @@ class PeriodCounter(object):
|
||||
initial_event_state = self._get_event_state(tup[:tl], tl, nr_of_periods, gte_threshold)
|
||||
|
||||
self.event_listeners[tl][(nr_of_periods, gte_threshold)] = \
|
||||
(when_becomes_true, when_becomes_false, auto_remove, initial_event_state)
|
||||
(when_becomes_true, when_becomes_false, purpose, initial_event_state)
|
||||
|
||||
def remove_event_listener(self, purpose):
|
||||
"""
|
||||
Remove all event listeners with the given purpose. The purpose is a string that can be used to identify the
|
||||
event listener. (The idea is: callbacks are organized by purpose, and when you want to remove a callback, you
|
||||
can do so by specifying the purpose.)
|
||||
"""
|
||||
for tl, mx in enumerate([MAX_TOTALS, MAX_YEARS, MAX_MONTHS, MAX_DAYS, MAX_HOURS, MAX_MINUTES]):
|
||||
for k, (wbt, wbf, this_purp, state) in list(self.event_listeners[tl].items()):
|
||||
if this_purp == purpose:
|
||||
del self.event_listeners[tl][k]
|
||||
|
||||
def _tl_for_period(self, period_name):
|
||||
return {
|
||||
|
||||
@@ -11,6 +11,7 @@ from issues.models import Issue
|
||||
|
||||
|
||||
_registry = None
|
||||
UNMUTE_PURPOSE = "unmute"
|
||||
|
||||
|
||||
def create_unmute_issue_handler(issue_id):
|
||||
@@ -74,7 +75,7 @@ class PeriodCounterRegistry(object):
|
||||
gte_threshold=vbc.volume,
|
||||
when_becomes_true=create_unmute_issue_handler(issue.id),
|
||||
tup=now.timetuple(),
|
||||
auto_remove=True, # unmuting is needed only once; hence auto_remove to avoid recurring unmute calls
|
||||
purpose=UNMUTE_PURPOSE,
|
||||
)
|
||||
|
||||
return by_project, by_issue
|
||||
|
||||
@@ -8,7 +8,7 @@ from issues.models import Issue
|
||||
from events.models import Event
|
||||
from events.factories import create_event
|
||||
|
||||
from .period_counter import PeriodCounter, _prev_tup, TL_DAY, TL_YEAR
|
||||
from .period_counter import PeriodCounter, _prev_tup, TL_DAY, TL_MONTH, TL_YEAR
|
||||
from .volume_based_condition import VolumeBasedCondition
|
||||
from .registry import PeriodCounterRegistry
|
||||
|
||||
@@ -126,13 +126,23 @@ class PeriodCounterTestCase(TestCase):
|
||||
self.assertEquals(2, wbt.calls)
|
||||
self.assertEquals(1, wbf.calls) # unchanged
|
||||
|
||||
def test_event_listeners_auto_remove(self):
|
||||
def test_event_listeners_purpose(self):
|
||||
tp_2020 = datetime(2020, 1, 1, 10, 15, tzinfo=timezone.utc)
|
||||
|
||||
pc = PeriodCounter()
|
||||
wbt = callback()
|
||||
|
||||
class destructive_callback(object):
|
||||
def __init__(self):
|
||||
self.calls = 0
|
||||
|
||||
def __call__(self):
|
||||
pc.remove_event_listener("foo")
|
||||
self.calls += 1
|
||||
|
||||
wbf = callback()
|
||||
pc.add_event_listener("year", 1, 1, wbt, wbf, auto_remove=True, initial_event_state=False)
|
||||
pc.add_event_listener("year", 1, 1, wbt, wbf, purpose="foo", initial_event_state=False)
|
||||
pc.add_event_listener("month", 1, 1, destructive_callback(), wbf, purpose="foo", initial_event_state=False)
|
||||
|
||||
self.assertEquals(0, wbt.calls)
|
||||
pc.inc(tp_2020)
|
||||
@@ -140,6 +150,7 @@ class PeriodCounterTestCase(TestCase):
|
||||
self.assertEquals(1, wbt.calls)
|
||||
|
||||
self.assertEquals({}, pc.event_listeners[TL_YEAR])
|
||||
self.assertEquals({}, pc.event_listeners[TL_MONTH])
|
||||
|
||||
|
||||
class VolumeBasedConditionTestCase(TestCase):
|
||||
|
||||
Reference in New Issue
Block a user