diff --git a/src/promptflow-devkit/promptflow/_sdk/operations/_local_storage_operations.py b/src/promptflow-devkit/promptflow/_sdk/operations/_local_storage_operations.py index a3437de5348..9a4ce5fbc3b 100644 --- a/src/promptflow-devkit/promptflow/_sdk/operations/_local_storage_operations.py +++ b/src/promptflow-devkit/promptflow/_sdk/operations/_local_storage_operations.py @@ -504,6 +504,13 @@ def _outputs_padding(df: "DataFrame", inputs_line_numbers: List[int]) -> "DataFr res = res.sort_values(by=LINE_NUMBER, ascending=True) return res + @staticmethod + def _fill_failed_outputs(df: "DataFrame") -> "DataFrame": + output_columns = [column for column in df.columns if column != LINE_NUMBER] + df = df.copy() + df[output_columns] = df[output_columns].astype(object) + return df.fillna(value="(Failed)") + def load_inputs_and_outputs(self) -> Tuple["DataFrame", "DataFrame"]: if not self._sdk_inputs_path.is_file() or not self._sdk_output_path.is_file(): inputs, outputs = self._collect_io_from_debug_info() @@ -513,7 +520,7 @@ def load_inputs_and_outputs(self) -> Tuple["DataFrame", "DataFrame"]: # if all line runs are failed, no need to fill if len(outputs) > 0: outputs = self._outputs_padding(outputs, inputs[LINE_NUMBER].tolist()) - outputs.fillna(value="(Failed)", inplace=True) # replace nan with explicit prompt + outputs = self._fill_failed_outputs(outputs) # replace nan with explicit prompt outputs = outputs.set_index(LINE_NUMBER) return inputs, outputs diff --git a/src/promptflow-devkit/tests/sdk_cli_test/unittests/test_local_storage_operations.py b/src/promptflow-devkit/tests/sdk_cli_test/unittests/test_local_storage_operations.py index 78e07b4516e..7cfc6c5156f 100644 --- a/src/promptflow-devkit/tests/sdk_cli_test/unittests/test_local_storage_operations.py +++ b/src/promptflow-devkit/tests/sdk_cli_test/unittests/test_local_storage_operations.py @@ -2,6 +2,8 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # --------------------------------------------------------- +import warnings + import pandas as pd import pytest @@ -34,3 +36,18 @@ def test_outputs_padding(self) -> None: assert df_with_padding.iloc[0].to_dict() == {LINE_NUMBER: 1, "col": "a"} assert df_with_padding.iloc[1].to_dict() == {LINE_NUMBER: 2, "col": "b"} assert df_with_padding.iloc[2].to_dict() == {LINE_NUMBER: 4, "col": ""} + + def test_outputs_padding_fill_failed_without_dtype_warning(self) -> None: + data = [ + {LINE_NUMBER: 1, "score": 0.5}, + ] + df = pd.DataFrame(data) + + df_with_padding = LocalStorageOperations._outputs_padding(df, inputs_line_numbers=[0, 1]) + with warnings.catch_warnings(record=True) as caught_warnings: + warnings.simplefilter("always") + df_with_padding = LocalStorageOperations._fill_failed_outputs(df_with_padding) + + assert len(caught_warnings) == 0 + assert df_with_padding.iloc[0].to_dict() == {LINE_NUMBER: 0, "score": "(Failed)"} + assert df_with_padding.iloc[1].to_dict() == {LINE_NUMBER: 1, "score": 0.5}