def test_find_free_slots(self):
        shift = Interval(9, 14)
        appointments = [Interval(9, 10), Interval(10, 11), Interval(13, 14)]

        slots = slots_in_interval(1, shift)
        free = [s for s in slots if not interval_overlaps(s, appointments)]

        self.assertEqual(free, [Interval(11, 12), Interval(12, 13)])
 def add_appointment(self, start, end):
     appo = Appointment(None, start, end)
     length = appo.interval.end - appo.interval.start
     for _, shift in self._agenda.iteritems():
         if appo.interval not in shift.interval:
             continue
         if appo.interval not in slots_in_interval(
                             length, shift.interval, self.minimum_length):
             continue
         appos_in_shift = [a.interval for (_, a) in shift.iteritems()]
         if not interval_overlaps(appo.interval, appos_in_shift):
             appo.parent_key = shift.key
             try:
                 appo = ds().put(appo)
             except (OverlappingIntervalWarning, ConcurrencyWarning):
                 appo.parent_key = None
                 continue
             return appo
     raise NotAvailableSlotError