Organize event_listeners by purpose

This commit is contained in:
Klaas van Schelven
2024-01-09 22:22:06 +01:00
parent b1738fff13
commit 2202fd8d5d
3 changed files with 32 additions and 15 deletions

View File

@@ -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 {

View File

@@ -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

View File

@@ -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):