def test_forward_non_recurrent_random(unit, overlap, trim):
    """`forward()` method of non-recurrent time intervals with and without
    overlapping `start` date."""
    correction = BASE[unit]

    max_ = add_delta(MAX, -1 * N, unit)

    unit_maximum = delta(MIN, max_, unit)

    interval = sorted(randuniq(2, correction, unit_maximum))

    if overlap:
        start = add_delta(
            MIN,
            rnd.randrange(int(interval[0]), int(interval[1])) - correction,
            unit
        )
    else:
        start = add_delta(MIN, int(interval[0]) - correction, unit)

    if trim:
        expected_start = start
    else:
        expected_start = add_delta(MIN, int(interval[0]) - correction, unit)

    stop = add_delta(MIN, int(interval[1]) - correction, unit)

    expected = [(expected_start, stop)]

    recurrentevent = RecurrentEvent(interval[0], interval[1], unit, None)
    actual = list(islice(recurrentevent.forward(start, trim), None, N))

    assert actual == expected
def test_forward_non_recurrent_random(unit, overlap):
    """`forward()` method of non-recurrent time intervals with and without
    overlapping `start` date."""
    correction = BASE[unit]

    max_ = add_delta(MAX, -1 * N, unit)

    unit_maximum = delta(MIN, max_, unit)

    interval = Interval(*sorted(randuniq(2, correction, unit_maximum)))

    if overlap:
        start = add_delta(
            MIN,
            rnd.randrange(
                int(interval.start), int(interval.stop)
            ) - correction,
            unit
        )
    else:
        start = add_delta(MIN,
                          int(interval.start) - correction,
                          unit)

    stop = add_delta(MIN, int(interval.stop) - correction + 1, unit)
    expected = [Interval(start, stop)]

    timeinterval = TimeInterval(interval, unit, None)
    actual = list(islice(timeinterval.forward(start), None, N))

    assert actual == expected
def test_interval_containment(unit, recurrence, sample, inclusion, expected):
    """Cases for containment test of an dates intervals."""
    correction = BASE[unit]

    lower, upper = unit_span(unit, recurrence, sample
                                               if recurrence is not None
                                               else None)
    if inclusion == 'included':
        test = lambda outer_start, outer_stop, inner_start, inner_stop: (
            lower <=
            outer_start <= inner_start <= inner_stop < outer_stop <
            upper
        )
    elif inclusion == 'not_included':
        test = lambda outer_start, outer_stop, inner_start, inner_stop: (
            lower <=
            inner_start < outer_start <= outer_stop < inner_stop <
            upper
        )
    else:
        raise NotImplementedError

    outer_start, outer_stop, inner_start, inner_stop = guess(lower, upper,
                                                             4, test)

    timeinterval = TimeInterval(Interval(outer_start, outer_stop),
                                unit, recurrence)
    if recurrence is not None:
        first = add_delta(sample, inner_start - correction, unit)
        second = add_delta(sample, inner_stop - correction, unit)
    else:
        first = add_delta(MIN, inner_start - correction, unit)
        second = add_delta(MIN, inner_stop - correction, unit)

    assert ((first, second) in timeinterval) == expected
def test_add_delta_raises_overflow_exception(unit):
    """'add_delta' raises `OverflowError` in case if resulting
    datetime is greater than `tempo.unit.MAX` or
    lesser than `tempo.unit.MIN`"""
    with pytest.raises(OverflowError):
        add_delta(MAX, 1, unit)

    with pytest.raises(OverflowError):
        add_delta(MIN, -1, unit)
Exemple #5
0
def unit_span(unit, recurrence=None, sample=None):
    """How much 'unit''s in 'recurrence'."""
    lower = BASE[unit]

    assert ((recurrence is None and sample is None) or
            (recurrence is not None and sample is not None))

    if recurrence is not None:
        upper = delta(sample, add_delta(sample, 1, recurrence),
                                        unit)
    else:
        upper = delta(MIN, add_delta(MAX, -1, unit), unit)

    assert lower != upper and lower < upper

    return lower, upper
Exemple #6
0
def sample(unit):
    """Random time between between bounds of possible time.

    Returned time is not included in the last segment of
    interval measured in 'unit'.
    """
    return floor(random_datetime_between(MIN, add_delta(MAX, -1, unit)), unit)
