We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Document how to read and write a multi-sheet excel
## Introduction

>A high-level, short overview of the problem(s) you are designing a solution for.

We have the implementation, but it is not easy to point to a documented example:

![image](https://user-images.githubusercontent.com/35801847/178237457-9152ffa0-fbb1-48ca-bf70-d5e2c89323ed.png)

## Background

> Provide the reader with the context surrounding the problem(s) you are trying to solve.

This is a common feature and something Kedro can already do.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `kedro/extras/datasets/pandas/excel_dataset.py`
Content:
```
1 """``ExcelDataSet`` loads/saves data from/to a Excel file using an underlying
2 filesystem (e.g.: local, S3, GCS). It uses pandas to handle the Excel file.
3 """
4 import logging
5 from copy import deepcopy
6 from io import BytesIO
7 from pathlib import PurePosixPath
8 from typing import Any, Dict, Union
9 
10 import fsspec
11 import pandas as pd
12 
13 from kedro.io.core import (
14     PROTOCOL_DELIMITER,
15     AbstractVersionedDataSet,
16     DataSetError,
17     Version,
18     get_filepath_str,
19     get_protocol_and_path,
20 )
21 
22 logger = logging.getLogger(__name__)
23 
24 
25 class ExcelDataSet(
26     AbstractVersionedDataSet[
27         Union[pd.DataFrame, Dict[str, pd.DataFrame]],
28         Union[pd.DataFrame, Dict[str, pd.DataFrame]],
29     ]
30 ):
31     """``ExcelDataSet`` loads/saves data from/to a Excel file using an underlying
32     filesystem (e.g.: local, S3, GCS). It uses pandas to handle the Excel file.
33 
34     Example adding a catalog entry with the ``YAML API``:
35 
36     .. code-block:: yaml
37 
38         >>> rockets:
39         >>>   type: pandas.ExcelDataSet
40         >>>   filepath: gcs://your_bucket/rockets.xlsx
41         >>>   fs_args:
42         >>>     project: my-project
43         >>>   credentials: my_gcp_credentials
44         >>>   save_args:
45         >>>     sheet_name: Sheet1
46         >>>   load_args:
47         >>>     sheet_name: Sheet1
48         >>>
49         >>> shuttles:
50         >>>   type: pandas.ExcelDataSet
51         >>>   filepath: data/01_raw/shuttles.xlsx
52 
53     Example using Python API:
54     ::
55 
56         >>> from kedro.extras.datasets.pandas import ExcelDataSet
57         >>> import pandas as pd
58         >>>
59         >>> data = pd.DataFrame({'col1': [1, 2], 'col2': [4, 5],
60         >>>                      'col3': [5, 6]})
61         >>>
62         >>> # data_set = ExcelDataSet(filepath="gcs://bucket/test.xlsx")
63         >>> data_set = ExcelDataSet(filepath="test.xlsx")
64         >>> data_set.save(data)
65         >>> reloaded = data_set.load()
66         >>> assert data.equals(reloaded)
67 
68     """
69 
70     DEFAULT_LOAD_ARGS = {"engine": "openpyxl"}
71     DEFAULT_SAVE_ARGS = {"index": False}
72 
73     # pylint: disable=too-many-arguments
74     def __init__(
75         self,
76         filepath: str,
77         engine: str = "openpyxl",
78         load_args: Dict[str, Any] = None,
79         save_args: Dict[str, Any] = None,
80         version: Version = None,
81         credentials: Dict[str, Any] = None,
82         fs_args: Dict[str, Any] = None,
83     ) -> None:
84         """Creates a new instance of ``ExcelDataSet`` pointing to a concrete Excel file
85         on a specific filesystem.
86 
87         Args:
88             filepath: Filepath in POSIX format to a Excel file prefixed with a protocol like
89                 `s3://`. If prefix is not provided, `file` protocol (local filesystem) will be used.
90                 The prefix should be any protocol supported by ``fsspec``.
91                 Note: `http(s)` doesn't support versioning.
92             engine: The engine used to write to excel files. The default
93                 engine is 'openpyxl'.
94             load_args: Pandas options for loading Excel files.
95                 Here you can find all available arguments:
96                 https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_excel.html
97                 All defaults are preserved, but "engine", which is set to "openpyxl".
98                 Supports multi-sheet Excel files (include `sheet_name = None` in `load_args`).
99             save_args: Pandas options for saving Excel files.
100                 Here you can find all available arguments:
101                 https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.to_excel.html
102                 All defaults are preserved, but "index", which is set to False.
103                 If you would like to specify options for the `ExcelWriter`,
104                 you can include them under the "writer" key. Here you can
105                 find all available arguments:
106                 https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.ExcelWriter.html
107             version: If specified, should be an instance of
108                 ``kedro.io.core.Version``. If its ``load`` attribute is
109                 None, the latest version will be loaded. If its ``save``
110                 attribute is None, save version will be autogenerated.
111             credentials: Credentials required to get access to the underlying filesystem.
112                 E.g. for ``GCSFileSystem`` it should look like `{"token": None}`.
113             fs_args: Extra arguments to pass into underlying filesystem class constructor
114                 (e.g. `{"project": "my-project"}` for ``GCSFileSystem``).
115 
116         Raises:
117             DataSetError: If versioning is enabled while in append mode.
118         """
119         _fs_args = deepcopy(fs_args) or {}
120         _credentials = deepcopy(credentials) or {}
121 
122         protocol, path = get_protocol_and_path(filepath, version)
123         if protocol == "file":
124             _fs_args.setdefault("auto_mkdir", True)
125 
126         self._protocol = protocol
127         self._storage_options = {**_credentials, **_fs_args}
128         self._fs = fsspec.filesystem(self._protocol, **self._storage_options)
129 
130         super().__init__(
131             filepath=PurePosixPath(path),
132             version=version,
133             exists_function=self._fs.exists,
134             glob_function=self._fs.glob,
135         )
136 
137         # Handle default load arguments
138         self._load_args = deepcopy(self.DEFAULT_LOAD_ARGS)
139         if load_args is not None:
140             self._load_args.update(load_args)
141 
142         # Handle default save arguments
143         self._save_args = deepcopy(self.DEFAULT_SAVE_ARGS)
144         if save_args is not None:
145             self._save_args.update(save_args)
146         self._writer_args = self._save_args.pop("writer", {})  # type: ignore
147         self._writer_args.setdefault("engine", engine or "openpyxl")  # type: ignore
148 
149         if version and self._writer_args.get("mode") == "a":  # type: ignore
150             raise DataSetError(
151                 "'ExcelDataSet' doesn't support versioning in append mode."
152             )
153 
154         if "storage_options" in self._save_args or "storage_options" in self._load_args:
155             logger.warning(
156                 "Dropping 'storage_options' for %s, "
157                 "please specify them under 'fs_args' or 'credentials'.",
158                 self._filepath,
159             )
160             self._save_args.pop("storage_options", None)
161             self._load_args.pop("storage_options", None)
162 
163     def _describe(self) -> Dict[str, Any]:
164         return dict(
165             filepath=self._filepath,
166             protocol=self._protocol,
167             load_args=self._load_args,
168             save_args=self._save_args,
169             writer_args=self._writer_args,
170             version=self._version,
171         )
172 
173     def _load(self) -> Union[pd.DataFrame, Dict[str, pd.DataFrame]]:
174         load_path = str(self._get_load_path())
175         if self._protocol == "file":
176             # file:// protocol seems to misbehave on Windows
177             # (<urlopen error file not on local host>),
178             # so we don't join that back to the filepath;
179             # storage_options also don't work with local paths
180             return pd.read_excel(load_path, **self._load_args)
181 
182         load_path = f"{self._protocol}{PROTOCOL_DELIMITER}{load_path}"
183         return pd.read_excel(
184             load_path, storage_options=self._storage_options, **self._load_args
185         )
186 
187     def _save(self, data: Union[pd.DataFrame, Dict[str, pd.DataFrame]]) -> None:
188         output = BytesIO()
189         save_path = get_filepath_str(self._get_save_path(), self._protocol)
190 
191         # pylint: disable=abstract-class-instantiated
192         with pd.ExcelWriter(output, **self._writer_args) as writer:
193             if isinstance(data, dict):
194                 for sheet_name, sheet_data in data.items():
195                     sheet_data.to_excel(
196                         writer, sheet_name=sheet_name, **self._save_args
197                     )
198             else:
199                 data.to_excel(writer, **self._save_args)
200 
201         with self._fs.open(save_path, mode="wb") as fs_file:
202             fs_file.write(output.getvalue())
203 
204         self._invalidate_cache()
205 
206     def _exists(self) -> bool:
207         try:
208             load_path = get_filepath_str(self._get_load_path(), self._protocol)
209         except DataSetError:
210             return False
211 
212         return self._fs.exists(load_path)
213 
214     def _release(self) -> None:
215         super()._release()
216         self._invalidate_cache()
217 
218     def _invalidate_cache(self) -> None:
219         """Invalidate underlying filesystem caches."""
220         filepath = get_filepath_str(self._filepath, self._protocol)
221         self._fs.invalidate_cache(filepath)
222
```
--- 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()

```

diff --git a/kedro/extras/datasets/pandas/excel_dataset.py b/kedro/extras/datasets/pandas/excel_dataset.py
--- a/kedro/extras/datasets/pandas/excel_dataset.py
+++ b/kedro/extras/datasets/pandas/excel_dataset.py
@@ -65,6 +65,36 @@
         >>> reloaded = data_set.load()
         >>> assert data.equals(reloaded)
 
+    Note: To save a multi-sheet excel file, no special ``save_args`` are required.
+    Instead, return a dictionary of ``Dict[str, pd.DataFrame]`` where the string
+    keys are your sheet names.
+
+    Example adding a catalog entry for multi-sheet excel file with the ``YAML API``:
+
+    .. code-block:: yaml
+
+        >>> trains:
+        >>>   type: pandas.ExcelDataSet
+        >>>   filepath: data/02_intermediate/company/trains.xlsx
+        >>>   load_args:
+        >>>     sheet_name: [Sheet1, Sheet2, Sheet3]
+
+    Example multi-sheet excel file using Python API:
+    ::
+
+        >>> from kedro.extras.datasets.pandas import ExcelDataSet
+        >>> import pandas as pd
+        >>>
+        >>> dataframe = pd.DataFrame({'col1': [1, 2], 'col2': [4, 5],
+        >>>                      'col3': [5, 6]})
+        >>> another_dataframe = pd.DataFrame({"x": [10, 20], "y": ["hello", "world"]})
+        >>> multiframe = {"Sheet1": dataframe, "Sheet2": another_dataframe}
+        >>> data_set = ExcelDataSet(filepath="test.xlsx", load_args = {"sheet_name": None})
+        >>> data_set.save(multiframe)
+        >>> reloaded = data_set.load()
+        >>> assert multiframe["Sheet1"].equals(reloaded["Sheet1"])
+        >>> assert multiframe["Sheet2"].equals(reloaded["Sheet2"])
+
     """
 
     DEFAULT_LOAD_ARGS = {"engine": "openpyxl"}

{"golden_diff": "diff --git a/kedro/extras/datasets/pandas/excel_dataset.py b/kedro/extras/datasets/pandas/excel_dataset.py\n--- a/kedro/extras/datasets/pandas/excel_dataset.py\n+++ b/kedro/extras/datasets/pandas/excel_dataset.py\n@@ -65,6 +65,36 @@\n         >>> reloaded = data_set.load()\n         >>> assert data.equals(reloaded)\n \n+    Note: To save a multi-sheet excel file, no special ``save_args`` are required.\n+    Instead, return a dictionary of ``Dict[str, pd.DataFrame]`` where the string\n+    keys are your sheet names.\n+\n+    Example adding a catalog entry for multi-sheet excel file with the ``YAML API``:\n+\n+    .. code-block:: yaml\n+\n+        >>> trains:\n+        >>>   type: pandas.ExcelDataSet\n+        >>>   filepath: data/02_intermediate/company/trains.xlsx\n+        >>>   load_args:\n+        >>>     sheet_name: [Sheet1, Sheet2, Sheet3]\n+\n+    Example multi-sheet excel file using Python API:\n+    ::\n+\n+        >>> from kedro.extras.datasets.pandas import ExcelDataSet\n+        >>> import pandas as pd\n+        >>>\n+        >>> dataframe = pd.DataFrame({'col1': [1, 2], 'col2': [4, 5],\n+        >>>                      'col3': [5, 6]})\n+        >>> another_dataframe = pd.DataFrame({\"x\": [10, 20], \"y\": [\"hello\", \"world\"]})\n+        >>> multiframe = {\"Sheet1\": dataframe, \"Sheet2\": another_dataframe}\n+        >>> data_set = ExcelDataSet(filepath=\"test.xlsx\", load_args = {\"sheet_name\": None})\n+        >>> data_set.save(multiframe)\n+        >>> reloaded = data_set.load()\n+        >>> assert multiframe[\"Sheet1\"].equals(reloaded[\"Sheet1\"])\n+        >>> assert multiframe[\"Sheet2\"].equals(reloaded[\"Sheet2\"])\n+\n     \"\"\"\n \n     DEFAULT_LOAD_ARGS = {\"engine\": \"openpyxl\"}\n", "issue": "Document how to read and write a multi-sheet excel\n## Introduction\r\n\r\n>A high-level, short overview of the problem(s) you are designing a solution for.\r\n\r\nWe have the implementation, but it is not easy to point to a documented example:\r\n\r\n![image](https://user-images.githubusercontent.com/35801847/178237457-9152ffa0-fbb1-48ca-bf70-d5e2c89323ed.png)\r\n\r\n## Background\r\n\r\n> Provide the reader with the context surrounding the problem(s) you are trying to solve.\r\n\r\nThis is a common feature and something Kedro can already do.\r\n\n", "before_files": [{"content": "\"\"\"``ExcelDataSet`` loads/saves data from/to a Excel file using an underlying\nfilesystem (e.g.: local, S3, GCS). It uses pandas to handle the Excel file.\n\"\"\"\nimport logging\nfrom copy import deepcopy\nfrom io import BytesIO\nfrom pathlib import PurePosixPath\nfrom typing import Any, Dict, Union\n\nimport fsspec\nimport pandas as pd\n\nfrom kedro.io.core import (\n    PROTOCOL_DELIMITER,\n    AbstractVersionedDataSet,\n    DataSetError,\n    Version,\n    get_filepath_str,\n    get_protocol_and_path,\n)\n\nlogger = logging.getLogger(__name__)\n\n\nclass ExcelDataSet(\n    AbstractVersionedDataSet[\n        Union[pd.DataFrame, Dict[str, pd.DataFrame]],\n        Union[pd.DataFrame, Dict[str, pd.DataFrame]],\n    ]\n):\n    \"\"\"``ExcelDataSet`` loads/saves data from/to a Excel file using an underlying\n    filesystem (e.g.: local, S3, GCS). It uses pandas to handle the Excel file.\n\n    Example adding a catalog entry with the ``YAML API``:\n\n    .. code-block:: yaml\n\n        >>> rockets:\n        >>>   type: pandas.ExcelDataSet\n        >>>   filepath: gcs://your_bucket/rockets.xlsx\n        >>>   fs_args:\n        >>>     project: my-project\n        >>>   credentials: my_gcp_credentials\n        >>>   save_args:\n        >>>     sheet_name: Sheet1\n        >>>   load_args:\n        >>>     sheet_name: Sheet1\n        >>>\n        >>> shuttles:\n        >>>   type: pandas.ExcelDataSet\n        >>>   filepath: data/01_raw/shuttles.xlsx\n\n    Example using Python API:\n    ::\n\n        >>> from kedro.extras.datasets.pandas import ExcelDataSet\n        >>> import pandas as pd\n        >>>\n        >>> data = pd.DataFrame({'col1': [1, 2], 'col2': [4, 5],\n        >>>                      'col3': [5, 6]})\n        >>>\n        >>> # data_set = ExcelDataSet(filepath=\"gcs://bucket/test.xlsx\")\n        >>> data_set = ExcelDataSet(filepath=\"test.xlsx\")\n        >>> data_set.save(data)\n        >>> reloaded = data_set.load()\n        >>> assert data.equals(reloaded)\n\n    \"\"\"\n\n    DEFAULT_LOAD_ARGS = {\"engine\": \"openpyxl\"}\n    DEFAULT_SAVE_ARGS = {\"index\": False}\n\n    # pylint: disable=too-many-arguments\n    def __init__(\n        self,\n        filepath: str,\n        engine: str = \"openpyxl\",\n        load_args: Dict[str, Any] = None,\n        save_args: Dict[str, Any] = None,\n        version: Version = None,\n        credentials: Dict[str, Any] = None,\n        fs_args: Dict[str, Any] = None,\n    ) -> None:\n        \"\"\"Creates a new instance of ``ExcelDataSet`` pointing to a concrete Excel file\n        on a specific filesystem.\n\n        Args:\n            filepath: Filepath in POSIX format to a Excel file prefixed with a protocol like\n                `s3://`. If prefix is not provided, `file` protocol (local filesystem) will be used.\n                The prefix should be any protocol supported by ``fsspec``.\n                Note: `http(s)` doesn't support versioning.\n            engine: The engine used to write to excel files. The default\n                engine is 'openpyxl'.\n            load_args: Pandas options for loading Excel files.\n                Here you can find all available arguments:\n                https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_excel.html\n                All defaults are preserved, but \"engine\", which is set to \"openpyxl\".\n                Supports multi-sheet Excel files (include `sheet_name = None` in `load_args`).\n            save_args: Pandas options for saving Excel files.\n                Here you can find all available arguments:\n                https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.to_excel.html\n                All defaults are preserved, but \"index\", which is set to False.\n                If you would like to specify options for the `ExcelWriter`,\n                you can include them under the \"writer\" key. Here you can\n                find all available arguments:\n                https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.ExcelWriter.html\n            version: If specified, should be an instance of\n                ``kedro.io.core.Version``. If its ``load`` attribute is\n                None, the latest version will be loaded. If its ``save``\n                attribute is None, save version will be autogenerated.\n            credentials: Credentials required to get access to the underlying filesystem.\n                E.g. for ``GCSFileSystem`` it should look like `{\"token\": None}`.\n            fs_args: Extra arguments to pass into underlying filesystem class constructor\n                (e.g. `{\"project\": \"my-project\"}` for ``GCSFileSystem``).\n\n        Raises:\n            DataSetError: If versioning is enabled while in append mode.\n        \"\"\"\n        _fs_args = deepcopy(fs_args) or {}\n        _credentials = deepcopy(credentials) or {}\n\n        protocol, path = get_protocol_and_path(filepath, version)\n        if protocol == \"file\":\n            _fs_args.setdefault(\"auto_mkdir\", True)\n\n        self._protocol = protocol\n        self._storage_options = {**_credentials, **_fs_args}\n        self._fs = fsspec.filesystem(self._protocol, **self._storage_options)\n\n        super().__init__(\n            filepath=PurePosixPath(path),\n            version=version,\n            exists_function=self._fs.exists,\n            glob_function=self._fs.glob,\n        )\n\n        # Handle default load arguments\n        self._load_args = deepcopy(self.DEFAULT_LOAD_ARGS)\n        if load_args is not None:\n            self._load_args.update(load_args)\n\n        # Handle default save arguments\n        self._save_args = deepcopy(self.DEFAULT_SAVE_ARGS)\n        if save_args is not None:\n            self._save_args.update(save_args)\n        self._writer_args = self._save_args.pop(\"writer\", {})  # type: ignore\n        self._writer_args.setdefault(\"engine\", engine or \"openpyxl\")  # type: ignore\n\n        if version and self._writer_args.get(\"mode\") == \"a\":  # type: ignore\n            raise DataSetError(\n                \"'ExcelDataSet' doesn't support versioning in append mode.\"\n            )\n\n        if \"storage_options\" in self._save_args or \"storage_options\" in self._load_args:\n            logger.warning(\n                \"Dropping 'storage_options' for %s, \"\n                \"please specify them under 'fs_args' or 'credentials'.\",\n                self._filepath,\n            )\n            self._save_args.pop(\"storage_options\", None)\n            self._load_args.pop(\"storage_options\", None)\n\n    def _describe(self) -> Dict[str, Any]:\n        return dict(\n            filepath=self._filepath,\n            protocol=self._protocol,\n            load_args=self._load_args,\n            save_args=self._save_args,\n            writer_args=self._writer_args,\n            version=self._version,\n        )\n\n    def _load(self) -> Union[pd.DataFrame, Dict[str, pd.DataFrame]]:\n        load_path = str(self._get_load_path())\n        if self._protocol == \"file\":\n            # file:// protocol seems to misbehave on Windows\n            # (<urlopen error file not on local host>),\n            # so we don't join that back to the filepath;\n            # storage_options also don't work with local paths\n            return pd.read_excel(load_path, **self._load_args)\n\n        load_path = f\"{self._protocol}{PROTOCOL_DELIMITER}{load_path}\"\n        return pd.read_excel(\n            load_path, storage_options=self._storage_options, **self._load_args\n        )\n\n    def _save(self, data: Union[pd.DataFrame, Dict[str, pd.DataFrame]]) -> None:\n        output = BytesIO()\n        save_path = get_filepath_str(self._get_save_path(), self._protocol)\n\n        # pylint: disable=abstract-class-instantiated\n        with pd.ExcelWriter(output, **self._writer_args) as writer:\n            if isinstance(data, dict):\n                for sheet_name, sheet_data in data.items():\n                    sheet_data.to_excel(\n                        writer, sheet_name=sheet_name, **self._save_args\n                    )\n            else:\n                data.to_excel(writer, **self._save_args)\n\n        with self._fs.open(save_path, mode=\"wb\") as fs_file:\n            fs_file.write(output.getvalue())\n\n        self._invalidate_cache()\n\n    def _exists(self) -> bool:\n        try:\n            load_path = get_filepath_str(self._get_load_path(), self._protocol)\n        except DataSetError:\n            return False\n\n        return self._fs.exists(load_path)\n\n    def _release(self) -> None:\n        super()._release()\n        self._invalidate_cache()\n\n    def _invalidate_cache(self) -> None:\n        \"\"\"Invalidate underlying filesystem caches.\"\"\"\n        filepath = get_filepath_str(self._filepath, self._protocol)\n        self._fs.invalidate_cache(filepath)\n", "path": "kedro/extras/datasets/pandas/excel_dataset.py"}], "after_files": [{"content": "\"\"\"``ExcelDataSet`` loads/saves data from/to a Excel file using an underlying\nfilesystem (e.g.: local, S3, GCS). It uses pandas to handle the Excel file.\n\"\"\"\nimport logging\nfrom copy import deepcopy\nfrom io import BytesIO\nfrom pathlib import PurePosixPath\nfrom typing import Any, Dict, Union\n\nimport fsspec\nimport pandas as pd\n\nfrom kedro.io.core import (\n    PROTOCOL_DELIMITER,\n    AbstractVersionedDataSet,\n    DataSetError,\n    Version,\n    get_filepath_str,\n    get_protocol_and_path,\n)\n\nlogger = logging.getLogger(__name__)\n\n\nclass ExcelDataSet(\n    AbstractVersionedDataSet[\n        Union[pd.DataFrame, Dict[str, pd.DataFrame]],\n        Union[pd.DataFrame, Dict[str, pd.DataFrame]],\n    ]\n):\n    \"\"\"``ExcelDataSet`` loads/saves data from/to a Excel file using an underlying\n    filesystem (e.g.: local, S3, GCS). It uses pandas to handle the Excel file.\n\n    Example adding a catalog entry with the ``YAML API``:\n\n    .. code-block:: yaml\n\n        >>> rockets:\n        >>>   type: pandas.ExcelDataSet\n        >>>   filepath: gcs://your_bucket/rockets.xlsx\n        >>>   fs_args:\n        >>>     project: my-project\n        >>>   credentials: my_gcp_credentials\n        >>>   save_args:\n        >>>     sheet_name: Sheet1\n        >>>   load_args:\n        >>>     sheet_name: Sheet1\n        >>>\n        >>> shuttles:\n        >>>   type: pandas.ExcelDataSet\n        >>>   filepath: data/01_raw/shuttles.xlsx\n\n    Example using Python API:\n    ::\n\n        >>> from kedro.extras.datasets.pandas import ExcelDataSet\n        >>> import pandas as pd\n        >>>\n        >>> data = pd.DataFrame({'col1': [1, 2], 'col2': [4, 5],\n        >>>                      'col3': [5, 6]})\n        >>>\n        >>> # data_set = ExcelDataSet(filepath=\"gcs://bucket/test.xlsx\")\n        >>> data_set = ExcelDataSet(filepath=\"test.xlsx\")\n        >>> data_set.save(data)\n        >>> reloaded = data_set.load()\n        >>> assert data.equals(reloaded)\n\n    Note: To save a multi-sheet excel file, no special ``save_args`` are required.\n    Instead, return a dictionary of ``Dict[str, pd.DataFrame]`` where the string\n    keys are your sheet names.\n\n    Example adding a catalog entry for multi-sheet excel file with the ``YAML API``:\n\n    .. code-block:: yaml\n\n        >>> trains:\n        >>>   type: pandas.ExcelDataSet\n        >>>   filepath: data/02_intermediate/company/trains.xlsx\n        >>>   load_args:\n        >>>     sheet_name: [Sheet1, Sheet2, Sheet3]\n\n    Example multi-sheet excel file using Python API:\n    ::\n\n        >>> from kedro.extras.datasets.pandas import ExcelDataSet\n        >>> import pandas as pd\n        >>>\n        >>> dataframe = pd.DataFrame({'col1': [1, 2], 'col2': [4, 5],\n        >>>                      'col3': [5, 6]})\n        >>> another_dataframe = pd.DataFrame({\"x\": [10, 20], \"y\": [\"hello\", \"world\"]})\n        >>> multiframe = {\"Sheet1\": dataframe, \"Sheet2\": another_dataframe}\n        >>> data_set = ExcelDataSet(filepath=\"test.xlsx\", load_args = {\"sheet_name\": None})\n        >>> data_set.save(multiframe)\n        >>> reloaded = data_set.load()\n        >>> assert multiframe[\"Sheet1\"].equals(reloaded[\"Sheet1\"])\n        >>> assert multiframe[\"Sheet2\"].equals(reloaded[\"Sheet2\"])\n\n    \"\"\"\n\n    DEFAULT_LOAD_ARGS = {\"engine\": \"openpyxl\"}\n    DEFAULT_SAVE_ARGS = {\"index\": False}\n\n    # pylint: disable=too-many-arguments\n    def __init__(\n        self,\n        filepath: str,\n        engine: str = \"openpyxl\",\n        load_args: Dict[str, Any] = None,\n        save_args: Dict[str, Any] = None,\n        version: Version = None,\n        credentials: Dict[str, Any] = None,\n        fs_args: Dict[str, Any] = None,\n    ) -> None:\n        \"\"\"Creates a new instance of ``ExcelDataSet`` pointing to a concrete Excel file\n        on a specific filesystem.\n\n        Args:\n            filepath: Filepath in POSIX format to a Excel file prefixed with a protocol like\n                `s3://`. If prefix is not provided, `file` protocol (local filesystem) will be used.\n                The prefix should be any protocol supported by ``fsspec``.\n                Note: `http(s)` doesn't support versioning.\n            engine: The engine used to write to excel files. The default\n                engine is 'openpyxl'.\n            load_args: Pandas options for loading Excel files.\n                Here you can find all available arguments:\n                https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_excel.html\n                All defaults are preserved, but \"engine\", which is set to \"openpyxl\".\n                Supports multi-sheet Excel files (include `sheet_name = None` in `load_args`).\n            save_args: Pandas options for saving Excel files.\n                Here you can find all available arguments:\n                https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.to_excel.html\n                All defaults are preserved, but \"index\", which is set to False.\n                If you would like to specify options for the `ExcelWriter`,\n                you can include them under the \"writer\" key. Here you can\n                find all available arguments:\n                https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.ExcelWriter.html\n            version: If specified, should be an instance of\n                ``kedro.io.core.Version``. If its ``load`` attribute is\n                None, the latest version will be loaded. If its ``save``\n                attribute is None, save version will be autogenerated.\n            credentials: Credentials required to get access to the underlying filesystem.\n                E.g. for ``GCSFileSystem`` it should look like `{\"token\": None}`.\n            fs_args: Extra arguments to pass into underlying filesystem class constructor\n                (e.g. `{\"project\": \"my-project\"}` for ``GCSFileSystem``).\n\n        Raises:\n            DataSetError: If versioning is enabled while in append mode.\n        \"\"\"\n        _fs_args = deepcopy(fs_args) or {}\n        _credentials = deepcopy(credentials) or {}\n\n        protocol, path = get_protocol_and_path(filepath, version)\n        if protocol == \"file\":\n            _fs_args.setdefault(\"auto_mkdir\", True)\n\n        self._protocol = protocol\n        self._storage_options = {**_credentials, **_fs_args}\n        self._fs = fsspec.filesystem(self._protocol, **self._storage_options)\n\n        super().__init__(\n            filepath=PurePosixPath(path),\n            version=version,\n            exists_function=self._fs.exists,\n            glob_function=self._fs.glob,\n        )\n\n        # Handle default load arguments\n        self._load_args = deepcopy(self.DEFAULT_LOAD_ARGS)\n        if load_args is not None:\n            self._load_args.update(load_args)\n\n        # Handle default save arguments\n        self._save_args = deepcopy(self.DEFAULT_SAVE_ARGS)\n        if save_args is not None:\n            self._save_args.update(save_args)\n        self._writer_args = self._save_args.pop(\"writer\", {})  # type: ignore\n        self._writer_args.setdefault(\"engine\", engine or \"openpyxl\")  # type: ignore\n\n        if version and self._writer_args.get(\"mode\") == \"a\":  # type: ignore\n            raise DataSetError(\n                \"'ExcelDataSet' doesn't support versioning in append mode.\"\n            )\n\n        if \"storage_options\" in self._save_args or \"storage_options\" in self._load_args:\n            logger.warning(\n                \"Dropping 'storage_options' for %s, \"\n                \"please specify them under 'fs_args' or 'credentials'.\",\n                self._filepath,\n            )\n            self._save_args.pop(\"storage_options\", None)\n            self._load_args.pop(\"storage_options\", None)\n\n    def _describe(self) -> Dict[str, Any]:\n        return dict(\n            filepath=self._filepath,\n            protocol=self._protocol,\n            load_args=self._load_args,\n            save_args=self._save_args,\n            writer_args=self._writer_args,\n            version=self._version,\n        )\n\n    def _load(self) -> Union[pd.DataFrame, Dict[str, pd.DataFrame]]:\n        load_path = str(self._get_load_path())\n        if self._protocol == \"file\":\n            # file:// protocol seems to misbehave on Windows\n            # (<urlopen error file not on local host>),\n            # so we don't join that back to the filepath;\n            # storage_options also don't work with local paths\n            return pd.read_excel(load_path, **self._load_args)\n\n        load_path = f\"{self._protocol}{PROTOCOL_DELIMITER}{load_path}\"\n        return pd.read_excel(\n            load_path, storage_options=self._storage_options, **self._load_args\n        )\n\n    def _save(self, data: Union[pd.DataFrame, Dict[str, pd.DataFrame]]) -> None:\n        output = BytesIO()\n        save_path = get_filepath_str(self._get_save_path(), self._protocol)\n\n        # pylint: disable=abstract-class-instantiated\n        with pd.ExcelWriter(output, **self._writer_args) as writer:\n            if isinstance(data, dict):\n                for sheet_name, sheet_data in data.items():\n                    sheet_data.to_excel(\n                        writer, sheet_name=sheet_name, **self._save_args\n                    )\n            else:\n                data.to_excel(writer, **self._save_args)\n\n        with self._fs.open(save_path, mode=\"wb\") as fs_file:\n            fs_file.write(output.getvalue())\n\n        self._invalidate_cache()\n\n    def _exists(self) -> bool:\n        try:\n            load_path = get_filepath_str(self._get_load_path(), self._protocol)\n        except DataSetError:\n            return False\n\n        return self._fs.exists(load_path)\n\n    def _release(self) -> None:\n        super()._release()\n        self._invalidate_cache()\n\n    def _invalidate_cache(self) -> None:\n        \"\"\"Invalidate underlying filesystem caches.\"\"\"\n        filepath = get_filepath_str(self._filepath, self._protocol)\n        self._fs.invalidate_cache(filepath)\n", "path": "kedro/extras/datasets/pandas/excel_dataset.py"}]}