Repository: openml/openml-python

Issue:
openml.datasets.get_data() has unpredictable number of return values
MWE:
```
dataset = openml.datasets.get_dataset(40978)

res = dataset.get_data(target=dataset.default_target_attribute)
print(len(res))
dataset = openml.datasets.get_dataset(2)

res = dataset.get_data(target=dataset.default_target_attribute)
print(len(res))
```
This depends on whether a default target attribute has been specified. 

Discussion:
codecov-io: # [Codecov](https://codecov.io/gh/openml/openml-python/pull/677?src=pr&el=h1) Report
> Merging [#677](https://codecov.io/gh/openml/openml-python/pull/677?src=pr&el=desc) into [develop](https://codecov.io/gh/openml/openml-python/commit/813daebea2d0c4932641f013ef79ba0ca72a9f46?src=pr&el=desc) will **decrease** coverage by `0.03%`.
> The diff coverage is `94.73%`.

[![Impacted file tree graph](https://codecov.io/gh/openml/openml-python/pull/677/graphs/tree.svg?width=650&token=IlImE4jvlP&height=150&src=pr)](https://codecov.io/gh/openml/openml-python/pull/677?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           develop    #677      +/-   ##
==========================================
- Coverage    90.54%   90.5%   -0.04%     
==========================================
  Files           36      36              
  Lines         3743    3730      -13     
==========================================
- Hits          3389    3376      -13     
  Misses         354     354
```


| [Impacted Files](https://codecov.io/gh/openml/openml-python/pull/677?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [openml/tasks/task.py](https://codecov.io/gh/openml/openml-python/pull/677/diff?src=pr&el=tree#diff-b3Blbm1sL3Rhc2tzL3Rhc2sucHk=) | `94.77% <100%> (ø)` | :arrow_up: |
| [openml/datasets/dataset.py](https://codecov.io/gh/openml/openml-python/pull/677/diff?src=pr&el=tree#diff-b3Blbm1sL2RhdGFzZXRzL2RhdGFzZXQucHk=) | `88.12% <93.33%> (-0.47%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/openml/openml-python/pull/677?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/openml/openml-python/pull/677?src=pr&el=footer). Last update [813daeb...b2fb382](https://codecov.io/gh/openml/openml-python/pull/677?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/examples/datasets_tutorial.py b/examples/datasets_tutorial.py
index dd24e349..4d340de7 100644
--- a/examples/datasets_tutorial.py
+++ b/examples/datasets_tutorial.py
@@ -60,10 +60,9 @@ print(dataset.description[:500])
 # controlled with the parameter ``dataset_format`` which can be either 'array'
 # (default) or 'dataframe'. Let's first build our dataset from a NumPy array
 # and manually create a dataframe.
-X, y, attribute_names = dataset.get_data(
+X, y, categorical_indicator, attribute_names = dataset.get_data(
     dataset_format='array',
-    target=dataset.default_target_attribute,
-    return_attribute_names=True,
+    target=dataset.default_target_attribute
 )
 eeg = pd.DataFrame(X, columns=attribute_names)
 eeg['class'] = y
@@ -72,8 +71,10 @@ print(eeg[:10])
 ############################################################################
 # Instead of manually creating the dataframe, you can already request a
 # dataframe with the correct dtypes.
-X, y = dataset.get_data(target=dataset.default_target_attribute,
-                        dataset_format='dataframe')
+X, y, categorical_indicator, attribute_names = dataset.get_data(
+    target=dataset.default_target_attribute,
+    dataset_format='dataframe'
+)
 print(X.head())
 print(X.info())
 
diff --git a/examples/flows_and_runs_tutorial.py b/examples/flows_and_runs_tutorial.py
index badddf1a..d196c30e 100644
--- a/examples/flows_and_runs_tutorial.py
+++ b/examples/flows_and_runs_tutorial.py
@@ -22,7 +22,7 @@ from sklearn import ensemble, neighbors, preprocessing, pipeline, tree
 openml.config.start_using_configuration_for_example()
 # NOTE: We are using dataset 68 from the test server: https://test.openml.org/d/68
 dataset = openml.datasets.get_dataset(68)
-X, y = dataset.get_data(
+X, y, categorical_indicator, attribute_names = dataset.get_data(
     dataset_format='array',
     target=dataset.default_target_attribute
 )
@@ -34,13 +34,12 @@ clf.fit(X, y)
 #
 # * e.g. categorical features -> do feature encoding
 dataset = openml.datasets.get_dataset(17)
-X, y, categorical = dataset.get_data(
+X, y, categorical_indicator, attribute_names = dataset.get_data(
     dataset_format='array',
-    target=dataset.default_target_attribute,
-    return_categorical_indicator=True,
+    target=dataset.default_target_attribute
 )
-print("Categorical features: %s" % categorical)
-enc = preprocessing.OneHotEncoder(categorical_features=categorical)
+print("Categorical features: {}".format(categorical_indicator))
+enc = preprocessing.OneHotEncoder(categorical_features=categorical_indicator)
 X = enc.fit_transform(X)
 clf.fit(X, y)
 
diff --git a/openml/datasets/dataset.py b/openml/datasets/dataset.py
index cb12d3af..b6833a51 100644
--- a/openml/datasets/dataset.py
+++ b/openml/datasets/dataset.py
@@ -4,7 +4,7 @@ import io
 import logging
 import os
 import pickle
-from typing import List, Optional, Union
+from typing import List, Optional, Union, Tuple, Iterable
 
 import arff
 import numpy as np
@@ -419,29 +419,31 @@ class OpenMLDataset(object):
         from .functions import _get_dataset_arff
         self.data_file = _get_dataset_arff(self)
 
-    def get_data(self, target: Optional[Union[List[str], str]] = None,
-                 include_row_id: bool = False,
-                 include_ignore_attributes: bool = False,
-                 return_categorical_indicator: bool = False,
-                 return_attribute_names: bool = False,
-                 dataset_format: str = None):
+    def get_data(
+            self,
+            target: Optional[Union[List[str], str]] = None,
+            include_row_id: bool = False,
+            include_ignore_attributes: bool = False,
+            dataset_format: str = "dataframe",
+    ) -> Tuple[
+            Union[np.ndarray, pd.DataFrame, scipy.sparse.csr_matrix],
+            Optional[Union[np.ndarray, pd.DataFrame]],
+            List[bool],
+            List[str]
+    ]:
         """ Returns dataset content as dataframes or sparse matrices.
 
         Parameters
         ----------
-        target : string, list of strings or None (default=None)
-            Name of target column(s) to separate from the data.
+        target : string, List[str] or None (default=None)
+            Name of target column to separate from the data.
+            Splitting multiple columns is currently not supported.
         include_row_id : boolean (default=False)
             Whether to include row ids in the returned dataset.
         include_ignore_attributes : boolean (default=False)
             Whether to include columns that are marked as "ignore"
             on the server in the dataset.
-        return_categorical_indicator : boolean (default=False)
-            Whether to return a boolean mask indicating which features are
-            categorical.
-        return_attribute_names : boolean (default=False)
-            Whether to return attribute names.
-        dataset_format : string, optional
+        dataset_format : string (default='dataframe')
             The format of returned dataset.
             If ``array``, the returned dataset will be a NumPy array or a SciPy sparse matrix.
             If ``dataframe``, the returned dataset will be a Pandas DataFrame or SparseDataFrame.
@@ -450,22 +452,13 @@ class OpenMLDataset(object):
         -------
         X : ndarray, dataframe, or sparse matrix, shape (n_samples, n_columns)
             Dataset
-        y : ndarray or series, shape (n_samples,)
-            Target column(s). Only returned if target is not None.
+        y : ndarray or pd.Series, shape (n_samples, ) or None
+            Target column
         categorical_indicator : boolean ndarray
             Mask that indicate categorical features.
-            Only returned if return_categorical_indicator is True.
-        return_attribute_names : list of strings
+        attribute_names : List[str]
             List of attribute names.
-            Only returned if return_attribute_names is True.
         """
-        if dataset_format is None:
-            warn('The default of "dataset_format" will change from "array" to'
-                 ' "dataframe" in 0.9', FutureWarning)
-            dataset_format = 'array'
-
-        rval = []
-
         if self.data_pickle_file is None:
             if self.data_file is None:
                 self._download_data()
@@ -480,23 +473,17 @@ class OpenMLDataset(object):
                 data, categorical, attribute_names = pickle.load(fh)
 
         to_exclude = []
-        if include_row_id is False:
-            if not self.row_id_attribute:
-                pass
-            else:
-                if isinstance(self.row_id_attribute, str):
-                    to_exclude.append(self.row_id_attribute)
-                else:
-                    to_exclude.extend(self.row_id_attribute)
-
-        if include_ignore_attributes is False:
-            if not self.ignore_attributes:
-                pass
-            else:
-                if isinstance(self.ignore_attributes, str):
-                    to_exclude.append(self.ignore_attributes)
-                else:
-                    to_exclude.extend(self.ignore_attributes)
+        if not include_row_id and self.row_id_attribute is not None:
+            if isinstance(self.row_id_attribute, str):
+                to_exclude.append(self.row_id_attribute)
+            elif isinstance(self.row_id_attribute, Iterable):
+                to_exclude.extend(self.row_id_attribute)
+
+        if not include_ignore_attributes and self.ignore_attributes is not None:
+            if isinstance(self.ignore_attributes, str):
+                to_exclude.append(self.ignore_attributes)
+            elif isinstance(self.ignore_attributes, Iterable):
+                to_exclude.extend(self.ignore_attributes)
 
         if len(to_exclude) > 0:
             logger.info("Going to remove the following attributes:"
@@ -514,7 +501,7 @@ class OpenMLDataset(object):
         if target is None:
             data = self._convert_array_format(data, dataset_format,
                                               attribute_names)
-            rval.append(data)
+            targets = None
         else:
             if isinstance(target, str):
                 if ',' in target:
@@ -552,19 +539,9 @@ class OpenMLDataset(object):
             y = y.squeeze()
             y = self._convert_array_format(y, dataset_format, attribute_names)
             y = y.astype(target_dtype) if dataset_format == 'array' else y
+            data, targets = x, y
 
-            rval.append(x)
-            rval.append(y)
-
-        if return_categorical_indicator:
-            rval.append(categorical)
-        if return_attribute_names:
-            rval.append(attribute_names)
-
-        if len(rval) == 1:
-            return rval[0]
-        else:
-            return rval
+        return data, targets, categorical, attribute_names
 
     def retrieve_class_labels(self, target_name: str = 'class') -> Union[None, List[str]]:
         """Reads the datasets arff to determine the class-labels.
diff --git a/openml/tasks/task.py b/openml/tasks/task.py
index e348dc39..0847189b 100644
--- a/openml/tasks/task.py
+++ b/openml/tasks/task.py
@@ -230,7 +230,10 @@ class OpenMLSupervisedTask(OpenMLTask, ABC):
     def get_X_and_y(
         self,
         dataset_format: str = 'array',
-    ) -> Union[np.ndarray, pd.DataFrame, scipy.sparse.spmatrix]:
+    ) -> Tuple[
+        Union[np.ndarray, pd.DataFrame, scipy.sparse.spmatrix],
+        Union[np.ndarray, pd.Series]
+    ]:
         """Get data associated with the current task.
 
         Parameters
@@ -247,10 +250,10 @@ class OpenMLSupervisedTask(OpenMLTask, ABC):
         dataset = self.get_dataset()
         if self.task_type_id not in (1, 2, 3):
             raise NotImplementedError(self.task_type)
-        X_and_y = dataset.get_data(
+        X, y, _, _ = dataset.get_data(
             dataset_format=dataset_format, target=self.target_name,
         )
-        return X_and_y
+        return X, y
 
     def _to_dict(self) -> 'OrderedDict[str, OrderedDict]':
 
@@ -393,10 +396,10 @@ class OpenMLClusteringTask(OpenMLTask):
 
         """
         dataset = self.get_dataset()
-        X_and_y = dataset.get_data(
+        data, *_ = dataset.get_data(
             dataset_format=dataset_format, target=None,
         )
-        return X_and_y
+        return data
 
     def _to_dict(self) -> 'OrderedDict[str, OrderedDict]':
 


Test patch:
diff --git a/tests/test_datasets/test_dataset.py b/tests/test_datasets/test_dataset.py
index 814408ce..5f4f9806 100644
--- a/tests/test_datasets/test_dataset.py
+++ b/tests/test_datasets/test_dataset.py
@@ -27,114 +27,26 @@ class OpenMLDatasetTest(TestBase):
         self.pc4 = openml.datasets.get_dataset(1049, download_data=False)
         self.jm1 = openml.datasets.get_dataset(1053, download_data=False)
 
-    def test_get_data_future_warning(self):
-        warn_msg = 'will change from "array" to "dataframe"'
-        with pytest.warns(FutureWarning, match=warn_msg):
-            self.dataset.get_data()
-
-    def test_get_data(self):
+    def test_get_data_array(self):
         # Basic usage
-        rval = self.dataset.get_data(dataset_format='array')
+        rval, _, categorical, attribute_names = self.dataset.get_data(dataset_format='array')
         self.assertIsInstance(rval, np.ndarray)
         self.assertEqual(rval.dtype, np.float32)
         self.assertEqual((898, 39), rval.shape)
-        rval, categorical = self.dataset.get_data(
-            dataset_format='array', return_categorical_indicator=True
-        )
         self.assertEqual(len(categorical), 39)
         self.assertTrue(all([isinstance(cat, bool) for cat in categorical]))
-        rval, attribute_names = self.dataset.get_data(
-            dataset_format='array', return_attribute_names=True
-        )
         self.assertEqual(len(attribute_names), 39)
         self.assertTrue(all([isinstance(att, str)
                              for att in attribute_names]))
+        self.assertIsNone(_)
 
         # check that an error is raised when the dataset contains string
         err_msg = "PyOpenML cannot handle string when returning numpy arrays"
         with pytest.raises(PyOpenMLError, match=err_msg):
             self.titanic.get_data(dataset_format='array')
 
-    def test_get_data_with_rowid(self):
-        self.dataset.row_id_attribute = "condition"
-        rval, categorical = self.dataset.get_data(
-            dataset_format='array', include_row_id=True,
-            return_categorical_indicator=True
-        )
-        self.assertEqual(rval.dtype, np.float32)
-        self.assertEqual(rval.shape, (898, 39))
-        self.assertEqual(len(categorical), 39)
-        rval, categorical = self.dataset.get_data(
-            dataset_format='array', include_row_id=False,
-            return_categorical_indicator=True
-        )
-        self.assertEqual(rval.dtype, np.float32)
-        self.assertEqual(rval.shape, (898, 38))
-        self.assertEqual(len(categorical), 38)
-
-    def test_get_data_with_target(self):
-        X, y = self.dataset.get_data(dataset_format='array', target="class")
-        self.assertIsInstance(X, np.ndarray)
-        self.assertEqual(X.dtype, np.float32)
-        self.assertIn(y.dtype, [np.int32, np.int64])
-        self.assertEqual(X.shape, (898, 38))
-        X, y, attribute_names = self.dataset.get_data(
-            dataset_format='array',
-            target="class",
-            return_attribute_names=True
-        )
-        self.assertEqual(len(attribute_names), 38)
-        self.assertNotIn("class", attribute_names)
-        self.assertEqual(y.shape, (898, ))
-
-    def test_get_data_rowid_and_ignore_and_target(self):
-        self.dataset.ignore_attributes = ["condition"]
-        self.dataset.row_id_attribute = ["hardness"]
-        X, y = self.dataset.get_data(
-            dataset_format='array',
-            target="class",
-            include_row_id=False,
-            include_ignore_attributes=False
-        )
-        self.assertEqual(X.dtype, np.float32)
-        self.assertIn(y.dtype, [np.int32, np.int64])
-        self.assertEqual(X.shape, (898, 36))
-        X, y, categorical = self.dataset.get_data(
-            dataset_format='array',
-            target="class",
-            return_categorical_indicator=True,
-        )
-        self.assertEqual(len(categorical), 36)
-        self.assertListEqual(categorical, [True] * 3 + [False] + [True] * 2 + [
-            False] + [True] * 23 + [False] * 3 + [True] * 3)
-        self.assertEqual(y.shape, (898, ))
-
-    def test_get_data_with_ignore_attributes(self):
-        self.dataset.ignore_attributes = ["condition"]
-        rval = self.dataset.get_data(
-            dataset_format='array', include_ignore_attributes=True
-        )
-        self.assertEqual(rval.dtype, np.float32)
-        self.assertEqual(rval.shape, (898, 39))
-        rval, categorical = self.dataset.get_data(
-            dataset_format='array', include_ignore_attributes=True,
-            return_categorical_indicator=True
-        )
-        self.assertEqual(len(categorical), 39)
-        rval = self.dataset.get_data(
-            dataset_format='array', include_ignore_attributes=False
-        )
-        self.assertEqual(rval.dtype, np.float32)
-        self.assertEqual(rval.shape, (898, 38))
-        rval, categorical = self.dataset.get_data(
-            dataset_format='array', include_ignore_attributes=False,
-            return_categorical_indicator=True
-        )
-        self.assertEqual(len(categorical), 38)
-        # TODO test multiple ignore attributes!
-
     def test_get_data_pandas(self):
-        data = self.titanic.get_data(dataset_format='dataframe')
+        data, _, _, _ = self.titanic.get_data(dataset_format='dataframe')
         self.assertTrue(isinstance(data, pd.DataFrame))
         self.assertEqual(data.shape[1], len(self.titanic.features))
         self.assertEqual(data.shape[0], 1309)
@@ -157,7 +69,7 @@ class OpenMLDatasetTest(TestBase):
         for col_name in data.columns:
             self.assertTrue(data[col_name].dtype.name == col_dtype[col_name])
 
-        X, y = self.titanic.get_data(
+        X, y, _, _ = self.titanic.get_data(
             dataset_format='dataframe',
             target=self.titanic.default_target_attribute)
         self.assertTrue(isinstance(X, pd.DataFrame))
@@ -171,14 +83,88 @@ class OpenMLDatasetTest(TestBase):
     def test_get_data_boolean_pandas(self):
         # test to check that we are converting properly True and False even
         # with some inconsistency when dumping the data on openml
-        data = self.jm1.get_data(dataset_format='dataframe')
+        data, _, _, _ = self.jm1.get_data()
         self.assertTrue(data['defects'].dtype.name == 'category')
-        self.assertTrue(
-            set(data['defects'].cat.categories) == set([True, False])
-        )
-        data = self.pc4.get_data(dataset_format='dataframe')
+        self.assertTrue(set(data['defects'].cat.categories) == {True, False})
+
+        data, _, _, _ = self.pc4.get_data()
         self.assertTrue(data['c'].dtype.name == 'category')
-        self.assertTrue(set(data['c'].cat.categories) == set([True, False]))
+        self.assertTrue(set(data['c'].cat.categories) == {True, False})
+
+    def test_get_data_no_str_data_for_nparrays(self):
+        # check that an error is raised when the dataset contains string
+        err_msg = "PyOpenML cannot handle string when returning numpy arrays"
+        with pytest.raises(PyOpenMLError, match=err_msg):
+            self.titanic.get_data(dataset_format='array')
+
+    def test_get_data_with_rowid(self):
+        self.dataset.row_id_attribute = "condition"
+        rval, _, categorical, _ = self.dataset.get_data(include_row_id=True)
+        self.assertIsInstance(rval, pd.DataFrame)
+        for (dtype, is_cat) in zip(rval.dtypes, categorical):
+            expected_type = 'category' if is_cat else 'float64'
+            self.assertEqual(dtype.name, expected_type)
+        self.assertEqual(rval.shape, (898, 39))
+        self.assertEqual(len(categorical), 39)
+
+        rval, _, categorical, _ = self.dataset.get_data()
+        self.assertIsInstance(rval, pd.DataFrame)
+        for (dtype, is_cat) in zip(rval.dtypes, categorical):
+            expected_type = 'category' if is_cat else 'float64'
+            self.assertEqual(dtype.name, expected_type)
+        self.assertEqual(rval.shape, (898, 38))
+        self.assertEqual(len(categorical), 38)
+
+    def test_get_data_with_target_array(self):
+        X, y, _, attribute_names = self.dataset.get_data(dataset_format='array', target="class")
+        self.assertIsInstance(X, np.ndarray)
+        self.assertEqual(X.dtype, np.float32)
+        self.assertEqual(X.shape, (898, 38))
+        self.assertIn(y.dtype, [np.int32, np.int64])
+        self.assertEqual(y.shape, (898, ))
+        self.assertEqual(len(attribute_names), 38)
+        self.assertNotIn("class", attribute_names)
+
+    def test_get_data_with_target_pandas(self):
+        X, y, categorical, attribute_names = self.dataset.get_data(target="class")
+        self.assertIsInstance(X, pd.DataFrame)
+        for (dtype, is_cat) in zip(X.dtypes, categorical):
+            expected_type = 'category' if is_cat else 'float64'
+            self.assertEqual(dtype.name, expected_type)
+        self.assertIsInstance(y, pd.Series)
+        self.assertEqual(y.dtype.name, 'category')
+
+        self.assertEqual(X.shape, (898, 38))
+        self.assertEqual(len(attribute_names), 38)
+        self.assertEqual(y.shape, (898, ))
+
+        self.assertNotIn("class", attribute_names)
+
+    def test_get_data_rowid_and_ignore_and_target(self):
+        self.dataset.ignore_attributes = ["condition"]
+        self.dataset.row_id_attribute = ["hardness"]
+        X, y, categorical, names = self.dataset.get_data(target="class")
+        self.assertEqual(X.shape, (898, 36))
+        self.assertEqual(len(categorical), 36)
+        cats = [True] * 3 + [False, True, True, False] + [True] * 23 + [False] * 3 + [True] * 3
+        self.assertListEqual(categorical, cats)
+        self.assertEqual(y.shape, (898, ))
+
+    def test_get_data_with_ignore_attributes(self):
+        self.dataset.ignore_attributes = ["condition"]
+        rval, _, categorical, _ = self.dataset.get_data(include_ignore_attributes=True)
+        for (dtype, is_cat) in zip(rval.dtypes, categorical):
+            expected_type = 'category' if is_cat else 'float64'
+            self.assertEqual(dtype.name, expected_type)
+        self.assertEqual(rval.shape, (898, 39))
+        self.assertEqual(len(categorical), 39)
+
+        rval, _, categorical, _ = self.dataset.get_data(include_ignore_attributes=False)
+        for (dtype, is_cat) in zip(rval.dtypes, categorical):
+            expected_type = 'category' if is_cat else 'float64'
+            self.assertEqual(dtype.name, expected_type)
+        self.assertEqual(rval.shape, (898, 38))
+        self.assertEqual(len(categorical), 38)
 
     def test_dataset_format_constructor(self):
 
@@ -196,12 +182,12 @@ class OpenMLDatasetTest(TestBase):
         # This class is using the anneal dataset with labels [1, 2, 3, 4, 5, 'U']. However,
         # label 4 does not exist and we test that the features 5 and 'U' are correctly mapped to
         # indices 4 and 5, and that nothing is mapped to index 3.
-        _, y = self.dataset.get_data('class', dataset_format='dataframe')
+        _, y, _, _ = self.dataset.get_data('class', dataset_format='dataframe')
         self.assertEqual(list(y.dtype.categories), ['1', '2', '3', '4', '5', 'U'])
-        _, y = self.dataset.get_data('class', dataset_format='array')
+        _, y, _, _ = self.dataset.get_data('class', dataset_format='array')
         self.assertEqual(np.min(y), 0)
         self.assertEqual(np.max(y), 5)
-        # Check that the
+        # Check that no label is mapped to 3, since it is reserved for label '4'.
         self.assertEqual(np.sum(y == 3), 0)
 
 
@@ -234,61 +220,50 @@ class OpenMLDatasetTestSparse(TestBase):
         self.sparse_dataset = openml.datasets.get_dataset(4136, download_data=False)
 
     def test_get_sparse_dataset_with_target(self):
-        X, y = self.sparse_dataset.get_data(
+        X, y, _, attribute_names = self.sparse_dataset.get_data(
             dataset_format='array', target="class"
         )
+
         self.assertTrue(sparse.issparse(X))
         self.assertEqual(X.dtype, np.float32)
+        self.assertEqual(X.shape, (600, 20000))
+
         self.assertIsInstance(y, np.ndarray)
         self.assertIn(y.dtype, [np.int32, np.int64])
-        self.assertEqual(X.shape, (600, 20000))
-        X, y, attribute_names = self.sparse_dataset.get_data(
-            dataset_format='array',
-            target="class",
-            return_attribute_names=True,
-        )
-        self.assertTrue(sparse.issparse(X))
+        self.assertEqual(y.shape, (600, ))
+
         self.assertEqual(len(attribute_names), 20000)
         self.assertNotIn("class", attribute_names)
-        self.assertEqual(y.shape, (600, ))
 
     def test_get_sparse_dataset(self):
-        rval = self.sparse_dataset.get_data(dataset_format='array')
+        rval, _, categorical, attribute_names = self.sparse_dataset.get_data(dataset_format='array')
         self.assertTrue(sparse.issparse(rval))
         self.assertEqual(rval.dtype, np.float32)
         self.assertEqual((600, 20001), rval.shape)
-        rval, categorical = self.sparse_dataset.get_data(
-            dataset_format='array', return_categorical_indicator=True
-        )
-        self.assertTrue(sparse.issparse(rval))
+
         self.assertEqual(len(categorical), 20001)
         self.assertTrue(all([isinstance(cat, bool) for cat in categorical]))
-        rval, attribute_names = self.sparse_dataset.get_data(
-            dataset_format='array', return_attribute_names=True
-        )
-        self.assertTrue(sparse.issparse(rval))
+
         self.assertEqual(len(attribute_names), 20001)
-        self.assertTrue(all([isinstance(att, str)
-                             for att in attribute_names]))
+        self.assertTrue(all([isinstance(att, str) for att in attribute_names]))
 
     def test_get_sparse_dataframe(self):
-        rval = self.sparse_dataset.get_data(dataset_format='dataframe')
+        rval, *_ = self.sparse_dataset.get_data()
         self.assertTrue(isinstance(rval, pd.SparseDataFrame))
         self.assertEqual((600, 20001), rval.shape)
 
     def test_get_sparse_dataset_with_rowid(self):
         self.sparse_dataset.row_id_attribute = ["V256"]
-        rval, categorical = self.sparse_dataset.get_data(
-            dataset_format='array', include_row_id=True,
-            return_categorical_indicator=True
+        rval, _, categorical, _ = self.sparse_dataset.get_data(
+            dataset_format='array', include_row_id=True
         )
         self.assertTrue(sparse.issparse(rval))
         self.assertEqual(rval.dtype, np.float32)
         self.assertEqual(rval.shape, (600, 20001))
         self.assertEqual(len(categorical), 20001)
-        rval, categorical = self.sparse_dataset.get_data(
-            dataset_format='array', include_row_id=False,
-            return_categorical_indicator=True
+
+        rval, _, categorical, _ = self.sparse_dataset.get_data(
+            dataset_format='array', include_row_id=False
         )
         self.assertTrue(sparse.issparse(rval))
         self.assertEqual(rval.dtype, np.float32)
@@ -297,37 +272,27 @@ class OpenMLDatasetTestSparse(TestBase):
 
     def test_get_sparse_dataset_with_ignore_attributes(self):
         self.sparse_dataset.ignore_attributes = ["V256"]
-        rval = self.sparse_dataset.get_data(
+        rval, _, categorical, _ = self.sparse_dataset.get_data(
             dataset_format='array', include_ignore_attributes=True
         )
         self.assertTrue(sparse.issparse(rval))
         self.assertEqual(rval.dtype, np.float32)
         self.assertEqual(rval.shape, (600, 20001))
-        rval, categorical = self.sparse_dataset.get_data(
-            dataset_format='array', include_ignore_attributes=True,
-            return_categorical_indicator=True
-        )
-        self.assertTrue(sparse.issparse(rval))
+
         self.assertEqual(len(categorical), 20001)
-        rval = self.sparse_dataset.get_data(
+        rval, _, categorical, _ = self.sparse_dataset.get_data(
             dataset_format='array', include_ignore_attributes=False
         )
         self.assertTrue(sparse.issparse(rval))
         self.assertEqual(rval.dtype, np.float32)
         self.assertEqual(rval.shape, (600, 20000))
-        rval, categorical = self.sparse_dataset.get_data(
-            dataset_format='array', include_ignore_attributes=False,
-            return_categorical_indicator=True
-        )
-        self.assertTrue(sparse.issparse(rval))
         self.assertEqual(len(categorical), 20000)
-        # TODO test multiple ignore attributes!
 
     def test_get_sparse_dataset_rowid_and_ignore_and_target(self):
         # TODO: re-add row_id and ignore attributes
         self.sparse_dataset.ignore_attributes = ["V256"]
         self.sparse_dataset.row_id_attribute = ["V512"]
-        X, y = self.sparse_dataset.get_data(
+        X, y, categorical, _ = self.sparse_dataset.get_data(
             dataset_format='array',
             target="class",
             include_row_id=False,
@@ -337,12 +302,7 @@ class OpenMLDatasetTestSparse(TestBase):
         self.assertEqual(X.dtype, np.float32)
         self.assertIn(y.dtype, [np.int32, np.int64])
         self.assertEqual(X.shape, (600, 19998))
-        X, y, categorical = self.sparse_dataset.get_data(
-            dataset_format='array',
-            target="class",
-            return_categorical_indicator=True,
-        )
-        self.assertTrue(sparse.issparse(X))
+
         self.assertEqual(len(categorical), 19998)
         self.assertListEqual(categorical, [False] * 19998)
         self.assertEqual(y.shape, (600, ))
diff --git a/tests/test_datasets/test_dataset_functions.py b/tests/test_datasets/test_dataset_functions.py
index 38fcb7c5..ca60be11 100644
--- a/tests/test_datasets/test_dataset_functions.py
+++ b/tests/test_datasets/test_dataset_functions.py
@@ -385,7 +385,7 @@ class TestOpenMLDataset(TestBase):
 
     def test_get_dataset_sparse(self):
         dataset = openml.datasets.get_dataset(102, download_data=False)
-        X = dataset.get_data(dataset_format='array')
+        X, *_ = dataset.get_data(dataset_format='array')
         self.assertIsInstance(X, scipy.sparse.csr_matrix)
 
     def test_download_rowid(self):