def test_portion_overlapping_with_month(self):

        self.assertEqual(
            None,
            self.negative_day_range.portion_overlapping_with_month(2019, 2))

        self.assertEqual(
            None, self.zero_day_range.portion_overlapping_with_month(2019, 2))

        self.assertEqual(
            self.one_day_range,
            self.one_day_range.portion_overlapping_with_month(2019, 2))

        self.assertEqual(
            self.single_month_range,
            self.single_month_range.portion_overlapping_with_month(2019, 2))

        self.assertEqual(
            TimeRange(lower_bound_inclusive_date=datetime.date(2019, 2, 3),
                      upper_bound_exclusive_date=datetime.date(2019, 3, 1)),
            self.multi_month_range.portion_overlapping_with_month(2019, 2))

        self.assertEqual(
            TimeRange(lower_bound_inclusive_date=datetime.date(2019, 3, 1),
                      upper_bound_exclusive_date=datetime.date(2019, 4, 1)),
            self.multi_month_range.portion_overlapping_with_month(2019, 3))

        self.assertEqual(
            TimeRange(lower_bound_inclusive_date=datetime.date(2019, 4, 1),
                      upper_bound_exclusive_date=datetime.date(2019, 4, 10)),
            self.multi_month_range.portion_overlapping_with_month(2019, 4))
Пример #2
0
    def is_fully_incarcerated_for_range(self,
                                        range_to_cover: TimeRange) -> bool:
        """Returns True if this person is incarcerated for the full duration of the time range."""

        months_range_overlaps = range_to_cover.get_months_range_overlaps_at_all(
        )

        if not months_range_overlaps:
            return False

        months_without_complete_incarceration = []
        for year, month in months_range_overlaps:
            was_incarcerated_all_month = (
                year, month) in self.months_fully_incarcerated
            if not was_incarcerated_all_month:
                months_without_complete_incarceration.append((year, month))

        for year, month in months_without_complete_incarceration:
            overlapping_periods = self.month_to_overlapping_incarceration_periods[
                year][month]

            range_portion_overlapping_month = range_to_cover.portion_overlapping_with_month(
                year, month)
            if not range_portion_overlapping_month:
                raise ValueError(
                    f'Expecting only months that overlap with the range, month ({year}, {month}) does not.'
                )

            remaining_ranges_to_cover = self._get_portions_of_range_not_covered_by_periods_subset(
                range_portion_overlapping_month, overlapping_periods)
            if remaining_ranges_to_cover:
                return False

        return True
    def test_exactly_overlapping_ranges(self):
        range_1 = TimeRange.for_month(2019, 2)
        range_2 = TimeRange.for_month(2019, 2)

        time_range_diff = TimeRangeDiff(range_1, range_2)

        self.assertEqual(range_1, time_range_diff.overlapping_range)
        self.assertEqual([], time_range_diff.range_1_non_overlapping_parts)
        self.assertEqual([], time_range_diff.range_2_non_overlapping_parts)
    def test_partially_overlapping_ranges(self):
        range_1 = TimeRange(datetime.date(2019, 2, 5),
                            datetime.date(2019, 5, 2))
        range_2 = TimeRange(datetime.date(2019, 3, 1),
                            datetime.date(2019, 6, 5))

        time_range_diff = TimeRangeDiff(range_1, range_2)

        self.assertEqual(
            TimeRange(datetime.date(2019, 3, 1), datetime.date(2019, 5, 2)),
            time_range_diff.overlapping_range)
        self.assertEqual(
            [TimeRange(datetime.date(2019, 2, 5), datetime.date(2019, 3, 1))],
            time_range_diff.range_1_non_overlapping_parts)
        self.assertEqual(
            [TimeRange(datetime.date(2019, 5, 2), datetime.date(2019, 6, 5))],
            time_range_diff.range_2_non_overlapping_parts)

        time_range_diff = TimeRangeDiff(range_2, range_1)
        self.assertEqual(
            TimeRange(datetime.date(2019, 3, 1), datetime.date(2019, 5, 2)),
            time_range_diff.overlapping_range)
        self.assertEqual(
            [TimeRange(datetime.date(2019, 5, 2), datetime.date(2019, 6, 5))],
            time_range_diff.range_1_non_overlapping_parts)
        self.assertEqual(
            [TimeRange(datetime.date(2019, 2, 5), datetime.date(2019, 3, 1))],
            time_range_diff.range_2_non_overlapping_parts)
