Repository: kedro-org/kedro

Issue:
[DataCatalog]: Error message is confusing when kedro-dataset is not installed
## Description
When `kedro-datasets` is not installed the error message one gets is not informative.

We propose enhancing the error message to provide a clear message on the root cause of the failure - when dataset dependencies are missing.

Relates to https://github.com/kedro-org/kedro/issues/2401

## Context
Currently, users are required to install all dependencies even for unused datasets (in case you want to run pipeline partially or do not load some datasets when standalone catalog usage). The error message generated when some datasets are not installed is unclear, making it difficult for users to understand why the pipeline fails. 

Example of the current error message:

```
DatasetError: An exception occurred when parsing config for dataset 'companies':
Class 'pandas.CSVDataset' not found, is this a typo?
```

This error occurs during dataset configuration parsing and lacks clarity, not suggesting the straightforward solution of installing the necessary package. This can lead to confusion and delays as users may not immediately realize that the issue is due to missing software rather than a typo in their configuration.


Discussion:
merelcht: I'm happy with this approach 👍 
datajoely: >In the past we try to improve (3) but (1)/(2) remains confusing. I wonder if it is simpler to list out all 3 cases explicitly and avoid trying to be too smart?

Explicit is better than implicit
ankatiyar: @noklam It seems like if an optional requirement is missing, this error is not triggered. It is when trying to run the project, the error that shows up is when the dataset is being loaded(or saved) -
```
kedro.io.core.DatasetError: Failed while loading data from data set ExcelDataset(filepath=/Users/ankita_katiyar/kedro_projects/demo/data/01_raw/shuttles.xlsx, load_args={'engine': openpyxl}, protocol=file, save_args={'index': False}, writer_args={'engine': openpyxl}).
Missing optional dependency 'openpyxl'.  Use pip or conda to install openpyxl.
```
datajoely: This is great - in the past this was an issue because sometimes it was stupid to install all of spark just to just run the Pandas parts. 

I wonder if it's finally time for us to may something like `kedro run --dry` a 1st class command for validating if a session is 'runnable'. It would be useful for our own testing and for users to build an integration test.
noklam: @ankatiyar yes, the error is triggered in different place. Since this issue only focus on the typo / kedro-datasets missing case, I have approved this now. 

Patch:
diff --git a/RELEASE.md b/RELEASE.md
index 262d8e37..36fd39ea 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -4,6 +4,7 @@
 
 ## Bug fixes and other changes
 * Updated error message for invalid catalog entries.
+* Updated error message for catalog entries when the dataset class is not found with hints on how to resolve the issue.
 * Fixed a bug in the `DataCatalog` `shallow_copy()` method to ensure it returns the type of the used catalog and doesn't cast it to `DataCatalog`.
 
 ## Breaking changes to the API
diff --git a/kedro/io/core.py b/kedro/io/core.py
index ec1b25bf..ff388a50 100644
--- a/kedro/io/core.py
+++ b/kedro/io/core.py
@@ -155,7 +155,7 @@ class AbstractDataset(abc.ABC, Generic[_DI, _DO]):
         except Exception as exc:
             raise DatasetError(
                 f"An exception occurred when parsing config "
-                f"for dataset '{name}':\n{str(exc)}."
+                f"for dataset '{name}':\n{str(exc)}"
             ) from exc
 
         try:
@@ -406,7 +406,23 @@ def parse_dataset_definition(
                 class_obj = tmp
                 break
         else:
-            raise DatasetError(f"Class '{dataset_type}' not found, is this a typo?")
+            hint = ""
+            if "DataSet" in dataset_type:
+                hint = (  # pragma: no cover # To remove when we drop support for python 3.8
+                    "Hint: If you are trying to use a dataset from `kedro-datasets`>=2.0.0, "
+                    "make sure that the dataset name uses the `Dataset` spelling instead of `DataSet`."
+                )
+            else:
+                hint = (
+                    "Hint: If you are trying to use a dataset from `kedro-datasets`, "
+                    "make sure that the package is installed in your current environment. "
+                    "You can do so by running `pip install kedro-datasets` or "
+                    "`pip install kedro-datasets[<dataset-group>]` to install `kedro-datasets` along with "
+                    "related dependencies for the specific dataset group."
+                )
+            raise DatasetError(
+                f"Class '{dataset_type}' not found, is this a typo?" f"\n{hint}"
+            )
 
     if not class_obj:
         class_obj = dataset_type


Test patch:
diff --git a/tests/io/test_data_catalog.py b/tests/io/test_data_catalog.py
index 26c3659c..1deecb7a 100644
--- a/tests/io/test_data_catalog.py
+++ b/tests/io/test_data_catalog.py
@@ -1,5 +1,6 @@
 import logging
 import re
+import sys
 from copy import deepcopy
 from datetime import datetime, timezone
 from pathlib import Path
@@ -503,7 +504,24 @@ class TestDataCatalogFromConfig:
 
         pattern = (
             "An exception occurred when parsing config for dataset 'boats':\n"
-            "Class 'kedro.io.CSVDatasetInvalid' not found"
+            "Class 'kedro.io.CSVDatasetInvalid' not found, is this a typo?"
+        )
+        with pytest.raises(DatasetError, match=re.escape(pattern)):
+            DataCatalog.from_config(**sane_config)
+
+    @pytest.mark.skipif(
+        sys.version_info < (3, 9),
+        reason="for python 3.8 kedro-datasets version 1.8 is used which has the old spelling",
+    )
+    def test_config_incorrect_spelling(self, sane_config):
+        """Check hint if the type uses the old DataSet spelling"""
+        sane_config["catalog"]["boats"]["type"] = "pandas.CSVDataSet"
+
+        pattern = (
+            "An exception occurred when parsing config for dataset 'boats':\n"
+            "Class 'pandas.CSVDataSet' not found, is this a typo?"
+            "\nHint: If you are trying to use a dataset from `kedro-datasets`>=2.0.0,"
+            " make sure that the dataset name uses the `Dataset` spelling instead of `DataSet`."
         )
         with pytest.raises(DatasetError, match=re.escape(pattern)):
             DataCatalog.from_config(**sane_config)