prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  No specific error when dataset tries to import a non-installed module
  When a dataset script tries to import a module/library that is not installed, there is no informative error message.
  
  See:
  - #1067 
  - #1068
  
  Related to:
  - #976
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `services/worker/src/worker/job_runners/config_names.py`
  Content:
  ```
  1 # SPDX-License-Identifier: Apache-2.0
  2 # Copyright 2022 The HuggingFace Authors.
  3 
  4 import logging
  5 from http import HTTPStatus
  6 from typing import Any, List, Literal, Mapping, Optional, TypedDict, Union
  7 
  8 from datasets import get_dataset_config_names
  9 from datasets.data_files import EmptyDatasetError as _EmptyDatasetError
  10 from libcommon.constants import PROCESSING_STEP_CONFIG_NAMES_VERSION
  11 from libcommon.simple_cache import SplitFullName
  12 
  13 from worker.job_runner import CompleteJobResult, JobRunnerError, ParameterMissingError
  14 from worker.job_runners._datasets_based_job_runner import DatasetsBasedJobRunner
  15 
  16 ConfigNamesJobRunnerErrorCode = Literal["EmptyDatasetError", "ConfigNamesError"]
  17 
  18 
  19 class ConfigNamesJobRunnerError(JobRunnerError):
  20     """Base class for job runner exceptions."""
  21 
  22     def __init__(
  23         self,
  24         message: str,
  25         status_code: HTTPStatus,
  26         code: ConfigNamesJobRunnerErrorCode,
  27         cause: Optional[BaseException] = None,
  28         disclose_cause: bool = False,
  29     ):
  30         super().__init__(
  31             message=message, status_code=status_code, code=code, cause=cause, disclose_cause=disclose_cause
  32         )
  33 
  34 
  35 class EmptyDatasetError(ConfigNamesJobRunnerError):
  36     """Raised when the dataset has no data."""
  37 
  38     def __init__(self, message: str, cause: Optional[BaseException] = None):
  39         super().__init__(message, HTTPStatus.INTERNAL_SERVER_ERROR, "EmptyDatasetError", cause, True)
  40 
  41 
  42 class ConfigNamesError(ConfigNamesJobRunnerError):
  43     """Raised when the config names could not be fetched."""
  44 
  45     def __init__(self, message: str, cause: Optional[BaseException] = None):
  46         super().__init__(message, HTTPStatus.INTERNAL_SERVER_ERROR, "ConfigNamesError", cause, True)
  47 
  48 
  49 class ConfigNameItem(TypedDict):
  50     dataset: str
  51     config: str
  52 
  53 
  54 class ConfigNamesResponse(TypedDict):
  55     config_names: List[ConfigNameItem]
  56 
  57 
  58 def compute_config_names_response(
  59     dataset: str,
  60     hf_token: Optional[str] = None,
  61 ) -> ConfigNamesResponse:
  62     """
  63     Get the response of /config-names for one specific dataset on huggingface.co.
  64     Dataset can be private or gated if you pass an acceptable token.
  65 
  66     It is assumed that the dataset exists and can be accessed using the token.
  67 
  68     Args:
  69         dataset (`str`):
  70             A namespace (user or an organization) and a repo name separated
  71             by a `/`.
  72         hf_token (`str`, *optional*):
  73             An authentication token (See https://huggingface.co/settings/token)
  74     Returns:
  75         `ConfigNamesResponse`: An object with the list of config names.
  76     <Tip>
  77     Raises the following errors:
  78         - [`~job_runners.config_names.EmptyDatasetError`]
  79           The dataset is empty.
  80         - [`~job_runners.config_names.ConfigNamesError`]
  81           If the list of configs could not be obtained using the datasets library.
  82     </Tip>
  83     """
  84     logging.info(f"get config names for dataset={dataset}")
  85     use_auth_token: Union[bool, str, None] = hf_token if hf_token is not None else False
  86     # get the list of splits in streaming mode
  87     try:
  88         config_name_items: List[ConfigNameItem] = [
  89             {"dataset": dataset, "config": str(config)}
  90             for config in sorted(get_dataset_config_names(path=dataset, use_auth_token=use_auth_token))
  91         ]
  92     except _EmptyDatasetError as err:
  93         raise EmptyDatasetError("The dataset is empty.", cause=err) from err
  94     except Exception as err:
  95         raise ConfigNamesError("Cannot get the config names for the dataset.", cause=err) from err
  96     return ConfigNamesResponse(config_names=config_name_items)
  97 
  98 
  99 class ConfigNamesJobRunner(DatasetsBasedJobRunner):
  100     @staticmethod
  101     def get_job_type() -> str:
  102         return "/config-names"
  103 
  104     @staticmethod
  105     def get_job_runner_version() -> int:
  106         return PROCESSING_STEP_CONFIG_NAMES_VERSION
  107 
  108     def compute(self) -> CompleteJobResult:
  109         if self.dataset is None:
  110             raise ParameterMissingError("'dataset' parameter is required")
  111         return CompleteJobResult(
  112             compute_config_names_response(dataset=self.dataset, hf_token=self.common_config.hf_token)
  113         )
  114 
  115     def get_new_splits(self, content: Mapping[str, Any]) -> set[SplitFullName]:
  116         """Get the set of new splits, from the content created by the compute."""
  117         return {SplitFullName(dataset=s["dataset"], config=s["config"], split=None) for s in content["config_names"]}
  118
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/services/worker/src/worker/job_runners/config_names.py b/services/worker/src/worker/job_runners/config_names.py
  --- a/services/worker/src/worker/job_runners/config_names.py
  +++ b/services/worker/src/worker/job_runners/config_names.py
  @@ -13,7 +13,7 @@
   from worker.job_runner import CompleteJobResult, JobRunnerError, ParameterMissingError
   from worker.job_runners._datasets_based_job_runner import DatasetsBasedJobRunner
   
  -ConfigNamesJobRunnerErrorCode = Literal["EmptyDatasetError", "ConfigNamesError"]
  +ConfigNamesJobRunnerErrorCode = Literal["EmptyDatasetError", "DatasetModuleNotInstalledError", "ConfigNamesError"]
   
   
   class ConfigNamesJobRunnerError(JobRunnerError):
  @@ -39,6 +39,13 @@
           super().__init__(message, HTTPStatus.INTERNAL_SERVER_ERROR, "EmptyDatasetError", cause, True)
   
   
  +class DatasetModuleNotInstalledError(ConfigNamesJobRunnerError):
  +    """Raised when the dataset tries to import a module that is not installed."""
  +
  +    def __init__(self, message: str, cause: Optional[BaseException] = None):
  +        super().__init__(message, HTTPStatus.INTERNAL_SERVER_ERROR, "DatasetModuleNotInstalledError", cause, True)
  +
  +
   class ConfigNamesError(ConfigNamesJobRunnerError):
       """Raised when the config names could not be fetched."""
   
  @@ -77,6 +84,8 @@
       Raises the following errors:
           - [`~job_runners.config_names.EmptyDatasetError`]
             The dataset is empty.
  +        - [`~job_runners.config_names.DatasetModuleNotInstalledError`]
  +          The dataset tries to import a module that is not installed.
           - [`~job_runners.config_names.ConfigNamesError`]
             If the list of configs could not be obtained using the datasets library.
       </Tip>
  @@ -91,6 +100,10 @@
           ]
       except _EmptyDatasetError as err:
           raise EmptyDatasetError("The dataset is empty.", cause=err) from err
  +    except ImportError as err:
  +        raise DatasetModuleNotInstalledError(
  +            "The dataset tries to import a module that is not installed.", cause=err
  +        ) from err
       except Exception as err:
           raise ConfigNamesError("Cannot get the config names for the dataset.", cause=err) from err
       return ConfigNamesResponse(config_names=config_name_items)
  
verification_info: {"golden_diff": "diff --git a/services/worker/src/worker/job_runners/config_names.py b/services/worker/src/worker/job_runners/config_names.py\n--- a/services/worker/src/worker/job_runners/config_names.py\n+++ b/services/worker/src/worker/job_runners/config_names.py\n@@ -13,7 +13,7 @@\n from worker.job_runner import CompleteJobResult, JobRunnerError, ParameterMissingError\n from worker.job_runners._datasets_based_job_runner import DatasetsBasedJobRunner\n \n-ConfigNamesJobRunnerErrorCode = Literal[\"EmptyDatasetError\", \"ConfigNamesError\"]\n+ConfigNamesJobRunnerErrorCode = Literal[\"EmptyDatasetError\", \"DatasetModuleNotInstalledError\", \"ConfigNamesError\"]\n \n \n class ConfigNamesJobRunnerError(JobRunnerError):\n@@ -39,6 +39,13 @@\n         super().__init__(message, HTTPStatus.INTERNAL_SERVER_ERROR, \"EmptyDatasetError\", cause, True)\n \n \n+class DatasetModuleNotInstalledError(ConfigNamesJobRunnerError):\n+    \"\"\"Raised when the dataset tries to import a module that is not installed.\"\"\"\n+\n+    def __init__(self, message: str, cause: Optional[BaseException] = None):\n+        super().__init__(message, HTTPStatus.INTERNAL_SERVER_ERROR, \"DatasetModuleNotInstalledError\", cause, True)\n+\n+\n class ConfigNamesError(ConfigNamesJobRunnerError):\n     \"\"\"Raised when the config names could not be fetched.\"\"\"\n \n@@ -77,6 +84,8 @@\n     Raises the following errors:\n         - [`~job_runners.config_names.EmptyDatasetError`]\n           The dataset is empty.\n+        - [`~job_runners.config_names.DatasetModuleNotInstalledError`]\n+          The dataset tries to import a module that is not installed.\n         - [`~job_runners.config_names.ConfigNamesError`]\n           If the list of configs could not be obtained using the datasets library.\n     </Tip>\n@@ -91,6 +100,10 @@\n         ]\n     except _EmptyDatasetError as err:\n         raise EmptyDatasetError(\"The dataset is empty.\", cause=err) from err\n+    except ImportError as err:\n+        raise DatasetModuleNotInstalledError(\n+            \"The dataset tries to import a module that is not installed.\", cause=err\n+        ) from err\n     except Exception as err:\n         raise ConfigNamesError(\"Cannot get the config names for the dataset.\", cause=err) from err\n     return ConfigNamesResponse(config_names=config_name_items)\n", "issue": "No specific error when dataset tries to import a non-installed module\nWhen a dataset script tries to import a module/library that is not installed, there is no informative error message.\r\n\r\nSee:\r\n- #1067 \r\n- #1068\r\n\r\nRelated to:\r\n- #976\n", "before_files": [{"content": "# SPDX-License-Identifier: Apache-2.0\n# Copyright 2022 The HuggingFace Authors.\n\nimport logging\nfrom http import HTTPStatus\nfrom typing import Any, List, Literal, Mapping, Optional, TypedDict, Union\n\nfrom datasets import get_dataset_config_names\nfrom datasets.data_files import EmptyDatasetError as _EmptyDatasetError\nfrom libcommon.constants import PROCESSING_STEP_CONFIG_NAMES_VERSION\nfrom libcommon.simple_cache import SplitFullName\n\nfrom worker.job_runner import CompleteJobResult, JobRunnerError, ParameterMissingError\nfrom worker.job_runners._datasets_based_job_runner import DatasetsBasedJobRunner\n\nConfigNamesJobRunnerErrorCode = Literal[\"EmptyDatasetError\", \"ConfigNamesError\"]\n\n\nclass ConfigNamesJobRunnerError(JobRunnerError):\n    \"\"\"Base class for job runner exceptions.\"\"\"\n\n    def __init__(\n        self,\n        message: str,\n        status_code: HTTPStatus,\n        code: ConfigNamesJobRunnerErrorCode,\n        cause: Optional[BaseException] = None,\n        disclose_cause: bool = False,\n    ):\n        super().__init__(\n            message=message, status_code=status_code, code=code, cause=cause, disclose_cause=disclose_cause\n        )\n\n\nclass EmptyDatasetError(ConfigNamesJobRunnerError):\n    \"\"\"Raised when the dataset has no data.\"\"\"\n\n    def __init__(self, message: str, cause: Optional[BaseException] = None):\n        super().__init__(message, HTTPStatus.INTERNAL_SERVER_ERROR, \"EmptyDatasetError\", cause, True)\n\n\nclass ConfigNamesError(ConfigNamesJobRunnerError):\n    \"\"\"Raised when the config names could not be fetched.\"\"\"\n\n    def __init__(self, message: str, cause: Optional[BaseException] = None):\n        super().__init__(message, HTTPStatus.INTERNAL_SERVER_ERROR, \"ConfigNamesError\", cause, True)\n\n\nclass ConfigNameItem(TypedDict):\n    dataset: str\n    config: str\n\n\nclass ConfigNamesResponse(TypedDict):\n    config_names: List[ConfigNameItem]\n\n\ndef compute_config_names_response(\n    dataset: str,\n    hf_token: Optional[str] = None,\n) -> ConfigNamesResponse:\n    \"\"\"\n    Get the response of /config-names for one specific dataset on huggingface.co.\n    Dataset can be private or gated if you pass an acceptable token.\n\n    It is assumed that the dataset exists and can be accessed using the token.\n\n    Args:\n        dataset (`str`):\n            A namespace (user or an organization) and a repo name separated\n            by a `/`.\n        hf_token (`str`, *optional*):\n            An authentication token (See https://huggingface.co/settings/token)\n    Returns:\n        `ConfigNamesResponse`: An object with the list of config names.\n    <Tip>\n    Raises the following errors:\n        - [`~job_runners.config_names.EmptyDatasetError`]\n          The dataset is empty.\n        - [`~job_runners.config_names.ConfigNamesError`]\n          If the list of configs could not be obtained using the datasets library.\n    </Tip>\n    \"\"\"\n    logging.info(f\"get config names for dataset={dataset}\")\n    use_auth_token: Union[bool, str, None] = hf_token if hf_token is not None else False\n    # get the list of splits in streaming mode\n    try:\n        config_name_items: List[ConfigNameItem] = [\n            {\"dataset\": dataset, \"config\": str(config)}\n            for config in sorted(get_dataset_config_names(path=dataset, use_auth_token=use_auth_token))\n        ]\n    except _EmptyDatasetError as err:\n        raise EmptyDatasetError(\"The dataset is empty.\", cause=err) from err\n    except Exception as err:\n        raise ConfigNamesError(\"Cannot get the config names for the dataset.\", cause=err) from err\n    return ConfigNamesResponse(config_names=config_name_items)\n\n\nclass ConfigNamesJobRunner(DatasetsBasedJobRunner):\n    @staticmethod\n    def get_job_type() -> str:\n        return \"/config-names\"\n\n    @staticmethod\n    def get_job_runner_version() -> int:\n        return PROCESSING_STEP_CONFIG_NAMES_VERSION\n\n    def compute(self) -> CompleteJobResult:\n        if self.dataset is None:\n            raise ParameterMissingError(\"'dataset' parameter is required\")\n        return CompleteJobResult(\n            compute_config_names_response(dataset=self.dataset, hf_token=self.common_config.hf_token)\n        )\n\n    def get_new_splits(self, content: Mapping[str, Any]) -> set[SplitFullName]:\n        \"\"\"Get the set of new splits, from the content created by the compute.\"\"\"\n        return {SplitFullName(dataset=s[\"dataset\"], config=s[\"config\"], split=None) for s in content[\"config_names\"]}\n", "path": "services/worker/src/worker/job_runners/config_names.py"}], "after_files": [{"content": "# SPDX-License-Identifier: Apache-2.0\n# Copyright 2022 The HuggingFace Authors.\n\nimport logging\nfrom http import HTTPStatus\nfrom typing import Any, List, Literal, Mapping, Optional, TypedDict, Union\n\nfrom datasets import get_dataset_config_names\nfrom datasets.data_files import EmptyDatasetError as _EmptyDatasetError\nfrom libcommon.constants import PROCESSING_STEP_CONFIG_NAMES_VERSION\nfrom libcommon.simple_cache import SplitFullName\n\nfrom worker.job_runner import CompleteJobResult, JobRunnerError, ParameterMissingError\nfrom worker.job_runners._datasets_based_job_runner import DatasetsBasedJobRunner\n\nConfigNamesJobRunnerErrorCode = Literal[\"EmptyDatasetError\", \"DatasetModuleNotInstalledError\", \"ConfigNamesError\"]\n\n\nclass ConfigNamesJobRunnerError(JobRunnerError):\n    \"\"\"Base class for job runner exceptions.\"\"\"\n\n    def __init__(\n        self,\n        message: str,\n        status_code: HTTPStatus,\n        code: ConfigNamesJobRunnerErrorCode,\n        cause: Optional[BaseException] = None,\n        disclose_cause: bool = False,\n    ):\n        super().__init__(\n            message=message, status_code=status_code, code=code, cause=cause, disclose_cause=disclose_cause\n        )\n\n\nclass EmptyDatasetError(ConfigNamesJobRunnerError):\n    \"\"\"Raised when the dataset has no data.\"\"\"\n\n    def __init__(self, message: str, cause: Optional[BaseException] = None):\n        super().__init__(message, HTTPStatus.INTERNAL_SERVER_ERROR, \"EmptyDatasetError\", cause, True)\n\n\nclass DatasetModuleNotInstalledError(ConfigNamesJobRunnerError):\n    \"\"\"Raised when the dataset tries to import a module that is not installed.\"\"\"\n\n    def __init__(self, message: str, cause: Optional[BaseException] = None):\n        super().__init__(message, HTTPStatus.INTERNAL_SERVER_ERROR, \"DatasetModuleNotInstalledError\", cause, True)\n\n\nclass ConfigNamesError(ConfigNamesJobRunnerError):\n    \"\"\"Raised when the config names could not be fetched.\"\"\"\n\n    def __init__(self, message: str, cause: Optional[BaseException] = None):\n        super().__init__(message, HTTPStatus.INTERNAL_SERVER_ERROR, \"ConfigNamesError\", cause, True)\n\n\nclass ConfigNameItem(TypedDict):\n    dataset: str\n    config: str\n\n\nclass ConfigNamesResponse(TypedDict):\n    config_names: List[ConfigNameItem]\n\n\ndef compute_config_names_response(\n    dataset: str,\n    hf_token: Optional[str] = None,\n) -> ConfigNamesResponse:\n    \"\"\"\n    Get the response of /config-names for one specific dataset on huggingface.co.\n    Dataset can be private or gated if you pass an acceptable token.\n\n    It is assumed that the dataset exists and can be accessed using the token.\n\n    Args:\n        dataset (`str`):\n            A namespace (user or an organization) and a repo name separated\n            by a `/`.\n        hf_token (`str`, *optional*):\n            An authentication token (See https://huggingface.co/settings/token)\n    Returns:\n        `ConfigNamesResponse`: An object with the list of config names.\n    <Tip>\n    Raises the following errors:\n        - [`~job_runners.config_names.EmptyDatasetError`]\n          The dataset is empty.\n        - [`~job_runners.config_names.DatasetModuleNotInstalledError`]\n          The dataset tries to import a module that is not installed.\n        - [`~job_runners.config_names.ConfigNamesError`]\n          If the list of configs could not be obtained using the datasets library.\n    </Tip>\n    \"\"\"\n    logging.info(f\"get config names for dataset={dataset}\")\n    use_auth_token: Union[bool, str, None] = hf_token if hf_token is not None else False\n    # get the list of splits in streaming mode\n    try:\n        config_name_items: List[ConfigNameItem] = [\n            {\"dataset\": dataset, \"config\": str(config)}\n            for config in sorted(get_dataset_config_names(path=dataset, use_auth_token=use_auth_token))\n        ]\n    except _EmptyDatasetError as err:\n        raise EmptyDatasetError(\"The dataset is empty.\", cause=err) from err\n    except ImportError as err:\n        raise DatasetModuleNotInstalledError(\n            \"The dataset tries to import a module that is not installed.\", cause=err\n        ) from err\n    except Exception as err:\n        raise ConfigNamesError(\"Cannot get the config names for the dataset.\", cause=err) from err\n    return ConfigNamesResponse(config_names=config_name_items)\n\n\nclass ConfigNamesJobRunner(DatasetsBasedJobRunner):\n    @staticmethod\n    def get_job_type() -> str:\n        return \"/config-names\"\n\n    @staticmethod\n    def get_job_runner_version() -> int:\n        return PROCESSING_STEP_CONFIG_NAMES_VERSION\n\n    def compute(self) -> CompleteJobResult:\n        if self.dataset is None:\n            raise ParameterMissingError(\"'dataset' parameter is required\")\n        return CompleteJobResult(\n            compute_config_names_response(dataset=self.dataset, hf_token=self.common_config.hf_token)\n        )\n\n    def get_new_splits(self, content: Mapping[str, Any]) -> set[SplitFullName]:\n        \"\"\"Get the set of new splits, from the content created by the compute.\"\"\"\n        return {SplitFullName(dataset=s[\"dataset\"], config=s[\"config\"], split=None) for s in content[\"config_names\"]}\n", "path": "services/worker/src/worker/job_runners/config_names.py"}]}