Example #1
0
    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)
Example #2
0
    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)
Example #3
0
    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)
Example #4
0
    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)
Example #5
0
    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)
Example #6
0
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
Example #7
0
    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