Пример #5
0
    def _get_portions_of_range_not_covered_by_periods_subset(
        time_range_to_cover: TimeRange,
        incarceration_periods_subset: List[StateIncarcerationPeriod]
    ) -> List[TimeRange]:
        """Returns a list of time ranges within the provided |time_range_to_cover| which the provided set of
        incarceration periods does not fully overlap.
        """

        remaining_ranges_to_cover = [time_range_to_cover]

        for incarceration_period in incarceration_periods_subset:
            ip_time_range = TimeRange.for_incarceration_period(
                incarceration_period)

            new_remaining_ranges_to_cover = []
            for time_range in remaining_ranges_to_cover:
                new_remaining_ranges_to_cover.extend(
                    TimeRangeDiff(
                        range_1=ip_time_range,
                        range_2=time_range).range_2_non_overlapping_parts)

            remaining_ranges_to_cover = new_remaining_ranges_to_cover
            if not remaining_ranges_to_cover:
                break

        return remaining_ranges_to_cover
def supervision_period_counts_towards_supervision_population_in_date_range_state_specific(
        date_range: TimeRange,
        supervision_sentences: List[StateSupervisionSentence],
        incarceration_sentences: List[StateIncarcerationSentence],
        supervision_period: StateSupervisionPeriod) -> bool:
    """ Returns False if there is state-specific information to indicate that the supervision period should not count
    towards the supervision population in a range. Returns True if either there is a state-specific check that indicates
    that the supervision period should count or if there is no state-specific check to perform.
    """

    if supervision_period.state_code == 'US_MO':
        sp_range = TimeRange.for_supervision_period(supervision_period)
        overlapping_range = TimeRangeDiff(range_1=date_range,
                                          range_2=sp_range).overlapping_range

        if not overlapping_range:
            return False

        return us_mo_get_most_recent_supervision_period_supervision_type_before_upper_bound_day(
            upper_bound_exclusive_date=overlapping_range.
            upper_bound_exclusive_date,
            lower_bound_inclusive_date=overlapping_range.
            lower_bound_inclusive_date,
            incarceration_sentences=incarceration_sentences,
            supervision_sentences=supervision_sentences) is not None

    return True
    def run_is_fully_incarcerated_for_range_check(
            self, incarceration_periods: List[StateIncarcerationPeriod],
            range_start_num_days_from_periods_start: int,
            range_end_num_days_from_periods_end: int,
            is_fully_incarcerated: bool):
        period_range_start = incarceration_periods[0].admission_date
        if not period_range_start:
            raise ValueError("Expected admission date")

        period_range_end = incarceration_periods[-1].release_date
        period_range_end = period_range_end if period_range_end else (
            date.today() + timedelta(days=1))

        lower_bound_inclusive = period_range_start + timedelta(
            days=range_start_num_days_from_periods_start)
        upper_bound_exclusive = period_range_end + timedelta(
            days=range_end_num_days_from_periods_end)

        index = IncarcerationPeriodIndex(incarceration_periods)

        time_range = TimeRange(
            lower_bound_inclusive_date=lower_bound_inclusive,
            upper_bound_exclusive_date=upper_bound_exclusive)
        if is_fully_incarcerated:
            self.assertTrue(index.is_fully_incarcerated_for_range(time_range))
        else:
            self.assertFalse(index.is_fully_incarcerated_for_range(time_range))
    def setUp(self) -> None:
        self.negative_day_range = TimeRange(
            lower_bound_inclusive_date=datetime.date(2019, 2, 3),
            upper_bound_exclusive_date=datetime.date(2019, 2, 2))

        self.zero_day_range = TimeRange(
            lower_bound_inclusive_date=datetime.date(2019, 2, 3),
            upper_bound_exclusive_date=datetime.date(2019, 2, 3))

        self.one_day_range = TimeRange(
            lower_bound_inclusive_date=datetime.date(2019, 2, 3),
            upper_bound_exclusive_date=datetime.date(2019, 2, 4))

        self.single_month_range = TimeRange(
            lower_bound_inclusive_date=datetime.date(2019, 2, 1),
            upper_bound_exclusive_date=datetime.date(2019, 3, 1))

        self.multi_month_range = TimeRange(
            lower_bound_inclusive_date=datetime.date(2019, 2, 3),
            upper_bound_exclusive_date=datetime.date(2019, 4, 10))
