فهرست منبع

feat: _upload() returns a reasoncollection instead of plain boolean

trgiangdo 10 ماه پیش
والد
کامیت
474a66f719

+ 18 - 8
taipy/core/data/_file_datanode_mixin.py

@@ -17,8 +17,10 @@ from os.path import isfile
 from typing import Any, Callable, Dict, Optional
 
 from taipy.config.config import Config
+from taipy.logger._taipy_logger import _TaipyLogger
 
 from .._entity._reload import _self_reload
+from ..reason import InvalidUploadFile, ReasonCollection, UploadFileCanNotBeRead
 from .data_node import DataNode
 from .data_node_id import Edit
 
@@ -34,6 +36,8 @@ class _FileDataNodeMixin(object):
     _DEFAULT_PATH_KEY = "default_path"
     _IS_GENERATED_KEY = "is_generated"
 
+    __logger = _TaipyLogger._get_logger()
+
     def __init__(self, properties: Dict) -> None:
         self._path: str = properties.get(self._PATH_KEY, properties.get(self._DEFAULT_PATH_KEY))
         self._is_generated: bool = properties.get(self._IS_GENERATED_KEY, self._path is None)
@@ -104,7 +108,7 @@ class _FileDataNodeMixin(object):
 
         return ""
 
-    def _upload(self, path: str, upload_checker: Optional[Callable[[str, Any], bool]] = None) -> bool:
+    def _upload(self, path: str, upload_checker: Optional[Callable[[str, Any], bool]] = None) -> ReasonCollection:
         """Upload a file data to the data node.
 
         Parameters:
@@ -118,16 +122,22 @@ class _FileDataNodeMixin(object):
         """
         from ._data_manager_factory import _DataManagerFactory
 
+        reason_collection = ReasonCollection()
+
         upload_path = pathlib.Path(path)
 
-        if upload_checker is not None:
-            try:
-                upload_data = self._read_from_path(str(upload_path))
-            except Exception:
-                return False
+        try:
+            upload_data = self._read_from_path(str(upload_path))
+        except Exception as err:
+            self.__logger.error(f"Error while uploading {upload_path.name} to data node {self.id}:")  # type: ignore[attr-defined]
+            self.__logger.error(f"Error: {err}")
+            reason_collection._add_reason(self.id, UploadFileCanNotBeRead(upload_path.name, self.id))  # type: ignore[attr-defined]
+            return reason_collection
 
+        if upload_checker is not None:
             if not upload_checker(upload_path.name, upload_data):
-                return False
+                reason_collection._add_reason(self.id, InvalidUploadFile(upload_path.name, self.id))  # type: ignore[attr-defined]
+                return reason_collection
 
         shutil.copy(upload_path, self.path)
 
@@ -135,7 +145,7 @@ class _FileDataNodeMixin(object):
         self.unlock_edit()  # type: ignore[attr-defined]
         _DataManagerFactory._build_manager()._set(self)  # type: ignore[arg-type]
 
-        return True
+        return reason_collection
 
     def _read_from_path(self, path: Optional[str] = None, **read_kwargs) -> Any:
         raise NotImplementedError

+ 2 - 0
taipy/core/reason/__init__.py

@@ -13,8 +13,10 @@ from .reason import (
     DataNodeEditInProgress,
     DataNodeIsNotWritten,
     EntityIsNotSubmittableEntity,
+    InvalidUploadFile,
     NotGlobalScope,
     Reason,
+    UploadFileCanNotBeRead,
     WrongConfigType,
 )
 from .reason_collection import ReasonCollection

+ 30 - 0
taipy/core/reason/reason.py

@@ -123,3 +123,33 @@ class NotGlobalScope(Reason):
 
     def __init__(self, config_id: str):
         Reason.__init__(self, f'Data node config "{config_id}" does not have GLOBAL scope')
