def test_union_of_overlapping(): first = IntervalSet((i.open(1, 5), i.closed(7, 10))) second = IntervalSet((i.open(8, 21), i.closed(22, 23))) expected = IntervalSet((i.open(1, 5), i.closedopen(7, 21), i.closed(22, 23))) result = first.union(second) assert result == expected
def test_union_of_disjoint(): first = IntervalSet((i.open(1, 5), i.closed(7, 10))) second = IntervalSet((i.open(12, 21), i.closed(22, 23))) expected = IntervalSet( (i.open(1, 5), i.closed(7, 10), i.open(12, 21), i.closed(22, 23))) result = first.union(second) assert result == expected
def test_subtract_overlapping(): left = IntervalSet((i.open(1, 4), i.open(5, 10))) right = IntervalSet((i.open(0, 2), i.open(6, 8))) expected = IntervalSet(( i.closedopen(2, 4), i.openclosed(5, 6), i.closedopen(8, 10), )) assert left - right == expected
def test_complement(): one = i.open(3, 6) two = i.open(7, 10) intervals = IntervalSet([one, two]) complement = intervals.complement() (lower, middle, upper) = sorted(complement) # an IntervalSet is not sorted assert lower == i.openclosed(i.NEGATIVE_INFINITY, 3) assert middle == i.closed(6, 7) assert upper == i.closedopen(10, i.INFINITY)
def as_interval_set(self, start: date, finish: date) -> IntervalSet: """ Return an interval set representation of the TimePattern between two bounds. The intervals are closed and expressed using Unix timestamps (the number of seconds since 1970-01-01 UTC, not counting leap seconds). Since TimePattern defines an infinite sequence of intervals across all time, this function takes a starting date and ending date. Only those intervals with start times that fall between the starting and ending date are returned in the interval set result. """ dow_dict = { "Mo": 0, "Tu": 1, "We": 2, "Th": 3, "Fr": 4, "Sa": 5, "Su": 6 } # REVIEW: Is there a more efficient implementation that uses dateutil.rrule? tz = timezone.get_current_timezone() iset = IntervalSet([]) # type: IntervalSet d = start - timedelta(days=1) # type: date while d <= finish: d = d + timedelta(days=1) if dow_dict[self.dow] != d.weekday(): continue if self.wom == self.WOM_LAST: if not is_last_xxxday_of_month(d): continue if self.wom not in [self.WOM_LAST, self.WOM_EVERY]: nth = int(self.wom) if not is_nth_xxxday_of_month(d, nth): continue am_pm_adjust = 0 if self.morning else 12 inter_start_dt = tz.localize( datetime(d.year, d.month, d.day, self.hour + am_pm_adjust, self.minute)) inter_start = dt2ts(inter_start_dt) inter_end = int(inter_start + self.duration * 3600) iset.add(closed(inter_start, inter_end)) return iset
def test_intersection_is_symmetric( ): # check expected result and symmetric property expected = IntervalSet((i.open(5, 6), )) first = IntervalSet((i.open(1, 2), i.open(4, 6))) second = IntervalSet((i.open(5, 7), i.open(12, 13))) assert first.intersection(second) == expected assert second.intersection(first) == expected
def test_values_in(): one = i.open(1, 5) two = i.closed(7, 10) ivset = IntervalSet((i.open(1, 5), i.closed(7, 10))) assert 1 not in ivset assert 1.00000001 in ivset assert 3 in ivset assert 7 in ivset assert 8 in ivset assert 10.0001 not in ivset assert one in ivset assert two in ivset
def get_availability(self: ConcreteEntity, range_begin: date, range_end: date) -> IntervalSet: available = IntervalSet([]) unavailable = IntervalSet([]) # Determine availability and unavailability according to entity's settings: for pos_tp in self.timepattern_set.filter( disposition=TimePattern.DISPOSITION_AVAILABLE).all(): available += pos_tp.as_interval_set(range_begin, range_end) if available.empty(): # If no positive timepatterns have been specified then we'll say that the pos part is infinite. # This makes it easy to specify things like "always available" and "always available except Fridays." # For the purpose of this method, "infite" translates to range_begin to range_end. make_ts = lambda d: dt2ts( pytz.utc.localize(datetime(d.year, d.month, d.day))) range_begin_ts = make_ts(range_begin) # type: TimeStamp range_end_ts = make_ts(range_end) # type: TimeStamp available.add(closed(range_begin_ts, range_end_ts)) for neg_tp in self.timepattern_set.filter( disposition=TimePattern.DISPOSITION_UNAVAILABLE).all(): unavailable += neg_tp.as_interval_set(range_begin, range_end) # Determine additional unavailability due to entity being involved in a scheduled class: for involvement in self.scheduled_class_involvements: # type: EntityInScheduledClass if involvement.entitys_status == EntityInScheduledClass.STATUS_G2G: pass # TODO return available - unavailable
def test_intersection_of_almost_overlapping(): first = IntervalSet((i.open(1, 5), i.closedopen(7, 10))) second = IntervalSet((i.open(1, 5), i.closed(7,23))) expected = IntervalSet((i.open(1, 5), i.closedopen(7, 10))) result = first.intersection(second) assert result == expected
def test_interval_set_with_empty_intervals_is_empty(): res = IntervalSet((i.open(1, 1), i.open(15, 15),)) assert res.empty()
def test_length_of_unioned(): first = IntervalSet((i.open(1, 5), i.closed(7, 10))) second = IntervalSet((i.open(8, 21), i.closed(22,23))) # This is of length 3 as 2 of the intervals overlap and therefore join together assert len(first.union(second)) == 3
def test_add_to_empty(): expected = IntervalSet((i.open(1, 7),)) result = IntervalSet() result.add(i.open(1, 7)) assert result == expected
def test_add_non_overlapping_unions(): expected = IntervalSet((i.open(1, 7), i.open(10, 20))) result = IntervalSet((i.open(1, 7),)) result.add(i.open(10, 20)) assert result == expected
def test_len_works_as_expected(): assert len(IntervalSet((i.open(1, 5), i.closed(7, 10)))) == 2
def test_union_non_overlapping(): one = i.open(3, 6) two = i.open(8, 10) expected = IntervalSet([one, two]) assert one.union(two) == expected assert two.union(one) == expected
def test_add_already_contained_has_no_effect(): expected = IntervalSet((i.open(1, 7), )) result = IntervalSet((i.open(1, 7), )) result.add(i.open(2, 4)) assert result == expected
def test_equality_empty_interval_sets(): one = IntervalSet() two = IntervalSet() assert one == two
def test_add_non_overlapping_unions(): expected = IntervalSet((i.open(1, 7), i.open(10, 20))) result = IntervalSet((i.open(1, 7), )) result.add(i.open(10, 20)) assert result == expected
def test_equality_of_two_equal_instances(): one = IntervalSet([i.open(1, 10)]) two = IntervalSet([i.open(1, 10)]) assert one == two
def test_add_overlapping_with_multiple(): expected = IntervalSet((i.open(1, 20), i.open(30, 40))) result = IntervalSet((i.open(1, 7), i.open(10, 20), i.open(30, 40))) result.add(i.open(2, 15)) assert result == expected
def test_add_to_empty(): expected = IntervalSet((i.open(1, 7), )) result = IntervalSet() result.add(i.open(1, 7)) assert result == expected
def test_union_on_empty_set_works(): expected = IntervalSet((i.open(1, 7), )) result = IntervalSet().union(IntervalSet((i.open(1, 7), ))) assert result == expected
def test_union_of_disjoint(): first = IntervalSet((i.open(1, 5), i.closed(7, 10))) second = IntervalSet((i.open(12, 21), i.closed(22,23))) expected = IntervalSet((i.open(1, 5), i.closed(7, 10), i.open(12, 21), i.closed(22, 23))) result = first.union(second) assert result == expected
def test_repr(): interval_set = IntervalSet([i.open(3, 6), i.open(7, 10)]) assert repr(interval_set) == 'IntervalSet((3, 6), (7, 10))'
def test_initialising_interval_with_overlapping_intervals_unions_them(): expected = IntervalSet((i.open(1, 10), )) result = IntervalSet([i.open(1, 7), i.closedopen(5, 10)]) assert result == expected
def test_comparison_raises_not_implemented_error_if_it_cannot_compare(): with pytest.raises(NotImplementedError): IntervalSet() == 1
def test_subtract_contained(): left = i.open(3, 6) right = i.open(4, 5) expected = IntervalSet([i.openclosed(3, 4), i.closedopen(5, 6)]) assert left - right == expected
def test_equality_of_not_equal(): one = IntervalSet([i.open(1, 10)]) two = IntervalSet([i.closed(1, 10)]) assert one != two
def test_intersection_is_symmetric(): # check expected result and symmetric property expected = IntervalSet((i.open(5, 6),)) first = IntervalSet((i.open(1, 2), i.open(4, 6))) second = IntervalSet((i.open(5, 7), i.open(12, 13))) assert first.intersection(second) == expected assert second.intersection(first) == expected
def test_initialising_with_generator_does_not_consume_generator_before_storing_items( ): generator = (el for el in (i.open(1, 5), i.closed(7, 10))) assert len(IntervalSet(generator)) == 2
def test_intersection_of_disjoint_is_empty(): first = IntervalSet((i.open(1, 5), i.closed(7, 10))) second = IntervalSet((i.open(20, 21), i.closed(22, 23))) expected = IntervalSet() result = first.intersection(second) assert result == expected
def test_add_already_contained_has_no_effect(): expected = IntervalSet((i.open(1, 7),)) result = IntervalSet((i.open(1, 7),)) result.add(i.open(2, 4)) assert result == expected
def test_creation(): one = i.open(3, 6) two = i.open(7, 10) expected_data = set([one, two]) result = IntervalSet([one, two]) assert result._data == expected_data
def test_length_of_empty_is_zero(): assert len(IntervalSet()) == 0
def test_intersection_of_almost_overlapping(): first = IntervalSet((i.open(1, 5), i.closedopen(7, 10))) second = IntervalSet((i.open(1, 5), i.closed(7, 23))) expected = IntervalSet((i.open(1, 5), i.closedopen(7, 10))) result = first.intersection(second) assert result == expected
def test_intersection_of_disjoint_is_empty(): first = IntervalSet((i.open(1, 5), i.closed(7, 10))) second = IntervalSet((i.open(20,21), i.closed(22,23))) expected = IntervalSet() result = first.intersection(second) assert result == expected
def test_intersection_of_equal(): first = IntervalSet((i.open(1, 5), i.closed(7, 10))) result = first.intersection(first) assert result == first
def test_union_of_overlapping(): first = IntervalSet((i.open(1, 5), i.closed(7, 10))) second = IntervalSet((i.open(8, 21), i.closed(22,23))) expected = IntervalSet((i.open(1, 5), i.closedopen(7, 21), i.closed(22, 23))) result = first.union(second) assert result == expected
def test_length_of_unioned(): first = IntervalSet((i.open(1, 5), i.closed(7, 10))) second = IntervalSet((i.open(8, 21), i.closed(22, 23))) # This is of length 3 as 2 of the intervals overlap and therefore join together assert len(first.union(second)) == 3
def test_union_of_equal(): first = IntervalSet((i.open(1, 5), i.closed(7, 10))) result = first.union(first) assert result == first
def test_unioning_empty_interval_set_with_non_empty_has_the_correct_len(): result = IntervalSet().union(IntervalSet((i.open(1, 2), i.open(3, 4)))) assert len(result) == 2