Пример #9
0
    def _months_fully_incarcerated(self) -> Set[Tuple[int, int]]:
        """For each StateIncarcerationPeriod, identifies months where the person was incarcerated for every day during
        that month. Returns a set of months in the format (year, month) for which the person spent the entire month in a
        prison.
        """
        months_fully_incarcerated: Set[Tuple[int, int]] = set()

        for incarceration_period in self.incarceration_periods:
            ip_range = TimeRange.for_incarceration_period(incarceration_period)
            months_overlaps_at_all = ip_range.get_months_range_overlaps_at_all(
            )

            for year, month in months_overlaps_at_all:
                overlapping_periods = self.month_to_overlapping_incarceration_periods[
                    year][month]

                remaining_ranges_to_cover = self._get_portions_of_range_not_covered_by_periods_subset(
                    TimeRange.for_month(year, month), overlapping_periods)
                if not remaining_ranges_to_cover:
                    months_fully_incarcerated.add((year, month))

        return months_fully_incarcerated
    def test_no_periods(self):

        index = IncarcerationPeriodIndex([])
        self.assertFalse(
            index.is_fully_incarcerated_for_range(
                TimeRange(lower_bound_inclusive_date=date(2019, 1, 2),
                          upper_bound_exclusive_date=date(2020, 2, 1))))

        self.assertFalse(
            index.is_fully_incarcerated_for_range(
                TimeRange(lower_bound_inclusive_date=date(2019, 1, 1),
                          upper_bound_exclusive_date=date(2019, 2, 1))))

        self.assertFalse(
            index.is_fully_incarcerated_for_range(
                TimeRange(lower_bound_inclusive_date=date(2019, 1, 1),
                          upper_bound_exclusive_date=date(2019, 1, 2))))

        self.assertFalse(
            index.is_fully_incarcerated_for_range(
                TimeRange(lower_bound_inclusive_date=date(2019, 1, 1),
                          upper_bound_exclusive_date=date(2019, 1, 1))))
Пример #11
0
    def _month_to_overlapping_incarceration_periods(
            self) -> Dict[int, Dict[int, List[StateIncarcerationPeriod]]]:
        month_to_overlapping_incarceration_periods: Dict[int, Dict[int, List[StateIncarcerationPeriod]]] = \
            defaultdict(lambda: defaultdict(list))

        for incarceration_period in self.incarceration_periods:
            ip_time_range = TimeRange.for_incarceration_period(
                incarceration_period)

            for year, month in ip_time_range.get_months_range_overlaps_at_all(
            ):
                month_to_overlapping_incarceration_periods[year][month].append(
                    incarceration_period)

        return month_to_overlapping_incarceration_periods
class TestTimeRange(unittest.TestCase):
    """Tests for TimeRange"""
    def setUp(self) -> None:
        self.negative_day_range = TimeRange(
            lower_bound_inclusive_date=datetime.date(2019, 2, 3),
            upper_bound_exclusive_date=datetime.date(2019, 2, 2))

        self.zero_day_range = TimeRange(
            lower_bound_inclusive_date=datetime.date(2019, 2, 3),
            upper_bound_exclusive_date=datetime.date(2019, 2, 3))

        self.one_day_range = TimeRange(
            lower_bound_inclusive_date=datetime.date(2019, 2, 3),
            upper_bound_exclusive_date=datetime.date(2019, 2, 4))

        self.single_month_range = TimeRange(
            lower_bound_inclusive_date=datetime.date(2019, 2, 1),
            upper_bound_exclusive_date=datetime.date(2019, 3, 1))

        self.multi_month_range = TimeRange(
            lower_bound_inclusive_date=datetime.date(2019, 2, 3),
            upper_bound_exclusive_date=datetime.date(2019, 4, 10))

    def test_get_months_range_overlaps_at_all(self):
        self.assertEqual(
            [], self.negative_day_range.get_months_range_overlaps_at_all())
        self.assertEqual(
            [], self.zero_day_range.get_months_range_overlaps_at_all())
        self.assertEqual([(2019, 2)],
                         self.one_day_range.get_months_range_overlaps_at_all())
        self.assertEqual(
            [(2019, 2)],
            self.single_month_range.get_months_range_overlaps_at_all())
        self.assertEqual(
            [(2019, 2), (2019, 3), (2019, 4)],
            self.multi_month_range.get_months_range_overlaps_at_all())

    def test_portion_overlapping_with_month(self):

        self.assertEqual(
            None,
            self.negative_day_range.portion_overlapping_with_month(2019, 2))

        self.assertEqual(
            None, self.zero_day_range.portion_overlapping_with_month(2019, 2))

        self.assertEqual(
            self.one_day_range,
            self.one_day_range.portion_overlapping_with_month(2019, 2))

        self.assertEqual(
            self.single_month_range,
            self.single_month_range.portion_overlapping_with_month(2019, 2))

        self.assertEqual(
            TimeRange(lower_bound_inclusive_date=datetime.date(2019, 2, 3),
                      upper_bound_exclusive_date=datetime.date(2019, 3, 1)),
            self.multi_month_range.portion_overlapping_with_month(2019, 2))

        self.assertEqual(
            TimeRange(lower_bound_inclusive_date=datetime.date(2019, 3, 1),
                      upper_bound_exclusive_date=datetime.date(2019, 4, 1)),
            self.multi_month_range.portion_overlapping_with_month(2019, 3))

        self.assertEqual(
            TimeRange(lower_bound_inclusive_date=datetime.date(2019, 4, 1),
                      upper_bound_exclusive_date=datetime.date(2019, 4, 10)),
            self.multi_month_range.portion_overlapping_with_month(2019, 4))