+
+
+class UploadFileCanNotBeRead(Reason):
+    """
+    The uploaded file can not be read, therefore is not a valid data file for the data node.
+
+    Attributes:
+        file_name (str): The name of the file that was uploaded.
+        datanode_id (str): The datanode id that the file is intended to upload to.
+    """
+
+    def __init__(self, file_name: str, datanode_id: str):
+        Reason.__init__(
+            self,
+            f"The uploaded file {file_name} can not be read, "
+            f'therefore is not a valid data file for data node "{datanode_id}"',
+        )
+
+
+class InvalidUploadFile(Reason):
+    """
+    The uploaded file has invalid data, therefore is not a valid data file for the data node.
+
+    Attributes:
+        file_name (str): The name of the file that was uploaded.
+        datanode_id (str): The datanode id that the file is intended to upload to.
+    """
+
+    def __init__(self, file_name: str, datanode_id: str):
+        Reason.__init__(self, f'The uploaded file {file_name} has invalid data for data node "{datanode_id}"')

+ 46 - 12
tests/core/data/test_csv_data_node.py

@@ -210,16 +210,33 @@ class TestCSVDataNode:
         def check_data_column(upload_path, upload_data):
             return upload_path.endswith(".csv") and upload_data.columns.tolist() == ["a", "b", "c"]
 
-        wrong_format_not_csv_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_csv").strpath
-        old_data.to_csv(wrong_format_not_csv_path, index=False)
-        wrong_format_csv_path = tmpdir_factory.mktemp("data").join("wrong_format_df.csv").strpath
-        pd.DataFrame([{"a": 1, "b": 2, "d": 3}, {"a": 4, "b": 5, "d": 6}]).to_csv(wrong_format_csv_path, index=False)
+        not_exists_csv_path = tmpdir_factory.mktemp("data").join("not_exists.csv").strpath
+        reasons = dn._upload(not_exists_csv_path, upload_checker=check_data_column)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0]) == "The uploaded file not_exists.csv can not be read,"
+            f' therefore is not a valid data file for data node "{dn.id}"'
+        )
 
+        not_csv_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_csv").strpath
+        old_data.to_csv(not_csv_path, index=False)
         # The upload should fail when the file is not a csv
-        assert not dn._upload(wrong_format_not_csv_path, upload_checker=check_data_column)
+        reasons = dn._upload(not_csv_path, upload_checker=check_data_column)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.not_csv has invalid data for data node "{dn.id}"'
+        )
 
+        wrong_format_csv_path = tmpdir_factory.mktemp("data").join("wrong_format_df.csv").strpath
+        pd.DataFrame([{"a": 1, "b": 2, "d": 3}, {"a": 4, "b": 5, "d": 6}]).to_csv(wrong_format_csv_path, index=False)
         # The upload should fail when check_data_column() return False
-        assert not dn._upload(wrong_format_csv_path, upload_checker=check_data_column)
+        reasons = dn._upload(wrong_format_csv_path, upload_checker=check_data_column)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.csv has invalid data for data node "{dn.id}"'
+        )
 
         assert_frame_equal(dn.read(), old_data)  # The content of the dn should not change when upload fails
         assert dn.last_edit_date == old_last_edit_date  # The last edit date should not change when upload fails
@@ -243,16 +260,33 @@ class TestCSVDataNode:
         def check_data_is_positive(upload_path, upload_data):
             return upload_path.endswith(".csv") and np.all(upload_data > 0)
 
-        wrong_format_not_csv_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_csv").strpath
-        pd.DataFrame(old_data).to_csv(wrong_format_not_csv_path, index=False)
-        wrong_format_csv_path = tmpdir_factory.mktemp("data").join("wrong_format_df.csv").strpath
-        pd.DataFrame(np.array([[-1, 2, 3], [-4, -5, -6]])).to_csv(wrong_format_csv_path, index=False)
+        not_exists_csv_path = tmpdir_factory.mktemp("data").join("not_exists.csv").strpath
+        reasons = dn._upload(not_exists_csv_path, upload_checker=check_data_is_positive)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0]) == "The uploaded file not_exists.csv can not be read"
+            f', therefore is not a valid data file for data node "{dn.id}"'
+        )
 
