Skip to content

Commit

Permalink
Documents the events and simplifies context access when using events. C…
Browse files Browse the repository at this point in the history
…loses #4
  • Loading branch information
Denis Krienbühl committed Feb 2, 2015
1 parent d51131a commit b8f1585
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 37 deletions.
7 changes: 6 additions & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@ Database Access
.. autoclass:: libres.db.queries.Queries
:members:

Events
------

.. automodule:: libres.modules.events
:members:

Models
------

.. autoclass:: libres.db.models.Allocation
:members:


Settings
--------

Expand Down
4 changes: 3 additions & 1 deletion libres/db/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ def confirm_reservations_for_session(self, session_id, token=None):
for reservation in reservations:
reservation.session_id = None

events.on_reservations_confirmed(self.context.name, reservations)
events.on_reservations_confirmed(
self.context, reservations, session_id
)

@serialized
def remove_reservation_from_session(self, session_id, token):
Expand Down
12 changes: 6 additions & 6 deletions libres/db/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def allocate(

self.session.add_all(allocations)

events.on_allocations_added(self.context.name, allocations)
events.on_allocations_added(self.context, allocations)

return allocations

Expand Down Expand Up @@ -781,7 +781,7 @@ def new_reservations_by_dates(dates):
for reservation in reservations:
self.session.add(reservation)

events.on_reservations_made(self.context.name, reservations)
events.on_reservations_made(self.context, reservations)

return token

Expand Down Expand Up @@ -847,7 +847,7 @@ def approve_reservations(self, token):
self._approve_reservation_record(reservation)
)

events.on_reservations_approved(self.context.name, reservations)
events.on_reservations_approved(self.context, reservations)

return slots_to_reserve

Expand All @@ -865,7 +865,7 @@ def deny_reservation(self, token):

query.delete()

events.on_reservations_denied(self.context.name, reservations)
events.on_reservations_denied(self.context, reservations)

@serialized
def remove_reservation(self, token, id=None):
Expand All @@ -890,7 +890,7 @@ def remove_reservation(self, token, id=None):
reservations = self.reservations_by_token(token, id)
reservations.delete('fetch')

events.on_reservations_removed(self.context.name, reservations)
events.on_reservations_removed(self.context, reservations)

@serialized
def change_email(self, token, new_email):
Expand Down Expand Up @@ -1005,7 +1005,7 @@ def change_reservation_time(self, token, id, new_start, new_end):
self._approve_reservation_record(new_reservation)

