def test_include_assessment_in_metric(self): pipeline = 'supervision' state_code = 'US_MO' assessment_type = StateAssessmentType.ORAS_COMMUNITY_SUPERVISION include_assessment = assessment_utils.include_assessment_in_metric(pipeline, state_code, assessment_type) self.assertTrue(include_assessment) assessment_type = StateAssessmentType.ORAS_COMMUNITY_SUPERVISION_SCREENING include_assessment = assessment_utils.include_assessment_in_metric(pipeline, state_code, assessment_type) self.assertTrue(include_assessment)
def test_include_assessment_in_metric_unsupported_state_code(self): pipeline = 'supervision' state_code = 'US_XX' assessment_type = StateAssessmentType.ORAS_MISDEMEANOR_ASSESSMENT include_assessment = assessment_utils.include_assessment_in_metric(pipeline, state_code, assessment_type) self.assertFalse(include_assessment)
def characteristics_dict(person: StatePerson, program_event: ProgramEvent) -> Dict[str, Any]: """Builds a dictionary that describes the characteristics of the person and event. Args: person: the StatePerson we are picking characteristics from program_event: the ProgramEvent we are picking characteristics from Returns: A dictionary populated with all relevant characteristics. """ characteristics: Dict[str, Any] = {} event_date = program_event.event_date if isinstance(program_event, ProgramReferralEvent): if program_event.supervision_type: characteristics['supervision_type'] = program_event.supervision_type if program_event.assessment_score and program_event.assessment_type: assessment_bucket = assessment_score_bucket( assessment_score=program_event.assessment_score, assessment_level=None, assessment_type=program_event.assessment_type) if assessment_bucket and include_assessment_in_metric( 'program', program_event.state_code, program_event.assessment_type): characteristics['assessment_score_bucket'] = assessment_bucket characteristics['assessment_type'] = program_event.assessment_type if program_event.participation_status: characteristics['participation_status'] = program_event.participation_status if program_event.supervising_officer_external_id: characteristics['supervising_officer_external_id'] = program_event.supervising_officer_external_id if program_event.supervising_district_external_id: characteristics['supervising_district_external_id'] = program_event.supervising_district_external_id elif isinstance(program_event, ProgramParticipationEvent): characteristics['date_of_participation'] = event_date if program_event.supervision_type: characteristics['supervision_type'] = program_event.supervision_type if program_event.program_location_id: characteristics['program_location_id'] = program_event.program_location_id if program_event.program_id: characteristics['program_id'] = program_event.program_id characteristics = add_demographic_characteristics(characteristics, person, event_date) characteristics_with_person_details = characteristics_with_person_id_fields( characteristics, program_event.state_code, person, 'program') return characteristics_with_person_details
def characteristics_dict(person: StatePerson, supervision_time_bucket: SupervisionTimeBucket, metric_type: SupervisionMetricType) -> Dict[str, Any]: """Builds a dictionary that describes the characteristics of the person and supervision_time_bucket. Args: person: the StatePerson we are picking characteristics from supervision_time_bucket: the SupervisionTimeBucket we are picking characteristics from metric_type: The SupervisionMetricType provided determines which fields should be added to the characteristics dictionary Returns: A dictionary populated with all relevant characteristics. """ characteristics: Dict[str, Any] = {} include_revocation_dimensions = _include_revocation_dimensions_for_metric( metric_type) include_assessment_dimensions = _include_assessment_dimensions_for_metric( metric_type) include_demographic_dimensions = _include_demographic_dimensions_for_metric( metric_type) include_person_level_dimensions = _include_person_level_dimensions_for_metric( metric_type) if (metric_type == SupervisionMetricType.POPULATION and isinstance(supervision_time_bucket, (RevocationReturnSupervisionTimeBucket, NonRevocationReturnSupervisionTimeBucket))): if supervision_time_bucket.most_severe_violation_type: characteristics[ 'most_severe_violation_type'] = supervision_time_bucket.most_severe_violation_type if supervision_time_bucket.most_severe_violation_type_subtype: characteristics['most_severe_violation_type_subtype'] = \ supervision_time_bucket.most_severe_violation_type_subtype if supervision_time_bucket.response_count is not None: characteristics[ 'response_count'] = supervision_time_bucket.response_count if include_revocation_dimensions and \ isinstance(supervision_time_bucket, RevocationReturnSupervisionTimeBucket): if supervision_time_bucket.revocation_type: characteristics[ 'revocation_type'] = supervision_time_bucket.revocation_type if supervision_time_bucket.source_violation_type: characteristics[ 'source_violation_type'] = supervision_time_bucket.source_violation_type if metric_type in [ SupervisionMetricType.REVOCATION_ANALYSIS, SupervisionMetricType.REVOCATION_VIOLATION_TYPE_ANALYSIS ]: if supervision_time_bucket.most_severe_violation_type: characteristics[ 'most_severe_violation_type'] = supervision_time_bucket.most_severe_violation_type if supervision_time_bucket.most_severe_violation_type_subtype: characteristics['most_severe_violation_type_subtype'] = \ supervision_time_bucket.most_severe_violation_type_subtype if metric_type in [SupervisionMetricType.REVOCATION_ANALYSIS]: if supervision_time_bucket.most_severe_response_decision: characteristics['most_severe_response_decision'] = \ supervision_time_bucket.most_severe_response_decision if supervision_time_bucket.response_count is not None: characteristics[ 'response_count'] = supervision_time_bucket.response_count if isinstance(supervision_time_bucket, SupervisionTerminationBucket): if supervision_time_bucket.termination_reason: characteristics[ 'termination_reason'] = supervision_time_bucket.termination_reason if supervision_time_bucket.supervision_type: characteristics[ 'supervision_type'] = supervision_time_bucket.supervision_type if supervision_time_bucket.case_type: characteristics['case_type'] = supervision_time_bucket.case_type if not include_revocation_dimensions and supervision_time_bucket.supervision_level: characteristics[ 'supervision_level'] = supervision_time_bucket.supervision_level if include_assessment_dimensions: # TODO(2853): Figure out more robust solution for not assessed people. Here we don't set assessment_type when # someone is not assessed. This only works as desired because BQ doesn't rely on assessment_type at all. characteristics['assessment_score_bucket'] = 'NOT_ASSESSED' if supervision_time_bucket.assessment_score and supervision_time_bucket.assessment_type: assessment_bucket = assessment_score_bucket( supervision_time_bucket.assessment_score, supervision_time_bucket.assessment_level, supervision_time_bucket.assessment_type) if assessment_bucket and include_assessment_in_metric( 'supervision', supervision_time_bucket.state_code, supervision_time_bucket.assessment_type): characteristics['assessment_score_bucket'] = assessment_bucket characteristics[ 'assessment_type'] = supervision_time_bucket.assessment_type if supervision_time_bucket.supervising_officer_external_id: characteristics[ 'supervising_officer_external_id'] = supervision_time_bucket.supervising_officer_external_id if supervision_time_bucket.supervising_district_external_id: characteristics[ 'supervising_district_external_id'] = supervision_time_bucket.supervising_district_external_id if isinstance(supervision_time_bucket, RevocationReturnSupervisionTimeBucket): event_date = supervision_time_bucket.revocation_admission_date elif isinstance(supervision_time_bucket, SupervisionTerminationBucket): event_date = supervision_time_bucket.termination_date else: year = supervision_time_bucket.year month = supervision_time_bucket.month event_date = date(year, month, 1) if include_demographic_dimensions: characteristics = add_demographic_characteristics( characteristics, person, event_date) if include_person_level_dimensions: characteristics = characteristics_with_person_id_fields( characteristics, person, 'supervision') if not include_revocation_dimensions and supervision_time_bucket.supervision_level_raw_text: characteristics['supervision_level_raw_text'] = \ supervision_time_bucket.supervision_level_raw_text if metric_type == SupervisionMetricType.POPULATION: if isinstance(supervision_time_bucket, (RevocationReturnSupervisionTimeBucket, NonRevocationReturnSupervisionTimeBucket)): characteristics['is_on_supervision_last_day_of_month'] = \ supervision_time_bucket.is_on_supervision_last_day_of_month if metric_type == SupervisionMetricType.REVOCATION_ANALYSIS: if isinstance(supervision_time_bucket, RevocationReturnSupervisionTimeBucket) \ and supervision_time_bucket.violation_history_description: characteristics['violation_history_description'] = \ supervision_time_bucket.violation_history_description if include_revocation_dimensions and isinstance( supervision_time_bucket, RevocationReturnSupervisionTimeBucket): characteristics['revocation_admission_date'] = \ supervision_time_bucket.revocation_admission_date if metric_type == SupervisionMetricType.ASSESSMENT_CHANGE: if isinstance(supervision_time_bucket, SupervisionTerminationBucket) \ and supervision_time_bucket.termination_date: characteristics[ 'termination_date'] = supervision_time_bucket.termination_date return characteristics
def characteristic_combinations(person: StatePerson, supervision_time_bucket: SupervisionTimeBucket, inclusions: Dict[str, bool], metric_type: SupervisionMetricType) -> \ List[Dict[str, Any]]: """Calculates all supervision metric combinations. Returns the list of all combinations of the metric characteristics, of all sizes, given the StatePerson and SupervisionTimeBucket. That is, this returns a list of dictionaries where each dictionary is a combination of 0 to n unique elements of characteristics applicable to the given person and supervision_time_bucket. Args: person: the StatePerson we are picking characteristics from supervision_time_bucket: the SupervisionTimeBucket we are picking characteristics from inclusions: A dictionary containing the following keys that correspond to characteristic dimensions: - age_bucket - ethnicity - gender - race Where the values are boolean flags indicating whether to include the dimension in the calculations. metric_type: The SupervisionMetricType provided determines which fields should be added to the characteristics dictionary Returns: A list of dictionaries containing all unique combinations of characteristics. """ characteristics: Dict[str, Any] = {} include_revocation_dimensions = _include_revocation_dimensions_for_metric( metric_type) include_assessment_dimensions = _include_assessment_dimensions_for_metric( metric_type) include_person_level_dimensions = _include_person_level_dimensions_for_metric( metric_type) if (metric_type == SupervisionMetricType.POPULATION and isinstance(supervision_time_bucket, (RevocationReturnSupervisionTimeBucket, NonRevocationReturnSupervisionTimeBucket))): if supervision_time_bucket.most_severe_violation_type: characteristics[ 'most_severe_violation_type'] = supervision_time_bucket.most_severe_violation_type if supervision_time_bucket.most_severe_violation_type_subtype: characteristics['most_severe_violation_type_subtype'] = \ supervision_time_bucket.most_severe_violation_type_subtype if supervision_time_bucket.response_count is not None: characteristics[ 'response_count'] = supervision_time_bucket.response_count if include_revocation_dimensions and \ isinstance(supervision_time_bucket, RevocationReturnSupervisionTimeBucket): if supervision_time_bucket.revocation_type: characteristics[ 'revocation_type'] = supervision_time_bucket.revocation_type if supervision_time_bucket.source_violation_type: characteristics[ 'source_violation_type'] = supervision_time_bucket.source_violation_type if metric_type in [ SupervisionMetricType.REVOCATION_ANALYSIS, SupervisionMetricType.REVOCATION_VIOLATION_TYPE_ANALYSIS ]: if supervision_time_bucket.most_severe_violation_type: characteristics[ 'most_severe_violation_type'] = supervision_time_bucket.most_severe_violation_type if supervision_time_bucket.most_severe_violation_type_subtype: characteristics['most_severe_violation_type_subtype'] = \ supervision_time_bucket.most_severe_violation_type_subtype if metric_type in [SupervisionMetricType.REVOCATION_ANALYSIS]: if supervision_time_bucket.most_severe_response_decision: characteristics['most_severe_response_decision'] = \ supervision_time_bucket.most_severe_response_decision if supervision_time_bucket.response_count is not None: characteristics[ 'response_count'] = supervision_time_bucket.response_count if isinstance(supervision_time_bucket, SupervisionTerminationBucket): if supervision_time_bucket.termination_reason: characteristics[ 'termination_reason'] = supervision_time_bucket.termination_reason if supervision_time_bucket.supervision_type: characteristics[ 'supervision_type'] = supervision_time_bucket.supervision_type if supervision_time_bucket.case_type: characteristics['case_type'] = supervision_time_bucket.case_type if not include_revocation_dimensions and supervision_time_bucket.supervision_level: characteristics[ 'supervision_level'] = supervision_time_bucket.supervision_level if include_assessment_dimensions: # TODO(2853): Figure out more robust solution for not assessed people. Here we don't set assessment_type when # someone is not assessed. This only works as desired because BQ doesn't rely on assessment_type at all. characteristics['assessment_score_bucket'] = 'NOT_ASSESSED' if supervision_time_bucket.assessment_score and supervision_time_bucket.assessment_type: assessment_bucket = assessment_score_bucket( supervision_time_bucket.assessment_score, supervision_time_bucket.assessment_level, supervision_time_bucket.assessment_type) if assessment_bucket and include_assessment_in_metric( 'supervision', supervision_time_bucket.state_code, supervision_time_bucket.assessment_type): characteristics['assessment_score_bucket'] = assessment_bucket characteristics[ 'assessment_type'] = supervision_time_bucket.assessment_type if supervision_time_bucket.supervising_officer_external_id: characteristics[ 'supervising_officer_external_id'] = supervision_time_bucket.supervising_officer_external_id if supervision_time_bucket.supervising_district_external_id: characteristics[ 'supervising_district_external_id'] = supervision_time_bucket.supervising_district_external_id if inclusions.get('age_bucket'): year = supervision_time_bucket.year month = supervision_time_bucket.month start_of_bucket = date(year, month, 1) entry_age = age_at_date(person, start_of_bucket) entry_age_bucket = age_bucket(entry_age) if entry_age_bucket is not None: characteristics['age_bucket'] = entry_age_bucket if inclusions.get('gender'): if person.gender is not None: characteristics['gender'] = person.gender if person.races or person.ethnicities: if inclusions.get('race'): races = person.races else: races = [] if inclusions.get('ethnicity'): ethnicities = person.ethnicities else: ethnicities = [] all_combinations = for_characteristics_races_ethnicities( races, ethnicities, characteristics) else: all_combinations = for_characteristics(characteristics) if include_person_level_dimensions: characteristics_with_person_details = characteristics_with_person_id_fields( characteristics, person, 'supervision') if not include_revocation_dimensions and supervision_time_bucket.supervision_level_raw_text: characteristics_with_person_details['supervision_level_raw_text'] = \ supervision_time_bucket.supervision_level_raw_text if metric_type == SupervisionMetricType.POPULATION: if isinstance(supervision_time_bucket, (RevocationReturnSupervisionTimeBucket, NonRevocationReturnSupervisionTimeBucket)): characteristics_with_person_details['is_on_supervision_last_day_of_month'] = \ supervision_time_bucket.is_on_supervision_last_day_of_month if metric_type == SupervisionMetricType.REVOCATION_ANALYSIS: # Only include violation history descriptions on person-level metrics if isinstance(supervision_time_bucket, RevocationReturnSupervisionTimeBucket) \ and supervision_time_bucket.violation_history_description: characteristics_with_person_details['violation_history_description'] = \ supervision_time_bucket.violation_history_description all_combinations.append(characteristics_with_person_details) return all_combinations