def test_include_in_monthly_metrics_after_end_date(self): calculation_month_upper_bound = date(2000, 1, 31) include = calculator_utils.include_in_output( year=2000, month=2, calculation_month_upper_bound=calculation_month_upper_bound, calculation_month_lower_bound=None, ) self.assertFalse(include)
def test_include_in_monthly_metrics(self): calculation_month_upper_bound = date(2000, 1, 31) include = calculator_utils.include_in_output( year=1999, month=11, calculation_month_upper_bound=calculation_month_upper_bound, calculation_month_lower_bound=None, ) self.assertTrue(include)
def test_include_in_monthly_metrics_one_month_run_exclude(self): calculation_month_upper_bound = date(1999, 12, 31) calculation_month_lower_bound = date(1999, 12, 1) include = calculator_utils.include_in_output( year=2000, month=1, calculation_month_upper_bound=calculation_month_upper_bound, calculation_month_lower_bound=calculation_month_lower_bound, ) self.assertFalse(include)
def test_include_in_monthly_metrics_before_lower_bound(self): calculation_month_upper_bound = date(2000, 1, 31) calculation_month_lower_bound = date(1999, 10, 1) include = calculator_utils.include_in_output( year=1990, month=4, calculation_month_upper_bound=calculation_month_upper_bound, calculation_month_lower_bound=calculation_month_lower_bound, ) self.assertFalse(include)
def test_include_in_monthly_metrics_month_of_end_date(self): calculation_month_upper_bound = date(2000, 1, 31) calculation_month_lower_bound = date(1999, 10, 1) include = calculator_utils.include_in_output( year=calculation_month_upper_bound.year, month=calculation_month_upper_bound.month, calculation_month_upper_bound=calculation_month_upper_bound, calculation_month_lower_bound=calculation_month_lower_bound, ) self.assertTrue(include)
def map_supervision_combinations( person: StatePerson, supervision_time_buckets: List[SupervisionTimeBucket], metric_inclusions: Dict[SupervisionMetricType, bool], calculation_end_month: Optional[str], calculation_month_count: int, person_metadata: PersonMetadata, ) -> List[Tuple[Dict[str, Any], Any]]: """Transforms SupervisionTimeBuckets and a StatePerson into metric combinations. Takes in a StatePerson and all of her SupervisionTimeBuckets and returns an array of "supervision combinations". These are key-value pairs where the key represents a specific metric and the value represents whether or not the person should be counted as a positive instance of that metric. This translates a particular time on supervision into many different supervision population metrics. Args: person: the StatePerson supervision_time_buckets: A list of SupervisionTimeBuckets for the given StatePerson. metric_inclusions: A dictionary where the keys are each SupervisionMetricType, and the values are boolean flags for whether or not to include that metric type in the calculations calculation_end_month: The year and month in YYYY-MM format of the last month for which metrics should be calculated. If unset, ends with the current month. calculation_month_count: The number of months (including the month of the calculation_end_month) to limit the monthly calculation output to. If set to -1, does not limit the calculations. person_metadata: Contains information about the StatePerson that is necessary for the metrics. Returns: A list of key-value tuples representing specific metric combinations and the value corresponding to that metric. """ metrics: List[Tuple[Dict[str, Any], Any]] = [] supervision_time_buckets.sort(key=attrgetter("year", "month")) calculation_month_upper_bound = get_calculation_month_upper_bound_date( calculation_end_month) calculation_month_lower_bound = get_calculation_month_lower_bound_date( calculation_month_upper_bound, calculation_month_count) for supervision_time_bucket in supervision_time_buckets: event_date = supervision_time_bucket.event_date if (isinstance(supervision_time_bucket, NonRevocationReturnSupervisionTimeBucket) and supervision_time_bucket.case_compliance): event_date = supervision_time_bucket.case_compliance.date_of_evaluation event_year = event_date.year event_month = event_date.month if not include_in_output( event_year, event_month, calculation_month_upper_bound, calculation_month_lower_bound, ): continue applicable_metric_types = BUCKET_TO_METRIC_TYPES.get( type(supervision_time_bucket)) if not applicable_metric_types: raise ValueError( "No metric types mapped to supervision_time_bucket of type {}". format(type(supervision_time_bucket))) for metric_type in applicable_metric_types: if not metric_inclusions[metric_type]: continue metric_class = METRIC_TYPE_TO_CLASS.get(metric_type) if not metric_class: raise ValueError( "No metric class for metric type {}".format(metric_type)) if include_event_in_metric(supervision_time_bucket, metric_type): characteristic_combo = characteristics_dict_builder( pipeline="supervision", event=supervision_time_bucket, metric_class=metric_class, person=person, event_date=event_date, person_metadata=person_metadata, ) metric_combo = augmented_combo_for_calculations( characteristic_combo, supervision_time_bucket.state_code, metric_type, event_year, event_month, ) value = value_for_metric_combo(supervision_time_bucket, metric_type) metrics.append((metric_combo, value)) return metrics
def produce_metrics( self, person: StatePerson, identifier_events: List[SupervisionEvent], metric_inclusions: Dict[SupervisionMetricType, bool], person_metadata: PersonMetadata, pipeline_type: PipelineType, pipeline_job_id: str, calculation_end_month: Optional[str] = None, calculation_month_count: int = -1, ) -> List[SupervisionMetric]: """Transforms SupervisionEvents and a StatePerson into SuperviisonMetrics. Takes in a StatePerson and all of their SupervisionEvents and returns an array of SupervisionMetrics. Args: person: the StatePerson identifier_events: A list of SupervisionEvents for the given StatePerson. metric_inclusions: A dictionary where the keys are each SupervisionMetricType, and the values are boolean flags for whether or not to include that metric type in the calculations calculation_end_month: The year and month in YYYY-MM format of the last month for which metrics should be calculated. If unset, ends with the current month. calculation_month_count: The number of months (including the month of the calculation_end_month) to limit the monthly calculation output to. If set to -1, does not limit the calculations. person_metadata: Contains information about the StatePerson that is necessary for the metrics. pipeline_job_id: The job_id of the pipeline that is currently running. Returns: A list of SupervisionMetrics. """ metrics: List[SupervisionMetric] = [] identifier_events.sort(key=attrgetter("year", "month")) calculation_month_upper_bound = get_calculation_month_upper_bound_date( calculation_end_month) calculation_month_lower_bound = get_calculation_month_lower_bound_date( calculation_month_upper_bound, calculation_month_count) for event in identifier_events: event_date = event.event_date if (isinstance( event, SupervisionPopulationEvent, ) and event.case_compliance): event_date = event.case_compliance.date_of_evaluation event_year = event_date.year event_month = event_date.month if not include_in_output( event_year, event_month, calculation_month_upper_bound, calculation_month_lower_bound, ): continue applicable_metric_types = self.event_to_metric_types.get( type(event)) if not applicable_metric_types: raise ValueError( "No metric types mapped to event of type {}".format( type(event))) for metric_type in applicable_metric_types: if not metric_inclusions[metric_type]: continue metric_class = self.metric_type_to_class.get(metric_type) if not metric_class: raise ValueError( "No metric class for metric type {}".format( metric_type)) if self.include_event_in_metric(event, metric_type): additional_attributes: Dict[str, Any] = {} if (isinstance( event, ProjectedSupervisionCompletionEvent, ) and metric_type == SupervisionMetricType. SUPERVISION_SUCCESSFUL_SENTENCE_DAYS_SERVED): additional_attributes[ "days_served"] = event.sentence_days_served metric = build_metric( pipeline=pipeline_type.value.lower(), event=event, metric_class=metric_class, person=person, event_date=event_date, person_metadata=person_metadata, pipeline_job_id=pipeline_job_id, additional_attributes=additional_attributes, ) if not isinstance(metric, SupervisionMetric): raise ValueError( f"Unexpected metric type {type(metric)}. " "All metrics should be SupervisionMetric.") metrics.append(metric) return metrics