events.on_reservation_time_changed(
self.context.name,
self.context,
new_reservation,
old_time=(old_start, old_end),
new_time=(
Expand Down
138 changes: 117 additions & 21 deletions libres/modules/events.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,135 @@
""" Events are called by the :class:`libres.db.scheduler.Scheduler` whenever
something interesting occurs.
The implementation is very simple:
To add an event::
from libres.modules import events
def on_allocations_added(context_name, allocations):
pass
events.on_allocations_added.append(on_allocations_added)
To remove the same event::
events.on_allocations_added.remove(on_allocations_added)
Events are called in the order they were added.
"""


class Event(list):
"""Event subscription. By http://stackoverflow.com/a/2022629
A list of callable objects. Calling an instance of this will cause a
call to each item in the list in ascending order by index.
Example Usage:
>>> def f(x):
... print 'f(%s)' % x
>>> def g(x):
... print 'g(%s)' % x
>>> e = Event()
>>> e()
>>> e.append(f)
>>> e(123)
f(123)
>>> e.remove(f)
>>> e()
>>> e += (f, g)
>>> e(10)
f(10)
g(10)
>>> del e[0]
>>> e(2)
g(2)
"""
def __call__(self, *args, **kwargs):
for f in self:
f(*args, **kwargs)


on_allocations_added = Event()
""" Called when an allocation is added, with the following arguments:
:context:
The :class:`libres.context.context.Context` used when adding the
allocations.
:allocations:
The list of :class:`libres.db.models.Allocation` allocations to be
commited.
"""

on_reservations_made = Event()
""" Called when a reservation is made, with the following arguments:
:context:
The :class:`libres.context.context.Context` used when adding the
reservation.
:reservations:
The list of :class:`libres.db.models.Reservation` reservations to be
commited. This is a list because one reservation can result in
multiple reservation records. All those records will have the
same reservation token and the same reservee email address.
"""

on_reservations_confirmed = Event()
""" Called when a reservation bound to a browser session is confirmed, with
the following arguments:
:context:
The :class:`libres.context.context.Context` used when confirming the
reservation.
:reservations:
The list of :class:`libres.db.models.Reservation` reservations being
confirmed.
:session_id:
The session id that is being confirmed.
"""

on_reservations_approved = Event()
on_reservations_removed = Event()
""" Called when a reservation is approved, with the following arguments:
:context:
The :class:`libres.context.context.Context` used when approving the
reservation.
:reservations:
The list of :class:`libres.db.models.Reservation` reservations being
approved.
"""

on_reservations_denied = Event()
""" Called when a reservation is denied, with the following arguments:
:context:
The :class:`libres.context.context.Context` used when denying the
reservation.
:reservations:
The list of :class:`libres.db.models.Reservation` reservations being
denied.
"""

on_reservations_removed = Event()
""" Called when a reservation is removed, with the following arguments:
:context:
The :class:`libres.context.context.Context` used when removing the
reservation.
:reservations:
The list of :class:`libres.db.models.Reservation` reservations being
removed.
"""

on_reservation_time_changed = Event()
""" Called when a reservation's time changes , with the following arguments:
:context:
The :class:`libres.context.context.Context` used when changing the
reservation time.
:reservation:
The :class:`libres.db.models.Reservation` reservation whose time is
changing.
:old_time:
A tuple of datetimes containing the old start and the old end.
:new_time:
A tuple of datetimes containing the new start and the new end.
"""
16 changes: 8 additions & 8 deletions libres/tests/test_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ def test_change_reservation(scheduler):
scheduler.commit()

assert reservation_changed.called
assert reservation_changed.call_args[0][0] == scheduler.context.name
assert reservation_changed.call_args[0][0].name == scheduler.context.name
assert reservation_changed.call_args[1]['old_time'][0].hour == 8
assert reservation_changed.call_args[1]['old_time'][1].hour == 9
assert reservation_changed.call_args[1]['new_time'][0].hour == 8
Expand Down Expand Up @@ -1373,15 +1373,15 @@ def test_events(scheduler):

scheduler.allocate(dates, approve_manually=True)
assert allocations_added.called
assert allocations_added.call_args[0][0] == scheduler.context.name
assert allocations_added.call_args[0][0].name == scheduler.context.name
assert len(allocations_added.call_args[0][1]) == 1

# create reservations

token = scheduler.reserve(u'test@example.org', dates)
assert reservations_made.called
assert reservations_made.call_args[0][0] == scheduler.context.name
assert reservations_made.call_args[0][0] == scheduler.context.name
assert reservations_made.call_args[0][0].name == scheduler.context.name
assert reservations_made.call_args[0][0].name == scheduler.context.name
assert reservations_made.call_args[0][1][0].token == token

reservations_made.reset_mock()
Expand All @@ -1392,7 +1392,7 @@ def test_events(scheduler):
assert reservations_approved.called
assert not reservations_denied.called
assert not reservations_made.called
assert reservations_approved.call_args[0][0] == scheduler.context.name
assert reservations_approved.call_args[0][0].name == scheduler.context.name
assert reservations_approved.call_args[0][1][0].token == token

reservations_approved.reset_mock()
Expand All @@ -1401,16 +1401,16 @@ def test_events(scheduler):
# remove the reservation and deny the next one
scheduler.remove_reservation(token)
assert reservations_removed.called
assert reservations_removed.call_args[0][0] == scheduler.context.name
assert reservations_removed.call_args[0][0].name == scheduler.context.name

token = scheduler.reserve(u'test@example.org', dates)
assert reservations_made.called
assert reservations_made.call_args[0][0] == scheduler.context.name
assert reservations_made.call_args[0][0].name == scheduler.context.name

scheduler.deny_reservation(token)

assert not reservations_approved.called
assert reservations_denied.call_args[0][0] == scheduler.context.name
assert reservations_denied.call_args[0][0].name == scheduler.context.name
assert reservations_denied.called
assert reservations_denied.call_args[0][1][0].token == token

Expand Down

0 comments on commit b8f1585

Please sign in to comment.