def test_get_class_names_from_class_mappings(self):
        config = parse_validate_deployment_config_file(
            self.deployment_config_multiclass)
        class_names = get_class_names_from_class_mapping(
            config["target"]["class_mapping"])
        assert class_names == ["GALAXY", "QSO", "STAR"]

        config = parse_validate_deployment_config_file(
            self.deployment_config_binary)
        class_names = get_class_names_from_class_mapping(
            config["target"]["class_mapping"])
        assert class_names == ["Iris-versicolor", "Iris-setosa"]
    def test_map_regression_prediction(self):
        d = {"Predictions": [1.2, 2.3, 3.4]}
        df = pd.DataFrame(data=d)
        config = parse_validate_deployment_config_file(
            self.deployment_config_regression)
        assert config["target"]["name"] == "MEDV"
        assert config["target"]["type"] == "Regression"

        response = build_pps_response_json_str(df, config,
                                               TargetType.REGRESSION)
        response_json = json.loads(response)
        assert isinstance(response_json, dict)
        assert "data" in response_json
        predictions_list = response_json["data"]
        assert isinstance(predictions_list, list)
        assert len(predictions_list) == df.shape[0]

        pred_iter = iter(predictions_list)
        for index, row in df.iterrows():
            pred_item = next(pred_iter)
            assert isinstance(pred_item, dict)
            assert pred_item["rowId"] == index
            assert pred_item["prediction"] == row[0]
            assert isinstance(pred_item["predictionValues"], list)
            assert len(pred_item["predictionValues"]) == 1
            assert pred_item["predictionValues"][0]["label"] == config[
                "target"]["name"]
            assert pred_item["predictionValues"][0]["value"] == row[0]
 def test_build_pps_response_json_str_bad_target(self):
     d = {"Predictions": [1.2, 2.3, 3.4]}
     df = pd.DataFrame(data=d)
     config = parse_validate_deployment_config_file(
         self.deployment_config_regression)
     with pytest.raises(DrumCommonException,
                        match="target type 'None' is not supported"):
         build_pps_response_json_str(df, config, None)
    def test_parse_deployment_config_file(self):
        not_json = '{"target: {"class_mapping": null, "missing_maps_to": null, "name": "MEDV", "prediction_threshold": 0.5, "type": "Regression" }}'
        no_target_json = '{"targe": {"class_mapping": null, "missing_maps_to": null, "name": "MEDV", "prediction_threshold": 0.5, "type": "Regression" }}'

        assert parse_validate_deployment_config_file(None) is None

        with NamedTemporaryFile(mode="w+") as f:
            f.write(not_json)
            f.flush()
            with pytest.raises(
                    DrumCommonException,
                    match="Failed to parse deployment config json file"):
                parse_validate_deployment_config_file(f.name)

        with NamedTemporaryFile(mode="w+") as f:
            f.write(no_target_json)
            f.flush()
            with pytest.raises(
                    DrumCommonException,
                    match=
                    "'target' section not found in deployment config json file",
            ):
                parse_validate_deployment_config_file(f.name)

        all_configs = [
            self.deployment_config_anomaly,
            self.deployment_config_regression,
            self.deployment_config_binary,
            self.deployment_config_multiclass,
        ]
        for config_path in all_configs:
            parse_validate_deployment_config_file(config_path)
    def test_map_multiclass_prediction(self):
        class_labels = ["QSO", "STAR", "GALAXY"]
        d = {
            class_labels[0]: [0.6, 0.2, 0.3],
            class_labels[1]: [0.3, 0.4, 0.5],
            class_labels[2]: [0.1, 0.4, 0.2],
        }
        df = pd.DataFrame(data=d)
        config = parse_validate_deployment_config_file(
            self.deployment_config_multiclass)
        assert config["target"]["name"] == "class"
        assert config["target"]["type"] == "Multiclass"

        response = build_pps_response_json_str(df, config,
                                               TargetType.MULTICLASS)
        response_json = json.loads(response)
        assert isinstance(response_json, dict)
        assert "data" in response_json
        predictions_list = response_json["data"]
        assert isinstance(predictions_list, list)
        assert len(predictions_list) == df.shape[0]

        pred_iter = iter(predictions_list)
        expected_pred_iterator = iter(["QSO", "GALAXY", "STAR"])
        for index, row in df.iterrows():
            pred_item = next(pred_iter)

            assert isinstance(pred_item, dict)
            assert pred_item["rowId"] == index

            assert pred_item["prediction"] == next(expected_pred_iterator)
            assert isinstance(pred_item["predictionValues"], list)
            assert len(pred_item["predictionValues"]) == 3

            # expected list must be formed in the [GALAXY, QSO, STAR] order as classes are ordered this way
            # in map_multiclass_predictions according to the class mapping in deployment document
            assert pred_item["predictionValues"] == [
                {
                    "label": class_labels[2],
                    "value": row[class_labels[2]]
                },
                {
                    "label": class_labels[0],
                    "value": row[class_labels[0]]
                },
                {
                    "label": class_labels[1],
                    "value": row[class_labels[1]]
                },
            ]
    def configure(self, params):
        super(PredictionServer, self).configure(params)
        self._code_dir = self._params.get("__custom_model_path__")
        self._show_perf = self._params.get("show_perf")
        self._run_language = RunLanguage(params.get("run_language"))
        self._target_type = TargetType(params[TARGET_TYPE_ARG_KEYWORD])

        self._stats_collector = StatsCollector(disable_instance=not self._show_perf)

        self._stats_collector.register_report(
            "run_predictor_total", "finish", StatsOperation.SUB, "start"
        )
        self._memory_monitor = MemoryMonitor(monitor_current_process=True)
        self._deployment_config = parse_validate_deployment_config_file(
            self._params["deployment_config"]
        )

        if self._run_language == RunLanguage.PYTHON:
            from datarobot_drum.drum.language_predictors.python_predictor.python_predictor import (
                PythonPredictor,
            )

            self._predictor = PythonPredictor()
        elif self._run_language == RunLanguage.JAVA:
            from datarobot_drum.drum.language_predictors.java_predictor.java_predictor import (
                JavaPredictor,
            )

            self._predictor = JavaPredictor()
        elif self._run_language == RunLanguage.JULIA:
            from datarobot_drum.drum.language_predictors.julia_predictor.julia_predictor import (
                JlPredictor,
            )

            self._predictor = JlPredictor()
        elif self._run_language == RunLanguage.R:
            # this import is here, because RPredictor imports rpy library,
            # which is not installed for Java and Python cases.
            from datarobot_drum.drum.language_predictors.r_predictor.r_predictor import RPredictor

            self._predictor = RPredictor()
        else:
            raise DrumCommonException(
                "Prediction server doesn't support language: {} ".format(self._run_language)
            )

        self._predictor.configure(params)
    def test_map_binary_prediction(self):
        positive_class = "Iris-setosa"
        negative_class = "Iris-versicolor"
        d = {positive_class: [0.6, 0.5, 0.2], negative_class: [0.4, 0.5, 0.8]}
        df = pd.DataFrame(data=d)
        config = parse_validate_deployment_config_file(
            self.deployment_config_binary)
        assert config["target"]["name"] == "Species"
        assert config["target"]["type"] == "Binary"

        response = build_pps_response_json_str(df, config, TargetType.BINARY)
        response_json = json.loads(response)
        assert isinstance(response_json, dict)
        assert "data" in response_json
        predictions_list = response_json["data"]
        assert isinstance(predictions_list, list)
        assert len(predictions_list) == df.shape[0]

        pred_iter = iter(predictions_list)
        for index, row in df.iterrows():
            pred_item = next(pred_iter)
            assert isinstance(pred_item, dict)
            assert pred_item["rowId"] == index
            assert pred_item["predictionThreshold"] == config["target"][
                "prediction_threshold"]
            assert (pred_item["prediction"] == "Iris-setosa"
                    if row[positive_class] > pred_item["predictionThreshold"]
                    else negative_class)
            assert isinstance(pred_item["predictionValues"], list)
            assert len(pred_item["predictionValues"]) == 2

            # expected list must be formed in the [positive_class, negative_class] order
            # as that's how it is generated in map_binary_prediction
            assert pred_item["predictionValues"] == [
                {
                    "label": positive_class,
                    "value": row[positive_class]
                },
                {
                    "label": negative_class,
                    "value": 1 - row[positive_class]
                },
            ]
    def configure(self, params):
        """
        @brief      It is called in within the 'deputy' context
        """
        super(UwsgiServing, self).configure(params)
        self._code_dir = self._params.get("__custom_model_path__")
        self._show_perf = self._params.get("show_perf")
        self._run_language = RunLanguage(params.get("run_language"))
        self._target_type = TargetType(params[TARGET_TYPE_ARG_KEYWORD])

        self._stats_collector = StatsCollector(
            disable_instance=not self._show_perf)

        self._stats_collector.register_report("run_predictor_total", "finish",
                                              StatsOperation.SUB, "start")
        self._memory_monitor = MemoryMonitor()
        self._deployment_config = parse_validate_deployment_config_file(
            self._params["deployment_config"])

        self._logger.info(
            "Configure component with input params, name: {}, params: {}".
            format(self.name(), params))