+        not_csv_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_csv").strpath
+        pd.DataFrame(old_data).to_csv(not_csv_path, index=False)
         # The upload should fail when the file is not a csv
-        assert not dn._upload(wrong_format_not_csv_path, upload_checker=check_data_is_positive)
+        reasons = dn._upload(not_csv_path, upload_checker=check_data_is_positive)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.not_csv has invalid data for data node "{dn.id}"'
+        )
 
+        wrong_format_csv_path = tmpdir_factory.mktemp("data").join("wrong_format_df.csv").strpath
+        pd.DataFrame(np.array([[-1, 2, 3], [-4, -5, -6]])).to_csv(wrong_format_csv_path, index=False)
         # The upload should fail when check_data_is_positive() return False
-        assert not dn._upload(wrong_format_csv_path, upload_checker=check_data_is_positive)
+        reasons = dn._upload(wrong_format_csv_path, upload_checker=check_data_is_positive)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.csv has invalid data for data node "{dn.id}"'
+        )
 
         np.array_equal(dn.read(), old_data)  # The content of the dn should not change when upload fails
         assert dn.last_edit_date == old_last_edit_date  # The last edit date should not change when upload fails

+ 45 - 12
tests/core/data/test_excel_data_node.py

@@ -408,16 +408,33 @@ class TestExcelDataNode:
             """
             return upload_path.endswith(".xlsx") and upload_data["Sheet1"].columns.tolist() == ["a", "b", "c"]
 
-        wrong_format_not_xlsx_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_xlsx").strpath
-        old_data.to_csv(wrong_format_not_xlsx_path, index=False)
-        wrong_format_xlsx_path = tmpdir_factory.mktemp("data").join("wrong_format_df.xlsx").strpath
-        pd.DataFrame([{"a": 1, "b": 2, "d": 3}, {"a": 4, "b": 5, "d": 6}]).to_excel(wrong_format_xlsx_path, index=False)
+        not_exists_xlsx_path = tmpdir_factory.mktemp("data").join("not_exists.xlsx").strpath
+        reasons = dn._upload(not_exists_xlsx_path, upload_checker=check_data_column)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0]) == "The uploaded file not_exists.xlsx can not be read,"
+            f' therefore is not a valid data file for data node "{dn.id}"'
+        )
 
+        not_xlsx_path = tmpdir_factory.mktemp("data").join("wrong_format_df.xlsm").strpath
+        old_data.to_excel(not_xlsx_path, index=False)
         # The upload should fail when the file is not a xlsx
-        assert not dn._upload(wrong_format_not_xlsx_path, upload_checker=check_data_column)
+        reasons = dn._upload(not_xlsx_path, upload_checker=check_data_column)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.xlsm has invalid data for data node "{dn.id}"'
+        )
 
+        wrong_format_xlsx_path = tmpdir_factory.mktemp("data").join("wrong_format_df.xlsx").strpath
+        pd.DataFrame([{"a": 1, "b": 2, "d": 3}, {"a": 4, "b": 5, "d": 6}]).to_excel(wrong_format_xlsx_path, index=False)
         # The upload should fail when check_data_column() return False
-        assert not dn._upload(wrong_format_xlsx_path, upload_checker=check_data_column)
+        reasons = dn._upload(wrong_format_xlsx_path, upload_checker=check_data_column)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.xlsx has invalid data for data node "{dn.id}"'
+        )
 
         assert_frame_equal(dn.read()["Sheet1"], old_data)  # The content of the dn should not change when upload fails
         assert dn.last_edit_date == old_last_edit_date  # The last edit date should not change when upload fails
@@ -441,16 +458,32 @@ class TestExcelDataNode:
         def check_data_is_positive(upload_path, upload_data):
             return upload_path.endswith(".xlsx") and np.all(upload_data["Sheet1"] > 0)
 
-        wrong_format_not_excel_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_excel").strpath
-        pd.DataFrame(old_data).to_csv(wrong_format_not_excel_path, index=False)
-        wrong_format_excel_path = tmpdir_factory.mktemp("data").join("wrong_format_df.xlsx").strpath
-        pd.DataFrame(np.array([[-1, 2, 3], [-4, -5, -6]])).to_excel(wrong_format_excel_path, index=False)
+        not_exists_xlsx_path = tmpdir_factory.mktemp("data").join("not_exists.xlsx").strpath
+        reasons = dn._upload(not_exists_xlsx_path, upload_checker=check_data_is_positive)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0]) == "The uploaded file not_exists.xlsx can not be read,"
+            f' therefore is not a valid data file for data node "{dn.id}"'
+        )
 
+        wrong_format_not_excel_path = tmpdir_factory.mktemp("data").join("wrong_format_df.xlsm").strpath
+        pd.DataFrame(old_data).to_excel(wrong_format_not_excel_path, index=False)
         # The upload should fail when the file is not a excel
-        assert not dn._upload(wrong_format_not_excel_path, upload_checker=check_data_is_positive)
+        reasons = dn._upload(wrong_format_not_excel_path, upload_checker=check_data_is_positive)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.xlsm has invalid data for data node "{dn.id}"'
+        )
 
+        not_xlsx_path = tmpdir_factory.mktemp("data").join("wrong_format_df.xlsx").strpath
+        pd.DataFrame(np.array([[-1, 2, 3], [-4, -5, -6]])).to_excel(not_xlsx_path, index=False)
         # The upload should fail when check_data_is_positive() return False
-        assert not dn._upload(wrong_format_excel_path, upload_checker=check_data_is_positive)
+        reasons = dn._upload(not_xlsx_path, upload_checker=check_data_is_positive)
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.xlsx has invalid data for data node "{dn.id}"'
+        )
 
         np.array_equal(dn.read()["Sheet1"], old_data)  # The content of the dn should not change when upload fails
         assert dn.last_edit_date == old_last_edit_date  # The last edit date should not change when upload fails

+ 25 - 6
tests/core/data/test_json_data_node.py

@@ -411,16 +411,35 @@ class TestJSONDataNode:
             all_column_is_abc = all(data.keys() == {"a", "b", "c"} for data in upload_data)
             return upload_path.endswith(".json") and all_column_is_abc
 
-        wrong_format_not_json_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_json").strpath
-        wrong_format_json_path = tmpdir_factory.mktemp("data").join("wrong_format_df.json").strpath
-        with open(wrong_format_not_json_path, "w") as f:
-            json.dump([{"a": 1, "b": 2, "d": 3}, {"a": 4, "b": 5, "d": 6}], f)
+        not_exists_json_path = tmpdir_factory.mktemp("data").join("not_exists.json").strpath
+        reasons = dn._upload(not_exists_json_path, upload_checker=check_data_keys)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0]) == "The uploaded file not_exists.json can not be read,"
+            f' therefore is not a valid data file for data node "{dn.id}"'
+        )
 
+        not_json_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_json").strpath
+        with open(not_json_path, "w") as f:
+            json.dump([{"a": 1, "b": 2, "d": 3}, {"a": 4, "b": 5, "d": 6}], f)
         # The upload should fail when the file is not a json
-        assert not dn._upload(wrong_format_not_json_path, upload_checker=check_data_keys)
+        reasons = dn._upload(not_json_path, upload_checker=check_data_keys)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.not_json has invalid data for data node "{dn.id}"'
+        )
 
+        wrong_format_json_path = tmpdir_factory.mktemp("data").join("wrong_format_df.json").strpath
+        with open(wrong_format_json_path, "w") as f:
+            json.dump([{"a": 1, "b": 2, "d": 3}, {"a": 4, "b": 5, "d": 6}], f)
         # The upload should fail when check_data_keys() return False
-        assert not dn._upload(wrong_format_json_path, upload_checker=check_data_keys)
+        reasons = dn._upload(wrong_format_json_path, upload_checker=check_data_keys)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.json has invalid data for data node "{dn.id}"'
+        )
 
         assert dn.read() == old_data  # The content of the dn should not change when upload fails
         assert dn.last_edit_date == old_last_edit_date  # The last edit date should not change when upload fails

+ 46 - 14
tests/core/data/test_parquet_data_node.py

@@ -267,18 +267,35 @@ class TestParquetDataNode:
         def check_data_column(upload_path, upload_data):
             return upload_path.endswith(".parquet") and upload_data.columns.tolist() == ["a", "b", "c"]
 
-        wrong_format_not_parquet_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_parquet").strpath
-        old_data.to_parquet(wrong_format_not_parquet_path, index=False)
-        wrong_format_parquet_path = tmpdir_factory.mktemp("data").join("wrong_format_df.parquet").strpath
-        pd.DataFrame([{"a": 1, "b": 2, "d": 3}, {"a": 4, "b": 5, "d": 6}]).to_parquet(
-            wrong_format_parquet_path, index=False
+        not_exists_parquet_path = tmpdir_factory.mktemp("data").join("not_exists.parquet").strpath
+        reasons = dn._upload(not_exists_parquet_path, upload_checker=check_data_column)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0]) == "The uploaded file not_exists.parquet can not be read,"
+            f' therefore is not a valid data file for data node "{dn.id}"'
         )
 
+        not_parquet_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_parquet").strpath
+        old_data.to_parquet(not_parquet_path, index=False)
         # The upload should fail when the file is not a parquet
-        assert not dn._upload(wrong_format_not_parquet_path, upload_checker=check_data_column)
+        reasons = dn._upload(not_parquet_path, upload_checker=check_data_column)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.not_parquet has invalid data for data node "{dn.id}"'
+        )
 
+        wrong_format_parquet_path = tmpdir_factory.mktemp("data").join("wrong_format_df.parquet").strpath
+        pd.DataFrame([{"a": 1, "b": 2, "d": 3}, {"a": 4, "b": 5, "d": 6}]).to_parquet(
+            wrong_format_parquet_path, index=False
+        )
         # The upload should fail when check_data_column() return False
-        assert not dn._upload(wrong_format_parquet_path, upload_checker=check_data_column)
+        reasons = dn._upload(wrong_format_parquet_path, upload_checker=check_data_column)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.parquet has invalid data for data node "{dn.id}"'
+        )
 
         assert_frame_equal(dn.read(), old_data)  # The content of the dn should not change when upload fails
         assert dn.last_edit_date == old_last_edit_date  # The last edit date should not change when upload fails
@@ -302,18 +319,33 @@ class TestParquetDataNode:
         def check_data_is_positive(upload_path, upload_data):
             return upload_path.endswith(".parquet") and np.all(upload_data > 0)
 
-        wrong_format_not_parquet_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_parquet").strpath
-        pd.DataFrame(old_data, columns=["a", "b", "c"]).to_parquet(wrong_format_not_parquet_path, index=False)
-        wrong_format_parquet_path = tmpdir_factory.mktemp("data").join("wrong_format_df.parquet").strpath
-        pd.DataFrame(np.array([[-1, 2, 3], [-4, -5, -6]]), columns=["a", "b", "c"]).to_parquet(
-            wrong_format_parquet_path, index=False
+        not_exists_parquet_path = tmpdir_factory.mktemp("data").join("not_exists.parquet").strpath
+        reasons = dn._upload(not_exists_parquet_path, upload_checker=check_data_is_positive)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0]) == "The uploaded file not_exists.parquet can not be read,"
+            f' therefore is not a valid data file for data node "{dn.id}"'
         )
 
+        not_parquet_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_parquet").strpath
+        pd.DataFrame(old_data, columns=["a", "b", "c"]).to_parquet(not_parquet_path, index=False)
         # The upload should fail when the file is not a parquet
-        assert not dn._upload(wrong_format_not_parquet_path, upload_checker=check_data_is_positive)
+        reasons = dn._upload(not_parquet_path, upload_checker=check_data_is_positive)
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.not_parquet has invalid data for data node "{dn.id}"'
+        )
 
+        wrong_format_parquet_path = tmpdir_factory.mktemp("data").join("wrong_format_df.parquet").strpath
+        pd.DataFrame(np.array([[-1, 2, 3], [-4, -5, -6]]), columns=["a", "b", "c"]).to_parquet(
+            wrong_format_parquet_path, index=False
+        )
         # The upload should fail when check_data_is_positive() return False
-        assert not dn._upload(wrong_format_parquet_path, upload_checker=check_data_is_positive)
+        reasons = dn._upload(wrong_format_parquet_path, upload_checker=check_data_is_positive)
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.parquet has invalid data for data node "{dn.id}"'
+        )
 
         np.array_equal(dn.read(), old_data)  # The content of the dn should not change when upload fails
         assert dn.last_edit_date == old_last_edit_date  # The last edit date should not change when upload fails

+ 25 - 6
tests/core/data/test_pickle_data_node.py

@@ -233,16 +233,35 @@ class TestPickleDataNodeEntity:
         def check_data_column(upload_path, upload_data):
             return upload_path.endswith(".p") and upload_data.columns.tolist() == ["a", "b", "c"]
 
-        wrong_format_not_pickle_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_pickle").strpath
-        wrong_format_pickle_path = tmpdir_factory.mktemp("data").join("wrong_format_df.p").strpath
-        with open(str(wrong_format_pickle_path), "wb") as f:
-            pickle.dump(pd.DataFrame([{"a": 1, "b": 2, "d": 3}, {"a": 4, "b": 5, "d": 6}]), f)
+        not_exists_json_path = tmpdir_factory.mktemp("data").join("not_exists.json").strpath
+        reasons = dn._upload(not_exists_json_path, upload_checker=check_data_column)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0]) == "The uploaded file not_exists.json can not be read,"
+            f' therefore is not a valid data file for data node "{dn.id}"'
+        )
 
+        not_pickle_path = tmpdir_factory.mktemp("data").join("wrong_format_df.not_pickle").strpath
+        with open(str(not_pickle_path), "wb") as f:
+            pickle.dump(pd.DataFrame([{"a": 1, "b": 2, "d": 3}, {"a": 4, "b": 5, "d": 6}]), f)
         # The upload should fail when the file is not a pickle
-        assert not dn._upload(wrong_format_not_pickle_path, upload_checker=check_data_column)
+        reasons = dn._upload(not_pickle_path, upload_checker=check_data_column)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.not_pickle has invalid data for data node "{dn.id}"'
+        )
 
+        wrong_format_pickle_path = tmpdir_factory.mktemp("data").join("wrong_format_df.p").strpath
+        with open(str(wrong_format_pickle_path), "wb") as f:
+            pickle.dump(pd.DataFrame([{"a": 1, "b": 2, "d": 3}, {"a": 4, "b": 5, "d": 6}]), f)
         # The upload should fail when check_data_column() return False
-        assert not dn._upload(wrong_format_pickle_path, upload_checker=check_data_column)
+        reasons = dn._upload(wrong_format_pickle_path, upload_checker=check_data_column)
+        assert bool(reasons) is False
+        assert (
+            str(list(reasons._reasons[dn.id])[0])
+            == f'The uploaded file wrong_format_df.p has invalid data for data node "{dn.id}"'
+        )
 
         assert_frame_equal(dn.read(), old_data)  # The content of the dn should not change when upload fails
         assert dn.last_edit_date == old_last_edit_date  # The last edit date should not change when upload fails