def test_forward_recurrent_random(unit, recurrence, overlap, trim):
    """`forward()` method of recurrent time intervals with and without
    overlapping `start` date."""
    correction = BASE[unit]

    max_ = add_delta(MAX, -1 * N, recurrence)

    unit_maximum = delta(MIN, add_delta(MIN, 1, recurrence), unit)

    from_, to = sorted(randuniq(2, correction, unit_maximum))

    expected = []

    initial = start = floor(
        add_delta(MIN, rnd.randrange(delta(MIN, max_, unit)), unit),
        recurrence

    )

    if overlap:
        initial = start = add_delta(
            initial,
            rnd.randrange(
                int(from_), int(to)
            ) - correction,
            unit
        )

    for i in range(N):
        recurrence_start = floor(start, recurrence)
        recurrence_stop = floor(add_delta(recurrence_start, 1, recurrence),
                                recurrence)
        first = floor(add_delta(recurrence_start,
                                from_ - correction,
                                unit), unit)
        second = floor(add_delta(recurrence_start, to - correction, unit),
                       unit)
        first = max(recurrence_start, min(first, recurrence_stop))
        second = min(recurrence_stop, second)
        assert first <= second
        assert start <= second
        if start > first and trim:
            first = start

        expected.append((first, second))
        start = floor(add_delta(recurrence_start, 1, recurrence), recurrence)

    recurrentevent = RecurrentEvent(from_, to, unit, recurrence)
    actual = list(islice(recurrentevent.forward(initial, trim), None, N))

    assert actual == expected
    def forward(self, start):
        """Iterate time intervals starting from 'start'.
        Intervals returned in form of `(start, end)` pair,
        where `start` is a datetime object representing the start
        of the interval and `end` is the non-inclusive end of the interval.

        Parameters
        ----------
        start : datetime.datetime
            A lower bound for the resulting sequence of intervals.

        Yields
        ------
        start : datetime.datetime
            Start of an interval.
        end : datetime.datetime
            End of an interval.
        """
        if self.recurrence is None:
            base = MIN
        else:
            base = floor(start, self.recurrence)

        correction = -1 * BASE[self.unit]

        def addfloor(base, delta):
            """Adds 'delta' to 'base' and than floors it
            by unit of this interval."""
            return floor(add_delta(base, delta, self.unit), self.unit)

        # Handle possible overlap in first interval
        try:
            first = addfloor(base, self.interval.start + correction)
            second = addfloor(base, self.interval.stop + correction + 1)
            if first < start < second:
                yield Interval(start, second)
            elif start <= first:
                yield Interval(first, second)
        except OverflowError:
            return

        if self.recurrence is None:
            return
        while True:  # Handle recurring intervals
            base = add_delta(base, 1, self.recurrence)
            try:
                first = addfloor(base, self.interval.start + correction)
                second = addfloor(base, self.interval.stop + correction + 1)
                if base > first:  # In case if flooring by week resulted
                    first = base  # as a time earlier than 'base'
                yield Interval(first, second)
            except OverflowError:
                return
def test_forward_recurrent_random(unit, recurrence, overlap):
    """`forward()` method of recurrent time intervals with and without
    overlapping `start` date."""
    correction = BASE[unit]

    max_ = add_delta(MAX, -1 * N, recurrence)

    unit_maximum = delta(MIN, add_delta(MIN, 1, recurrence), unit)

    interval = Interval(*sorted(randuniq(2, correction, unit_maximum)))

    expected = []

    initial = start = floor(
        add_delta(MIN, rnd.randrange(delta(MIN, max_, unit)), unit),
        recurrence
    )

    if overlap:
        initial = start = add_delta(
            initial,
            rnd.randrange(
                int(interval.start), int(interval.stop)
            ) - correction,
            unit
        )

    for i in range(N):
        recurrence_start = floor(start, recurrence)
        first = floor(add_delta(recurrence_start,
                                interval.start - correction,
                                unit), unit)
        second = add_delta(floor(add_delta(recurrence_start,
                                 interval.stop - correction,
                                 unit),
                            unit), 1, unit)
        assert first < second
        assert start < second
        if start > first:
            first = start

        expected.append(Interval(first, second))
        start = floor(add_delta(recurrence_start, 1, recurrence), recurrence)

    timeinterval = TimeInterval(interval, unit, recurrence)
    actual = list(islice(timeinterval.forward(initial), None, N))

    assert actual == expected
def test_add_delta_raises_value_error_on_wrong_unit():
    with pytest.raises(ValueError):
        add_delta(MIN, -1, 'wrong_unit')
def test_add_delta(datetime, delta, unit, expected):
    """Cases for `add_delta`."""
    assert add_delta(datetime, delta, unit) == expected
Exemple #12
0
 def addfloor(base, delta):
     """Adds 'delta' to 'base' and than floors it
     by unit of this interval."""
     return floor(add_delta(base, delta, self.unit), self.unit)
    def forward(self, start, trim=True):
        """Iterate time intervals starting from 'start'.
        Intervals returned in form of `(start, end)` pair,
        where `start` is a datetime object representing the start
        of the interval and `end` is the non-inclusive end of the interval.

        Parameters
        ----------
        start : datetime.datetime
            A lower bound for the resulting sequence of intervals.
        trim : bool
            Whether a first interval should be trimmed by 'start' or
            it should be full, so it's start point may potentially be
            earlier, that 'start'.

        Yields
        ------
        start : datetime.datetime
            Start of an interval.
        end : datetime.datetime
            End of an interval.
        """
        # pylint: disable=too-many-branches
        if self.recurrence is None:
            base = MIN
        else:
            base = floor(start, self.recurrence)

        correction = -1 * BASE[self.unit]

        def addfloor(base, n):
            """Adds 'delta' to 'base' and than floors it
            by unit of this interval."""
            return floor(add_delta(base, n, self.unit), self.unit)

        # Handle possible overlap in first interval
        try:
            first = addfloor(base, self.start + correction)

            if start > first:
                if trim:
                    first = start
                # If 'unit' is week, 'first' could be earlier than
                # start of 'recurrence' time component corresponding to
                # 'start'.
                elif self.recurrence is not None:
                    recurrence_start = floor(start, self.recurrence)
                    if first < recurrence_start:
                        first = recurrence_start

            if self.isgapless():
                yield first, MAX
                return

            second = addfloor(base, self.stop + correction)

            if self.recurrence is not None:
                first, second = self._clamp_by_recurrence(base, first, second)

            yield first, second
        except OverflowError:
            return

        if self.recurrence is None:
            return
        while True:  # Handle recurring intervals
            base = add_delta(base, 1, self.recurrence)
            try:
                first = addfloor(base, self.start + correction)
                second = addfloor(base, self.stop + correction)
                if base > first:  # In case if flooring by week resulted
                    first = base  # as a time earlier than 'base'

                first, second = self._clamp_by_recurrence(base, first, second)
                yield first, second
            except OverflowError:
                return
 def _clamp_by_recurrence(self, base, *dates):
     max_ = floor(add_delta(base, 1, self.recurrence), self.recurrence)
     return [min(d, max_) for d in dates]