def test_completeEnumSet_admittedForCommitmentFromSupervision(
            self) -> None:
        period = schema.StateIncarcerationPeriod()
        for admission_reason in StateIncarcerationPeriodAdmissionReason:
            period.admission_reason = admission_reason.value
            is_commitment_from_supervision(
                StateIncarcerationPeriodAdmissionReason.
                parse_from_canonical_string(period.admission_reason, ),
                allow_ingest_only_enum_values=True,
            )

        is_commitment_from_supervision(
            StateIncarcerationPeriodAdmissionReason.
            parse_from_canonical_string(None))
Beispiel #2
0
    def _admission_event_for_period(
        self,
        incarceration_sentences: List[StateIncarcerationSentence],
        supervision_sentences: List[StateSupervisionSentence],
        incarceration_period: StateIncarcerationPeriod,
        incarceration_period_index: PreProcessedIncarcerationPeriodIndex,
        supervision_period_index: PreProcessedSupervisionPeriodIndex,
        assessments: List[StateAssessment],
        sorted_violation_responses: List[StateSupervisionViolationResponse],
        supervision_period_to_agent_associations: Dict[int, Dict[Any, Any]],
        county_of_residence: Optional[str],
    ) -> Optional[IncarcerationAdmissionEvent]:
        """Returns an IncarcerationAdmissionEvent if this incarceration period represents an
        admission to incarceration."""

        admission_date: Optional[date] = incarceration_period.admission_date
        admission_reason: Optional[
            StateIncarcerationPeriodAdmissionReason
        ] = incarceration_period.admission_reason

        if admission_date and admission_reason:
            state_code = incarceration_period.state_code
            commitment_from_supervision_delegate = (
                get_state_specific_commitment_from_supervision_delegate(state_code)
            )
            violation_delegate = get_state_specific_violation_delegate(state_code)

            if is_commitment_from_supervision(admission_reason):

                return self._commitment_from_supervision_event_for_period(
                    incarceration_sentences=incarceration_sentences,
                    supervision_sentences=supervision_sentences,
                    incarceration_period=incarceration_period,
                    incarceration_period_index=incarceration_period_index,
                    supervision_period_index=supervision_period_index,
                    assessments=assessments,
                    sorted_violation_responses=sorted_violation_responses,
                    supervision_period_to_agent_associations=supervision_period_to_agent_associations,
                    county_of_residence=county_of_residence,
                    commitment_from_supervision_delegate=commitment_from_supervision_delegate,
                    violation_delegate=violation_delegate,
                )

            return IncarcerationStandardAdmissionEvent(
                state_code=incarceration_period.state_code,
                event_date=admission_date,
                facility=incarceration_period.facility,
                admission_reason=admission_reason,
                admission_reason_raw_text=incarceration_period.admission_reason_raw_text,
                specialized_purpose_for_incarceration=incarceration_period.specialized_purpose_for_incarceration,
                county_of_residence=county_of_residence,
            )

        return None
Beispiel #3
0
    def test_is_commitment_from_supervision_all_enums(self) -> None:
        for admission_reason in StateIncarcerationPeriodAdmissionReason:
            if (
                admission_reason
                == StateIncarcerationPeriodAdmissionReason.ADMITTED_FROM_SUPERVISION
            ):
                with self.assertRaises(ValueError):
                    _ = state_incarceration_period.is_commitment_from_supervision(
                        admission_reason
                    )

                # Assert no error when we allow ingest-only values
                _ = state_incarceration_period.is_commitment_from_supervision(
                    admission_reason, allow_ingest_only_enum_values=True
                )
            else:
                # Assert no error
                _ = state_incarceration_period.is_commitment_from_supervision(
                    admission_reason
                )
def associate_revocation_svrs_with_ips(
        merged_persons: List[schema.StatePerson]):
    """
    For each person in the provided |merged_persons|, attempts to associate
    StateSupervisionViolationResponses that result in revocation with their
    corresponding StateIncarcerationPeriod.
    """
    for person in merged_persons:
        svrs = get_all_entities_of_cls(
            [person], schema.StateSupervisionViolationResponse)
        ips = get_all_entities_of_cls([person],
                                      schema.StateIncarcerationPeriod)

        revocation_svrs: List[schema.StateSupervisionViolationResponse] = []
        for svr in svrs:
            svr = cast(schema.StateSupervisionViolationResponse, svr)
            if revoked_to_prison(svr) and svr.response_date:
                revocation_svrs.append(svr)
        revocation_ips: List[schema.StateIncarcerationPeriod] = []
        for ip in ips:
            ip = cast(schema.StateIncarcerationPeriod, ip)
            admission_reason = (StateIncarcerationPeriodAdmissionReason.
                                parse_from_canonical_string(
                                    ip.admission_reason))
            if isinstance(admission_reason,
                          StateIncarcerationPeriodAdmissionReason):
                if (is_commitment_from_supervision(
                        admission_reason, allow_ingest_only_enum_values=True)
                        and ip.admission_date):
                    revocation_ips.append(ip)

        if not revocation_svrs or not revocation_ips:
            continue

        sorted_svrs = sorted(revocation_svrs, key=lambda x: x.response_date)

        seen: Set[int] = set()
        for svr in sorted_svrs:
            closest_ip = _get_closest_matching_incarceration_period(
                svr, revocation_ips)
            if closest_ip and id(closest_ip) not in seen:
                seen.add(id(closest_ip))
                closest_ip.source_supervision_violation_response = svr
Beispiel #5
0
def get_pre_incarceration_supervision_type_from_ip_admission_reason(
    admission_reason: StateIncarcerationPeriodAdmissionReason,
) -> Optional[StateSupervisionPeriodSupervisionType]:
    """Derives the supervision type the person was serving prior to being
    admitted to incarceration with the given |admission_reason|."""
    if not is_commitment_from_supervision(admission_reason):
        # If this isn't a commitment from supervision admission then we can't infer
        # the pre-incarceration supervision type from the admission_reason
        return None

    if (admission_reason not in
            COMMITMENT_FROM_SUPERVISION_ADMISSION_REASON_TO_SUPERVISION_TYPE_MAP
        ):
        raise ValueError(
            "Enum case not handled for StateIncarcerationPeriodAdmissionReason of type: "
            f"{admission_reason}.")

    return COMMITMENT_FROM_SUPERVISION_ADMISSION_REASON_TO_SUPERVISION_TYPE_MAP.get(
        admission_reason)
Beispiel #6
0
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,
        ),
    )