def test_find_last_terminated_period_before_date_overlapping_no_termination( self, ): supervision_period_older = StateSupervisionPeriod.new_with_defaults( state_code="US_XX", start_date=date(2000, 1, 1), termination_date=date(2007, 9, 20), status=StateSupervisionPeriodStatus.PRESENT_WITHOUT_INFO, ) # Overlapping supervision period that should have been found in the other identifier code supervision_period_recent = StateSupervisionPeriod.new_with_defaults( state_code="US_XX", start_date=date(2006, 3, 1), status=StateSupervisionPeriodStatus.PRESENT_WITHOUT_INFO, ) most_recently_terminated_period = find_last_terminated_period_before_date( upper_bound_date=date(2007, 10, 1), periods=[ supervision_period_older, supervision_period_recent, ], maximum_months_proximity=SUPERVISION_PERIOD_PROXIMITY_MONTH_LIMIT, ) self.assertEqual(supervision_period_older, most_recently_terminated_period)
def test_find_last_terminated_period_before_date_none(self): supervision_period_older = StateSupervisionPeriod.new_with_defaults( state_code="US_XX", start_date=date(2000, 1, 1), termination_date=date(2005, 1, 1), status=StateSupervisionPeriodStatus.PRESENT_WITHOUT_INFO, ) supervision_period_recent = StateSupervisionPeriod.new_with_defaults( state_code="US_XX", start_date=date(2006, 3, 1), termination_date=date(2010, 1, 1), status=StateSupervisionPeriodStatus.PRESENT_WITHOUT_INFO, ) most_recently_terminated_period = find_last_terminated_period_before_date( upper_bound_date=date(1990, 10, 1), periods=[ supervision_period_older, supervision_period_recent, ], maximum_months_proximity=SUPERVISION_PERIOD_PROXIMITY_MONTH_LIMIT, ) self.assertIsNone(most_recently_terminated_period)
def test_find_last_terminated_period_before_date_same_termination_date( self, ): supervision_period_a = StateSupervisionPeriod.new_with_defaults( external_id="a", state_code="US_XX", start_date=date(2006, 1, 1), termination_date=date(2007, 12, 31), status=StateSupervisionPeriodStatus.PRESENT_WITHOUT_INFO, ) supervision_period_b = StateSupervisionPeriod.new_with_defaults( external_id="b", state_code="US_XX", start_date=date(2006, 1, 1), termination_date=date(2007, 12, 31), status=StateSupervisionPeriodStatus.PRESENT_WITHOUT_INFO, ) most_recently_terminated_period = find_last_terminated_period_before_date( upper_bound_date=date(2008, 1, 10), periods=[supervision_period_a, supervision_period_b], maximum_months_proximity=SUPERVISION_PERIOD_PROXIMITY_MONTH_LIMIT, ) self.assertEqual(supervision_period_a, most_recently_terminated_period)
def test_find_last_terminated_period_before_date_ends_on_cutoff_date(self): supervision_period_older = StateSupervisionPeriod.new_with_defaults( state_code="US_XX", start_date=date(2000, 1, 1), termination_date=date(2005, 1, 1), status=StateSupervisionPeriodStatus.PRESENT_WITHOUT_INFO, ) supervision_period_recent = StateSupervisionPeriod.new_with_defaults( state_code="US_XX", start_date=date(2006, 3, 1), termination_date=date(2010, 1, 1), status=StateSupervisionPeriodStatus.PRESENT_WITHOUT_INFO, ) # Set the admission date to be on the last day of the cut-off for how close a supervision period termination # has to be to a revocation admission to be counted as a proximal supervision period admission_date = supervision_period_recent.termination_date + relativedelta( days=SUPERVISION_PERIOD_PROXIMITY_MONTH_LIMIT) most_recently_terminated_period = find_last_terminated_period_before_date( upper_bound_date=admission_date, periods=[ supervision_period_older, supervision_period_recent, ], maximum_months_proximity=SUPERVISION_PERIOD_PROXIMITY_MONTH_LIMIT, ) self.assertEqual(supervision_period_recent, most_recently_terminated_period)
def test_find_last_terminated_period_before_date_no_periods(self): most_recently_terminated_period = find_last_terminated_period_before_date( upper_bound_date=date(1990, 10, 1), periods=[], maximum_months_proximity=SUPERVISION_PERIOD_PROXIMITY_MONTH_LIMIT, ) self.assertIsNone(most_recently_terminated_period)
def test_find_last_terminated_period_before_date_month_boundary(self): supervision_period = StateSupervisionPeriod.new_with_defaults( state_code="US_XX", start_date=date(2000, 1, 1), termination_date=date(2005, 3, 31), status=StateSupervisionPeriodStatus.PRESENT_WITHOUT_INFO, ) most_recently_terminated_period = find_last_terminated_period_before_date( upper_bound_date=date(2005, 4, 1), periods=[supervision_period], maximum_months_proximity=SUPERVISION_PERIOD_PROXIMITY_MONTH_LIMIT, ) self.assertEqual(supervision_period, most_recently_terminated_period)
def test_find_last_terminated_period_before_date_same_termination_date_override( self, ): """Tests the find_last_terminated_period_before_date function when a same_date_sort_fn function is included. """ supervision_period_a = StateSupervisionPeriod.new_with_defaults( external_id="a", state_code="US_XX", start_date=date(2006, 1, 1), termination_date=date(2007, 12, 31), status=StateSupervisionPeriodStatus.PRESENT_WITHOUT_INFO, termination_reason=StateSupervisionPeriodTerminationReason. DISCHARGE, ) supervision_period_b = StateSupervisionPeriod.new_with_defaults( external_id="b", state_code="US_XX", start_date=date(2006, 1, 1), termination_date=date(2007, 12, 31), status=StateSupervisionPeriodStatus.PRESENT_WITHOUT_INFO, termination_reason=StateSupervisionPeriodTerminationReason. ABSCONSION, ) def _same_date_sort_override(period_a: StateSupervisionPeriod, period_b: StateSupervisionPeriod) -> int: prioritized_termination_reasons = [ StateSupervisionPeriodTerminationReason.ABSCONSION, StateSupervisionPeriodTerminationReason.EXPIRATION, ] prioritize_a = (period_a.termination_reason in prioritized_termination_reasons) prioritize_b = (period_b.termination_reason in prioritized_termination_reasons) if prioritize_a and prioritize_b: return 0 return -1 if prioritize_a else 1 most_recently_terminated_period = find_last_terminated_period_before_date( upper_bound_date=date(2008, 1, 10), periods=[supervision_period_a, supervision_period_b], maximum_months_proximity=SUPERVISION_PERIOD_PROXIMITY_MONTH_LIMIT, same_date_sort_fn=_same_date_sort_override, ) self.assertEqual(supervision_period_b, most_recently_terminated_period)
def _get_commitment_from_supervision_supervision_period( incarceration_period: StateIncarcerationPeriod, commitment_from_supervision_delegate: StateSpecificCommitmentFromSupervisionDelegate, supervision_period_index: PreProcessedSupervisionPeriodIndex, incarceration_period_index: PreProcessedIncarcerationPeriodIndex, ) -> Optional[StateSupervisionPeriod]: """Identifies the supervision period associated with the commitment to supervision admission on the given |admission_date|. If |prioritize_overlapping_periods| is True, prioritizes supervision periods that are overlapping with the |admission_date|. Else, prioritizes the period that has most recently terminated within SUPERVISION_PERIOD_PROXIMITY_MONTH_LIMIT months of the |admission_date|. """ if not supervision_period_index.supervision_periods: return None if not incarceration_period.admission_date: raise ValueError( "Unexpected missing admission_date on incarceration period: " f"[{incarceration_period}]") if not incarceration_period.admission_reason: raise ValueError( "Unexpected missing admission_reason on incarceration period: " f"[{incarceration_period}]") admission_date = incarceration_period.admission_date admission_reason = incarceration_period.admission_reason if not is_commitment_from_supervision(admission_reason): raise ValueError( "This function should only be called with an " "incarceration_period that is a commitment from supervision. " "Found an incarceration period with an admission_reason that " "is not a valid commitment from supervision admission: " f"{admission_reason}.") preceding_incarceration_period = ( incarceration_period_index.preceding_incarceration_period_in_index( incarceration_period)) if period_is_commitment_from_supervision_admission_from_parole_board_hold( incarceration_period=incarceration_period, preceding_incarceration_period=preceding_incarceration_period, ): if not preceding_incarceration_period: raise ValueError( "This should never happen, since the determination of " "whether the commitment came from a board hold requires " "the preceding_incarceration_period to be a board hold.") if not preceding_incarceration_period.admission_date: raise ValueError( "Unexpected missing admission_date on incarceration period: " f"[{preceding_incarceration_period}]") # If this person was a commitment from supervision from a parole board hold, # then the date that they entered prison was the date of the preceding # incarceration period. admission_date = preceding_incarceration_period.admission_date relevant_periods = _get_relevant_sps_for_pre_commitment_sp_search( admission_reason=admission_reason, supervision_periods=supervision_period_index.supervision_periods, commitment_from_supervision_delegate= commitment_from_supervision_delegate, ) overlapping_periods = _supervision_periods_overlapping_with_date( admission_date, relevant_periods) # If there's more than one recently terminated period with the same # termination_date, prioritize the ones with REVOCATION or RETURN_TO_INCARCERATION # termination_reasons def _same_date_sort_override(period_a: StateSupervisionPeriod, period_b: StateSupervisionPeriod) -> int: prioritized_termination_reasons = [ StateSupervisionPeriodTerminationReason.REVOCATION, StateSupervisionPeriodTerminationReason.RETURN_TO_INCARCERATION, ] prioritize_a = period_a.termination_reason in prioritized_termination_reasons prioritize_b = period_b.termination_reason in prioritized_termination_reasons if prioritize_a and prioritize_b: return sort_period_by_external_id(period_a, period_b) return -1 if prioritize_a else 1 most_recent_terminated_period = find_last_terminated_period_before_date( upper_bound_date=admission_date, periods=relevant_periods, maximum_months_proximity=SUPERVISION_PERIOD_PROXIMITY_MONTH_LIMIT, same_date_sort_fn=_same_date_sort_override, ) terminated_periods = ([most_recent_terminated_period] if most_recent_terminated_period else []) if (admission_reason in commitment_from_supervision_delegate. admission_reasons_that_should_prioritize_overlaps_in_pre_commitment_sp_search( )): valid_pre_commitment_periods = ( overlapping_periods if overlapping_periods else terminated_periods) else: valid_pre_commitment_periods = ( terminated_periods if terminated_periods else overlapping_periods) if not valid_pre_commitment_periods: return None # In the case where there are multiple relevant SPs at this point, sort and return # the first one return min( valid_pre_commitment_periods, key=lambda e: ( # Prioritize terminated periods with a termination_reason of REVOCATION # (False sorts before True) e.termination_reason != StateSupervisionPeriodTerminationReason. REVOCATION, # Prioritize termination_date closest to the admission_date abs(((e.termination_date or datetime.date.today()) - admission_date ).days), # Deterministically sort by external_id in the case where there # are two REVOKED periods with the same termination_date e.external_id, ), )
def us_nd_infer_supervision_period_admission( supervision_period: StateSupervisionPeriod, supervision_period_index: PreProcessedSupervisionPeriodIndex, incarceration_period_index: PreProcessedIncarcerationPeriodIndex, ) -> Optional[StateSupervisionPeriodAdmissionReason]: """Looks at the provided |supervision_period|, all supervision periods for this person via the |supervision_period_index|, and all incarceration periods via |incarceration_period_index| and returns the admission reason for this |supervision_period|. This is necessary because we do not currently have a way to ingest ND admission reasons for supervision periods. """ if not supervision_period.start_date: raise ValueError( "Found null supervision_period.start_date while inferring admission reason." ) all_periods: List[Union[StateIncarcerationPeriod, StateSupervisionPeriod]] = [] all_periods.extend(supervision_period_index.supervision_periods) all_periods.extend(incarceration_period_index.incarceration_periods) most_recent_previous_period = find_last_terminated_period_before_date( upper_bound_date=supervision_period.start_date, periods=all_periods, maximum_months_proximity=LOOKBACK_MONTHS_LIMIT, ) if not most_recent_previous_period: if supervision_period.supervision_type == StateSupervisionType.PAROLE: # If there was not a previous period and the person is under parole supervision, the current admission # reason should be CONDITIONAL_RELEASE return StateSupervisionPeriodAdmissionReason.CONDITIONAL_RELEASE if supervision_period.supervision_type == StateSupervisionType.PROBATION: # If there was not a previous period and the person is under PROBATION supervision, the current admission # reason should be COURT_SENTENCE return StateSupervisionPeriodAdmissionReason.COURT_SENTENCE if isinstance(most_recent_previous_period, StateIncarcerationPeriod): if (most_recent_previous_period.release_reason == StateIncarcerationPeriodReleaseReason.CONDITIONAL_RELEASE): # If the most recent previous incarceration period terminated in CONDITIONAL_RELEASE, set that as the # admission reason. return StateSupervisionPeriodAdmissionReason.CONDITIONAL_RELEASE if isinstance(most_recent_previous_period, StateSupervisionPeriod): if (most_recent_previous_period.termination_reason == StateSupervisionPeriodTerminationReason.ABSCONSION): # If the most recent previous supervision period was an absconsion, the current supervision period's # admission reason should be ABSCONSION. return StateSupervisionPeriodAdmissionReason.RETURN_FROM_ABSCONSION if (most_recent_previous_period.termination_reason == StateSupervisionPeriodTerminationReason.REVOCATION): # If the most recent previous supervision period was a REVOCATION, the current supervision period's # admission reason should be COURT_SENTENCE. return StateSupervisionPeriodAdmissionReason.COURT_SENTENCE if (most_recent_previous_period.supervision_type == StateSupervisionType.HALFWAY_HOUSE and supervision_period.supervision_type == StateSupervisionType.PAROLE): # If the supervision type transitioned from HALFWAY_HOUSE to PAROLE, the current supervision period's # admission reason should be TRANSFER_WITHIN_STATE. return StateSupervisionPeriodAdmissionReason.TRANSFER_WITHIN_STATE if (most_recent_previous_period.supervision_type == StateSupervisionType.PAROLE and supervision_period.supervision_type == StateSupervisionType.PROBATION): # If the supervision type transitioned from PAROLE to PROBATION, the admission reason should be # COURT_SENTENCE. return StateSupervisionPeriodAdmissionReason.COURT_SENTENCE if (most_recent_previous_period.supervising_officer and supervision_period.supervising_officer and most_recent_previous_period.supervising_officer != supervision_period.supervising_officer): # If the supervision officer changed between the previous and current supervision period, the admission # reason should be TRANSFER_WITHIN_STATE. return StateSupervisionPeriodAdmissionReason.TRANSFER_WITHIN_STATE if (most_recent_previous_period.supervision_type == StateSupervisionType.PROBATION and supervision_period.supervision_type == StateSupervisionType.PAROLE): # If the supervision type transitioned from PROBATION to PAROLE, the admission reason should be # INTERNAL_UNKNOWN, since this should be extremely rare. return StateSupervisionPeriodAdmissionReason.INTERNAL_UNKNOWN return None
def _us_nd_normalize_period_if_commitment_from_supervision( incarceration_period_list_index: int, sorted_incarceration_periods: List[StateIncarcerationPeriod], supervision_period_index: Optional[PreProcessedSupervisionPeriodIndex], ) -> StateIncarcerationPeriod: """Returns an updated version of the specified incarceration period if it is a commitment from supervision admission. Updates the admission_reason to be a PROBATION_REVOCATION or a PAROLE_REVOCATION for the following scenarios: - The person was admitted to a state prison due to a NEW_ADMISSION (not a period of TEMPORARY_CUSTODY in a county jail) and was previously in a PAROLE or PROBATION supervision period that terminated due to a REVOCATION. Also note that in this case, we also ensure that there was not an intermediate period of incarceration in a state prison between the supervision REVOCATION and this incarceration period under examination, to make sure we do not mistakenly re-classify what is truly a NEW_ADMISSION as a REVOCATION. """ if supervision_period_index is None: raise ValueError( "IP pre-processing relies on supervision periods for US_ND. " "Expected non-null supervision_period_index.") incarceration_period = sorted_incarceration_periods[ incarceration_period_list_index] admission_date = incarceration_period.admission_date if not admission_date: raise ValueError(f"Admission date for null for {incarceration_period}") admission_reason = incarceration_period.admission_reason if admission_reason == StateIncarcerationPeriodAdmissionReason.NEW_ADMISSION: most_recent_supervision_period = find_last_terminated_period_before_date( upper_bound_date=admission_date, periods=supervision_period_index.supervision_periods, maximum_months_proximity= _NEW_ADMISSION_PROBATION_COMMITMENT_LOOKBACK_MONTHS, ) if (most_recent_supervision_period and most_recent_supervision_period.termination_reason == StateSupervisionPeriodTerminationReason.REVOCATION and most_recent_supervision_period.supervision_type in (StateSupervisionType.PAROLE, StateSupervisionType.PROBATION)): was_intermediate_state_prison_admission = ( _intermediate_state_prison_admission( most_recent_supervision_period, incarceration_period, sorted_incarceration_periods, )) # If there was a separate admission to a state prison after the revocation # and before this admission, then it is not accurate to describe *this* # admission as being due to a revocation if was_intermediate_state_prison_admission: return incarceration_period return attr.evolve( incarceration_period, admission_reason=( StateIncarcerationPeriodAdmissionReason. PROBATION_REVOCATION if most_recent_supervision_period.supervision_type == StateSupervisionType.PROBATION else StateIncarcerationPeriodAdmissionReason.PAROLE_REVOCATION), ) # This period does not require any updated values return incarceration_period