From 523790647d5f322fde761d10ab0e82a9f54858dd Mon Sep 17 00:00:00 2001 From: naman9271 Date: Sun, 16 Nov 2025 11:09:56 +0530 Subject: [PATCH 01/11] test_dataset migrated succesfully --- tests/test_datasets/test_dataset.py | 663 +++++++++++++++------------- 1 file changed, 346 insertions(+), 317 deletions(-) diff --git a/tests/test_datasets/test_dataset.py b/tests/test_datasets/test_dataset.py index 86a4d3f577..c254437453 100644 --- a/tests/test_datasets/test_dataset.py +++ b/tests/test_datasets/test_dataset.py @@ -2,280 +2,302 @@ from __future__ import annotations import os -import unittest.mock from time import time import numpy as np import pandas as pd import pytest -from scipy import sparse import openml from openml.datasets import OpenMLDataFeature, OpenMLDataset from openml.exceptions import PyOpenMLError -from openml.testing import TestBase -import pytest +# Fixtures for datasets +@pytest.fixture(scope="module") +def production_server(): + """Configure to use production server.""" + original_server = openml.config.server + openml.config.server = "https://www.openml.org/api/v1/xml" + yield + openml.config.server = original_server -@pytest.mark.production() -class OpenMLDatasetTest(TestBase): - _multiprocess_can_split_ = True - - def setUp(self): - super().setUp() - self.use_production_server() - - # Load dataset id 2 - dataset 2 is interesting because it contains - # missing values, categorical features etc. - self._dataset = None - # titanic as missing values, categories, and string - self._titanic = None - # these datasets have some boolean features - self._pc4 = None - self._jm1 = None - self._iris = None - - @property - def dataset(self): - if self._dataset is None: - self._dataset = openml.datasets.get_dataset(2, download_data=False) - return self._dataset - - @property - def titanic(self): - if self._titanic is None: - self._titanic = openml.datasets.get_dataset(40945, download_data=False) - return self._titanic - - @property - def pc4(self): - if self._pc4 is None: - self._pc4 = openml.datasets.get_dataset(1049, download_data=False) - return self._pc4 - - @property - def jm1(self): - if self._jm1 is None: - self._jm1 = openml.datasets.get_dataset(1053, download_data=False) - return self._jm1 - - @property - def iris(self): - if self._iris is None: - self._iris = openml.datasets.get_dataset(61, download_data=False) - return self._iris - - def test_repr(self): - # create a bare-bones dataset as would be returned by - # create_dataset - data = openml.datasets.OpenMLDataset(name="somename", description="a description") - str(data) - - def test_init_string_validation(self): - with pytest.raises(ValueError, match="Invalid symbols ' ' in name"): - openml.datasets.OpenMLDataset(name="some name", description="a description") - - with pytest.raises(ValueError, match="Invalid symbols 'ï' in description"): - openml.datasets.OpenMLDataset(name="somename", description="a descriptïon") - - with pytest.raises(ValueError, match="Invalid symbols 'ü' in citation"): - openml.datasets.OpenMLDataset( - name="somename", - description="a description", - citation="Something by Müller", - ) - - def test__unpack_categories_with_nan_likes(self): - # unpack_categories decodes numeric categorical values according to the header - # Containing a 'non' category in the header shouldn't lead to failure. - categories = ["a", "b", None, float("nan"), np.nan] - series = pd.Series([0, 1, None, float("nan"), np.nan, 1, 0]) - clean_series = OpenMLDataset._unpack_categories(series, categories) - - expected_values = ["a", "b", np.nan, np.nan, np.nan, "b", "a"] - self.assertListEqual(list(clean_series.values), expected_values) - self.assertListEqual(list(clean_series.cat.categories.values), list("ab")) - - def test_get_data_pandas(self): - data, _, _, _ = self.titanic.get_data() - assert isinstance(data, pd.DataFrame) - assert data.shape[1] == len(self.titanic.features) - assert data.shape[0] == 1309 - col_dtype = { - "pclass": "uint8", - "survived": "category", - "name": "object", - "sex": "category", - "age": "float64", - "sibsp": "uint8", - "parch": "uint8", - "ticket": "object", - "fare": "float64", - "cabin": "object", - "embarked": "category", - "boat": "object", - "body": "float64", - "home.dest": "object", - } - for col_name in data.columns: - assert data[col_name].dtype.name == col_dtype[col_name] - - X, y, _, _ = self.titanic.get_data( - target=self.titanic.default_target_attribute, - ) - assert isinstance(X, pd.DataFrame) - assert isinstance(y, pd.Series) - assert X.shape == (1309, 13) - assert y.shape == (1309,) - for col_name in X.columns: - assert X[col_name].dtype.name == col_dtype[col_name] - assert y.dtype.name == col_dtype["survived"] - - @pytest.mark.skip("https://github.com/openml/openml-python/issues/1157") - 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() - assert data["defects"].dtype.name == "category" - assert set(data["defects"].cat.categories) == {True, False} - - data, _, _, _ = self.pc4.get_data() - assert data["c"].dtype.name == "category" - assert set(data["c"].cat.categories) == {True, False} - - def _check_expected_type(self, dtype, is_cat, col): - if is_cat: - expected_type = "category" - elif not col.isna().any() and (col.astype("uint8") == col).all(): - expected_type = "uint8" - else: - expected_type = "float64" - - assert dtype.name == expected_type - - @pytest.mark.skip("https://github.com/openml/openml-python/issues/1157") - def test_get_data_with_rowid(self): - self.dataset.row_id_attribute = "condition" - rval, _, categorical, _ = self.dataset.get_data(include_row_id=True) - assert isinstance(rval, pd.DataFrame) - for dtype, is_cat, col in zip(rval.dtypes, categorical, rval): - self._check_expected_type(dtype, is_cat, rval[col]) - assert rval.shape == (898, 39) - assert len(categorical) == 39 - - rval, _, categorical, _ = self.dataset.get_data() - assert isinstance(rval, pd.DataFrame) - for dtype, is_cat, col in zip(rval.dtypes, categorical, rval): - self._check_expected_type(dtype, is_cat, rval[col]) - assert rval.shape == (898, 38) - assert len(categorical) == 38 - - @pytest.mark.skip("https://github.com/openml/openml-python/issues/1157") - def test_get_data_with_target_pandas(self): - X, y, categorical, attribute_names = self.dataset.get_data(target="class") - assert isinstance(X, pd.DataFrame) - for dtype, is_cat, col in zip(X.dtypes, categorical, X): - self._check_expected_type(dtype, is_cat, X[col]) - assert isinstance(y, pd.Series) - assert y.dtype.name == "category" - - assert X.shape == (898, 38) - assert len(attribute_names) == 38 - assert y.shape == (898,) - - assert "class" not in attribute_names - - def test_get_data_rowid_and_ignore_and_target(self): - self.dataset.ignore_attribute = ["condition"] - self.dataset.row_id_attribute = ["hardness"] - X, y, categorical, names = self.dataset.get_data(target="class") - assert X.shape == (898, 36) - assert len(categorical) == 36 - cats = [True] * 3 + [False, True, True, False] + [True] * 23 + [False] * 3 + [True] * 3 - self.assertListEqual(categorical, cats) - assert y.shape == (898,) - - @pytest.mark.skip("https://github.com/openml/openml-python/issues/1157") - def test_get_data_with_ignore_attributes(self): - self.dataset.ignore_attribute = ["condition"] - rval, _, categorical, _ = self.dataset.get_data(include_ignore_attribute=True) - for dtype, is_cat, col in zip(rval.dtypes, categorical, rval): - self._check_expected_type(dtype, is_cat, rval[col]) - assert rval.shape == (898, 39) - assert len(categorical) == 39 - - rval, _, categorical, _ = self.dataset.get_data(include_ignore_attribute=False) - for dtype, is_cat, col in zip(rval.dtypes, categorical, rval): - self._check_expected_type(dtype, is_cat, rval[col]) - assert rval.shape == (898, 38) - assert len(categorical) == 38 - - def test_get_data_with_nonexisting_class(self): - # 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") - assert list(y.dtype.categories) == ["1", "2", "3", "4", "5", "U"] - - def test_get_data_corrupt_pickle(self): - # Lazy loaded dataset, populate cache. - self.iris.get_data() - # Corrupt pickle file, overwrite as empty. - with open(self.iris.data_pickle_file, "w") as fh: - fh.write("") - # Despite the corrupt file, the data should be loaded from the ARFF file. - # A warning message is written to the python logger. - xy, _, _, _ = self.iris.get_data() - assert isinstance(xy, pd.DataFrame) - assert xy.shape == (150, 5) - - def test_lazy_loading_metadata(self): - # Initial Setup - did_cache_dir = openml.utils._create_cache_directory_for_id( - openml.datasets.functions.DATASETS_CACHE_DIR_NAME, - 2, - ) - _compare_dataset = openml.datasets.get_dataset( - 2, - download_data=False, - download_features_meta_data=True, - download_qualities=True, - ) - change_time = os.stat(did_cache_dir).st_mtime - - # Test with cache - _dataset = openml.datasets.get_dataset( - 2, - download_data=False, - download_features_meta_data=False, - download_qualities=False, - ) - assert change_time == os.stat(did_cache_dir).st_mtime - assert _dataset.features == _compare_dataset.features - assert _dataset.qualities == _compare_dataset.qualities - - # -- Test without cache - openml.utils._remove_cache_dir_for_id( - openml.datasets.functions.DATASETS_CACHE_DIR_NAME, - did_cache_dir, - ) - _dataset = openml.datasets.get_dataset( - 2, - download_data=False, - download_features_meta_data=False, - download_qualities=False, +@pytest.fixture(scope="module") +def anneal_dataset(production_server): + """Load dataset id 2 - contains missing values, categorical features etc.""" + return openml.datasets.get_dataset(2, download_data=False) + + +@pytest.fixture(scope="module") +def titanic_dataset(production_server): + """Titanic dataset - has missing values, categories, and string.""" + return openml.datasets.get_dataset(40945, download_data=False) + + +@pytest.fixture(scope="module") +def pc4_dataset(production_server): + """PC4 dataset - has some boolean features.""" + return openml.datasets.get_dataset(1049, download_data=False) + + +@pytest.fixture(scope="module") +def jm1_dataset(production_server): + """JM1 dataset - has some boolean features.""" + return openml.datasets.get_dataset(1053, download_data=False) + + +@pytest.fixture(scope="module") +def iris_dataset(production_server): + """Iris dataset.""" + return openml.datasets.get_dataset(61, download_data=False) + + +def test_repr(): + """Test dataset repr doesn't crash.""" + # create a bare-bones dataset as would be returned by + # create_dataset + data = openml.datasets.OpenMLDataset(name="somename", description="a description") + str(data) + + +def test_init_string_validation(): + """Test that invalid characters in dataset fields raise ValueError.""" + with pytest.raises(ValueError, match="Invalid symbols ' ' in name"): + openml.datasets.OpenMLDataset(name="some name", description="a description") + + with pytest.raises(ValueError, match="Invalid symbols 'ï' in description"): + openml.datasets.OpenMLDataset(name="somename", description="a descriptïon") + + with pytest.raises(ValueError, match="Invalid symbols 'ü' in citation"): + openml.datasets.OpenMLDataset( + name="somename", + description="a description", + citation="Something by Müller", ) - assert ["description.xml"] == os.listdir(did_cache_dir) - assert change_time != os.stat(did_cache_dir).st_mtime - assert _dataset.features == _compare_dataset.features - assert _dataset.qualities == _compare_dataset.qualities - def test_equality_comparison(self): - self.assertEqual(self.iris, self.iris) - self.assertNotEqual(self.iris, self.titanic) - self.assertNotEqual(self.titanic, "Wrong_object") + +def test__unpack_categories_with_nan_likes(): + """Test that unpacking categories with NaN-like values works correctly.""" + # unpack_categories decodes numeric categorical values according to the header + # Containing a 'non' category in the header shouldn't lead to failure. + categories = ["a", "b", None, float("nan"), np.nan] + series = pd.Series([0, 1, None, float("nan"), np.nan, 1, 0]) + clean_series = OpenMLDataset._unpack_categories(series, categories) + + expected_values = ["a", "b", np.nan, np.nan, np.nan, "b", "a"] + assert list(clean_series.values) == expected_values + assert list(clean_series.cat.categories.values) == list("ab") + +@pytest.mark.production() +def test_get_data_pandas(titanic_dataset): + """Test get_data returns correct pandas DataFrame.""" + data, _, _, _ = titanic_dataset.get_data() + assert isinstance(data, pd.DataFrame) + assert data.shape[1] == len(titanic_dataset.features) + assert data.shape[0] == 1309 + col_dtype = { + "pclass": "uint8", + "survived": "category", + "name": "object", + "sex": "category", + "age": "float64", + "sibsp": "uint8", + "parch": "uint8", + "ticket": "object", + "fare": "float64", + "cabin": "object", + "embarked": "category", + "boat": "object", + "body": "float64", + "home.dest": "object", + } + for col_name in data.columns: + assert data[col_name].dtype.name == col_dtype[col_name] + + X, y, _, _ = titanic_dataset.get_data( + target=titanic_dataset.default_target_attribute, + ) + assert isinstance(X, pd.DataFrame) + assert isinstance(y, pd.Series) + assert X.shape == (1309, 13) + assert y.shape == (1309,) + for col_name in X.columns: + assert X[col_name].dtype.name == col_dtype[col_name] + assert y.dtype.name == col_dtype["survived"] + + +@pytest.mark.production() +@pytest.mark.skip("https://github.com/openml/openml-python/issues/1157") +def test_get_data_boolean_pandas(jm1_dataset, pc4_dataset): + """Test boolean data is correctly converted.""" + # test to check that we are converting properly True and False even + # with some inconsistency when dumping the data on openml + data, _, _, _ = jm1_dataset.get_data() + assert data["defects"].dtype.name == "category" + assert set(data["defects"].cat.categories) == {True, False} + + data, _, _, _ = pc4_dataset.get_data() + assert data["c"].dtype.name == "category" + assert set(data["c"].cat.categories) == {True, False} + + +def _check_expected_type(dtype, is_cat, col): + """Helper to check expected pandas dtype.""" + if is_cat: + expected_type = "category" + elif not col.isna().any() and (col.astype("uint8") == col).all(): + expected_type = "uint8" + else: + expected_type = "float64" + + assert dtype.name == expected_type + +@pytest.mark.production() +@pytest.mark.skip("https://github.com/openml/openml-python/issues/1157") +def test_get_data_with_rowid(anneal_dataset): + """Test get_data with row_id_attribute.""" + anneal_dataset.row_id_attribute = "condition" + rval, _, categorical, _ = anneal_dataset.get_data(include_row_id=True) + assert isinstance(rval, pd.DataFrame) + for dtype, is_cat, col in zip(rval.dtypes, categorical, rval): + _check_expected_type(dtype, is_cat, rval[col]) + assert rval.shape == (898, 39) + assert len(categorical) == 39 + + rval, _, categorical, _ = anneal_dataset.get_data() + assert isinstance(rval, pd.DataFrame) + for dtype, is_cat, col in zip(rval.dtypes, categorical, rval): + _check_expected_type(dtype, is_cat, rval[col]) + assert rval.shape == (898, 38) + assert len(categorical) == 38 + + +@pytest.mark.production() +@pytest.mark.skip("https://github.com/openml/openml-python/issues/1157") +def test_get_data_with_target_pandas(anneal_dataset): + """Test get_data with target specified.""" + X, y, categorical, attribute_names = anneal_dataset.get_data(target="class") + assert isinstance(X, pd.DataFrame) + for dtype, is_cat, col in zip(X.dtypes, categorical, X): + _check_expected_type(dtype, is_cat, X[col]) + assert isinstance(y, pd.Series) + assert y.dtype.name == "category" + + assert X.shape == (898, 38) + assert len(attribute_names) == 38 + assert y.shape == (898,) + + assert "class" not in attribute_names + + +@pytest.mark.production() +def test_get_data_rowid_and_ignore_and_target(anneal_dataset): + """Test get_data with rowid, ignore and target attributes.""" + anneal_dataset.ignore_attribute = ["condition"] + anneal_dataset.row_id_attribute = ["hardness"] + X, y, categorical, names = anneal_dataset.get_data(target="class") + assert X.shape == (898, 36) + assert len(categorical) == 36 + cats = [True] * 3 + [False, True, True, False] + [True] * 23 + [False] * 3 + [True] * 3 + assert categorical == cats + assert y.shape == (898,) + + +@pytest.mark.production() +@pytest.mark.skip("https://github.com/openml/openml-python/issues/1157") +def test_get_data_with_ignore_attributes(anneal_dataset): + """Test get_data with ignore_attribute.""" + anneal_dataset.ignore_attribute = ["condition"] + rval, _, categorical, _ = anneal_dataset.get_data(include_ignore_attribute=True) + for dtype, is_cat, col in zip(rval.dtypes, categorical, rval): + _check_expected_type(dtype, is_cat, rval[col]) + assert rval.shape == (898, 39) + assert len(categorical) == 39 + + rval, _, categorical, _ = anneal_dataset.get_data(include_ignore_attribute=False) + for dtype, is_cat, col in zip(rval.dtypes, categorical, rval): + _check_expected_type(dtype, is_cat, rval[col]) + assert rval.shape == (898, 38) + assert len(categorical) == 38 + + +@pytest.mark.production() +def test_get_data_with_nonexisting_class(anneal_dataset): + """Test dataset with missing class labels.""" + # 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, _, _ = anneal_dataset.get_data("class") + assert list(y.dtype.categories) == ["1", "2", "3", "4", "5", "U"] + + +@pytest.mark.production() +def test_get_data_corrupt_pickle(iris_dataset): + """Test that corrupt pickle files are handled gracefully.""" + # Lazy loaded dataset, populate cache. + iris_dataset.get_data() + # Corrupt pickle file, overwrite as empty. + with open(iris_dataset.data_pickle_file, "w") as fh: + fh.write("") + # Despite the corrupt file, the data should be loaded from the ARFF file. + # A warning message is written to the python logger. + xy, _, _, _ = iris_dataset.get_data() + assert isinstance(xy, pd.DataFrame) + assert xy.shape == (150, 5) + + +@pytest.mark.production() +def test_lazy_loading_metadata(): + """Test lazy loading of dataset metadata.""" + # Initial Setup + did_cache_dir = openml.utils._create_cache_directory_for_id( + openml.datasets.functions.DATASETS_CACHE_DIR_NAME, + 2, + ) + _compare_dataset = openml.datasets.get_dataset( + 2, + download_data=False, + download_features_meta_data=True, + download_qualities=True, + ) + change_time = os.stat(did_cache_dir).st_mtime + + # Test with cache + _dataset = openml.datasets.get_dataset( + 2, + download_data=False, + download_features_meta_data=False, + download_qualities=False, + ) + assert change_time == os.stat(did_cache_dir).st_mtime + assert _dataset.features == _compare_dataset.features + assert _dataset.qualities == _compare_dataset.qualities + + # -- Test without cache + openml.utils._remove_cache_dir_for_id( + openml.datasets.functions.DATASETS_CACHE_DIR_NAME, + did_cache_dir, + ) + + _dataset = openml.datasets.get_dataset( + 2, + download_data=False, + download_features_meta_data=False, + download_qualities=False, + ) + assert ["description.xml"] == os.listdir(did_cache_dir) + assert change_time != os.stat(did_cache_dir).st_mtime + assert _dataset.features == _compare_dataset.features + assert _dataset.qualities == _compare_dataset.qualities + + +@pytest.mark.production() +def test_equality_comparison(iris_dataset, titanic_dataset): + """Test dataset equality comparison.""" + assert iris_dataset == iris_dataset + assert iris_dataset != titanic_dataset + assert titanic_dataset != "Wrong_object" def test_tagging(): @@ -338,65 +360,72 @@ def test_add_illegal_url_ontology(): assert e.code == 1106 +@pytest.fixture(scope="module") +def sparse_dataset(production_server): + """Sparse dataset for testing.""" + return openml.datasets.get_dataset(4136, download_data=False) + + @pytest.mark.production() -class OpenMLDatasetTestSparse(TestBase): - _multiprocess_can_split_ = True - - def setUp(self): - super().setUp() - self.use_production_server() - - self.sparse_dataset = openml.datasets.get_dataset(4136, download_data=False) - - def test_get_sparse_dataset_dataframe_with_target(self): - X, y, _, attribute_names = self.sparse_dataset.get_data(target="class") - assert isinstance(X, pd.DataFrame) - assert isinstance(X.dtypes[0], pd.SparseDtype) - assert X.shape == (600, 20000) - - assert isinstance(y, pd.Series) - assert isinstance(y.dtypes, pd.SparseDtype) - assert y.shape == (600,) - - assert len(attribute_names) == 20000 - assert "class" not in attribute_names - - def test_get_sparse_dataset_dataframe(self): - rval, *_ = self.sparse_dataset.get_data() - assert isinstance(rval, pd.DataFrame) - np.testing.assert_array_equal( - [pd.SparseDtype(np.float32, fill_value=0.0)] * len(rval.dtypes), - rval.dtypes, - ) - assert rval.shape == (600, 20001) - - def test_get_sparse_dataset_rowid_and_ignore_and_target(self): - # TODO: re-add row_id and ignore attributes - self.sparse_dataset.ignore_attribute = ["V256"] - self.sparse_dataset.row_id_attribute = ["V512"] - X, y, categorical, _ = self.sparse_dataset.get_data( - target="class", - include_row_id=False, - include_ignore_attribute=False, - ) - assert all(dtype == pd.SparseDtype(np.float32, fill_value=0.0) for dtype in X.dtypes) - # array format returned dense, but now we only return sparse and let the user handle it. - assert isinstance(y.dtypes, pd.SparseDtype) - assert X.shape == (600, 19998) - - assert len(categorical) == 19998 - self.assertListEqual(categorical, [False] * 19998) - assert y.shape == (600,) - - def test_get_sparse_categorical_data_id_395(self): - dataset = openml.datasets.get_dataset(395, download_data=True) - feature = dataset.features[3758] - assert isinstance(dataset, OpenMLDataset) - assert isinstance(feature, OpenMLDataFeature) - assert dataset.name == "re1.wc" - assert feature.name == "CLASS_LABEL" - assert feature.data_type == "nominal" - assert len(feature.nominal_values) == 25 +def test_get_sparse_dataset_dataframe_with_target(sparse_dataset): + """Test sparse dataset with target.""" + X, y, _, attribute_names = sparse_dataset.get_data(target="class") + assert isinstance(X, pd.DataFrame) + assert isinstance(X.dtypes[0], pd.SparseDtype) + assert X.shape == (600, 20000) + + assert isinstance(y, pd.Series) + assert isinstance(y.dtypes, pd.SparseDtype) + assert y.shape == (600,) + + assert len(attribute_names) == 20000 + assert "class" not in attribute_names + + +@pytest.mark.production() +def test_get_sparse_dataset_dataframe(sparse_dataset): + """Test sparse dataset returns sparse DataFrame.""" + rval, *_ = sparse_dataset.get_data() + assert isinstance(rval, pd.DataFrame) + np.testing.assert_array_equal( + [pd.SparseDtype(np.float32, fill_value=0.0)] * len(rval.dtypes), + rval.dtypes, + ) + assert rval.shape == (600, 20001) + + +@pytest.mark.production() +def test_get_sparse_dataset_rowid_and_ignore_and_target(sparse_dataset): + """Test sparse dataset with row_id, ignore and target attributes.""" + # TODO: re-add row_id and ignore attributes + sparse_dataset.ignore_attribute = ["V256"] + sparse_dataset.row_id_attribute = ["V512"] + X, y, categorical, _ = sparse_dataset.get_data( + target="class", + include_row_id=False, + include_ignore_attribute=False, + ) + assert all(dtype == pd.SparseDtype(np.float32, fill_value=0.0) for dtype in X.dtypes) + # array format returned dense, but now we only return sparse and let the user handle it. + assert isinstance(y.dtypes, pd.SparseDtype) + assert X.shape == (600, 19998) + + assert len(categorical) == 19998 + assert categorical == [False] * 19998 + assert y.shape == (600,) + + +@pytest.mark.production() +def test_get_sparse_categorical_data_id_395(): + """Test sparse categorical dataset.""" + dataset = openml.datasets.get_dataset(395, download_data=True) + feature = dataset.features[3758] + assert isinstance(dataset, OpenMLDataset) + assert isinstance(feature, OpenMLDataFeature) + assert dataset.name == "re1.wc" + assert feature.name == "CLASS_LABEL" + assert feature.data_type == "nominal" + assert len(feature.nominal_values) == 25 def test__read_features(mocker, workdir, static_cache_dir): From 4d6b9ece9fc5f910040f6f6c4b9b436025b50470 Mon Sep 17 00:00:00 2001 From: PGijsbers Date: Tue, 10 Nov 2026 15:12:17 +0100 Subject: [PATCH 02/11] Fixture was needlessly narrowly scoped --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index c96cbf0915..ffce2887bd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -333,7 +333,7 @@ def with_test_cache(test_files_directory, request): shutil.rmtree(tmp_cache) -@pytest.fixture +@pytest.fixture(scope="session") def static_cache_dir(): return Path(__file__).parent / "files" From 2ee16bebebafd77eefc0d0e4aaaa82c30796303f Mon Sep 17 00:00:00 2001 From: PGijsbers Date: Tue, 10 Nov 2026 15:13:38 +0100 Subject: [PATCH 03/11] Fix lazy load test --- tests/test_datasets/test_dataset.py | 46 ++++++++++++++++++----------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/tests/test_datasets/test_dataset.py b/tests/test_datasets/test_dataset.py index eeead23fd3..fb591482da 100644 --- a/tests/test_datasets/test_dataset.py +++ b/tests/test_datasets/test_dataset.py @@ -2,11 +2,14 @@ from __future__ import annotations import os +from pathlib import Path +import shutil from time import time import numpy as np import pandas as pd import pytest +import requests import openml from openml.datasets import OpenMLDataFeature, OpenMLDataset @@ -14,10 +17,11 @@ # Fixtures for datasets @pytest.fixture(scope="module") -def production_server(): +def production_server(static_cache_dir): """Configure to use production server.""" original_server = openml.config.server openml.config.server = "https://www.openml.org/api/v1/xml" + openml.config.set_root_cache_directory(static_cache_dir) yield openml.config.server = original_server @@ -251,49 +255,55 @@ def test_get_data_corrupt_pickle(iris_dataset): assert xy.shape == (150, 5) -@pytest.mark.production_server -def test_lazy_loading_metadata(): +@pytest.mark.test_server +def test_lazy_loading_metadata(mocker): """Test lazy loading of dataset metadata.""" - # Initial Setup - did_cache_dir = openml.utils._create_cache_directory_for_id( - openml.datasets.functions.DATASETS_CACHE_DIR_NAME, - 2, - ) + # The test automatically executes with a temporary cache directory, + # that means files should be downloaded: + spy = mocker.spy(requests.sessions.Session, "request") _compare_dataset = openml.datasets.get_dataset( 2, download_data=False, download_features_meta_data=True, download_qualities=True, ) - change_time = os.stat(did_cache_dir).st_mtime + eager_download_call_count = spy.call_count + assert eager_download_call_count > 0, ( + "Eager download should make network call if cache is empty." + ) - # Test with cache _dataset = openml.datasets.get_dataset( 2, download_data=False, download_features_meta_data=False, download_qualities=False, ) - assert change_time == os.stat(did_cache_dir).st_mtime + + assert spy.call_count == eager_download_call_count, ( + "Lazy instantiation with description in cache shouldn't make network call." + ) assert _dataset.features == _compare_dataset.features assert _dataset.qualities == _compare_dataset.qualities - - # -- Test without cache - openml.utils._remove_cache_dir_for_id( - openml.datasets.functions.DATASETS_CACHE_DIR_NAME, - did_cache_dir, + assert spy.call_count == eager_download_call_count, ( + "Lazy loading with files in cache shouldn't make network calls." ) + # -- Test without cache + shutil.rmtree(openml.config.get_cache_directory()) _dataset = openml.datasets.get_dataset( 2, download_data=False, download_features_meta_data=False, download_qualities=False, ) - assert ["description.xml"] == os.listdir(did_cache_dir) - assert change_time != os.stat(did_cache_dir).st_mtime + assert _dataset.features == _compare_dataset.features assert _dataset.qualities == _compare_dataset.qualities + lazy_download_call_count = spy.call_count - eager_download_call_count + assert lazy_download_call_count == eager_download_call_count, ( + "Lazy fetching of files should result in the same number of calls " + "if all attributes have been accessed." + ) @pytest.mark.production_server From 34230915c3a6778998d15b351a88eac44dcc3018 Mon Sep 17 00:00:00 2001 From: PGijsbers Date: Tue, 10 Nov 2026 15:18:07 +0100 Subject: [PATCH 04/11] Remove test since it was written for numpy data loading --- tests/test_datasets/test_dataset.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/tests/test_datasets/test_dataset.py b/tests/test_datasets/test_dataset.py index fb591482da..f2d4fb3f3e 100644 --- a/tests/test_datasets/test_dataset.py +++ b/tests/test_datasets/test_dataset.py @@ -2,7 +2,6 @@ from __future__ import annotations import os -from pathlib import Path import shutil from time import time @@ -204,7 +203,7 @@ def test_get_data_rowid_and_ignore_and_target(anneal_dataset): """Test get_data with rowid, ignore and target attributes.""" anneal_dataset.ignore_attribute = ["condition"] anneal_dataset.row_id_attribute = ["hardness"] - X, y, categorical, names = anneal_dataset.get_data(target="class") + X, y, categorical, _names = anneal_dataset.get_data(target="class") assert X.shape == (898, 36) assert len(categorical) == 36 cats = [True] * 3 + [False, True, True, False] + [True] * 23 + [False] * 3 + [True] * 3 @@ -230,16 +229,6 @@ def test_get_data_with_ignore_attributes(anneal_dataset): assert len(categorical) == 38 -@pytest.mark.production_server -def test_get_data_with_nonexisting_class(anneal_dataset): - """Test dataset with missing class labels.""" - # 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, _, _ = anneal_dataset.get_data("class") - assert list(y.dtype.categories) == ["1", "2", "3", "4", "5", "U"] - - @pytest.mark.production_server def test_get_data_corrupt_pickle(iris_dataset): """Test that corrupt pickle files are handled gracefully.""" From e683dc9c87b9514c084c8285681023351cfbff0d Mon Sep 17 00:00:00 2001 From: PGijsbers Date: Tue, 10 Nov 2026 15:54:39 +0100 Subject: [PATCH 05/11] Fix access to sparse dataset, use test server for pickle test --- tests/test_datasets/test_dataset.py | 39 ++++++++++++++++++----------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/tests/test_datasets/test_dataset.py b/tests/test_datasets/test_dataset.py index f2d4fb3f3e..724091f61f 100644 --- a/tests/test_datasets/test_dataset.py +++ b/tests/test_datasets/test_dataset.py @@ -14,6 +14,9 @@ from openml.datasets import OpenMLDataFeature, OpenMLDataset +SPARSE_DATASET_ID = 4136 + + # Fixtures for datasets @pytest.fixture(scope="module") def production_server(static_cache_dir): @@ -229,14 +232,25 @@ def test_get_data_with_ignore_attributes(anneal_dataset): assert len(categorical) == 38 -@pytest.mark.production_server -def test_get_data_corrupt_pickle(iris_dataset): - """Test that corrupt pickle files are handled gracefully.""" - # Lazy loaded dataset, populate cache. +@pytest.mark.test_server +def test_get_data_corrupt_pickle(): + """Test that corrupt pickle files are handled gracefully. + + The pickle file is stored for fast-load convenience only, but the + primary file is the parquet (or aff) file. If a pickle file is corrupted + the file should be loaded from the parquet (or arff) file instead. + + This feature will be removed when arff support is removed (#1027). + """ + iris_dataset = openml.datasets.get_dataset(128, download_data=True) + # Only on first load would the pickle file actually be created. iris_dataset.get_data() - # Corrupt pickle file, overwrite as empty. + assert os.stat(iris_dataset.data_pickle_file).st_size > 0 + with open(iris_dataset.data_pickle_file, "w") as fh: fh.write("") + assert os.stat(iris_dataset.data_pickle_file).st_size == 0 + # Despite the corrupt file, the data should be loaded from the ARFF file. # A warning message is written to the python logger. xy, _, _, _ = iris_dataset.get_data() @@ -371,15 +385,10 @@ def test_add_illegal_url_ontology(): assert e.code == 1106 # noqa: PT017 -@pytest.fixture(scope="module") -def sparse_dataset(production_server): - """Sparse dataset for testing.""" - return openml.datasets.get_dataset(4136, download_data=False) - - @pytest.mark.production_server -def test_get_sparse_dataset_dataframe_with_target(sparse_dataset): +def test_get_sparse_dataset_dataframe_with_target(): """Test sparse dataset with target.""" + sparse_dataset = openml.datasets.get_dataset(4136, download_data=False) X, y, _, attribute_names = sparse_dataset.get_data(target="class") assert isinstance(X, pd.DataFrame) assert isinstance(X.dtypes.iloc[0], pd.SparseDtype) @@ -394,7 +403,8 @@ def test_get_sparse_dataset_dataframe_with_target(sparse_dataset): @pytest.mark.production_server -def test_get_sparse_dataset_dataframe(sparse_dataset): +def test_get_sparse_dataset_dataframe(): + sparse_dataset = openml.datasets.get_dataset(4136, download_data=False) """Test sparse dataset returns sparse DataFrame.""" rval, *_ = sparse_dataset.get_data() assert isinstance(rval, pd.DataFrame) @@ -406,8 +416,9 @@ def test_get_sparse_dataset_dataframe(sparse_dataset): @pytest.mark.production_server -def test_get_sparse_dataset_rowid_and_ignore_and_target(sparse_dataset): +def test_get_sparse_dataset_rowid_and_ignore_and_target(): """Test sparse dataset with row_id, ignore and target attributes.""" + sparse_dataset = openml.datasets.get_dataset(4136, download_data=False) # TODO: re-add row_id and ignore attributes sparse_dataset.ignore_attribute = ["V256"] sparse_dataset.row_id_attribute = ["V512"] From fd6370cc31a99e8e28587393d1d1d167038547ba Mon Sep 17 00:00:00 2001 From: PGijsbers Date: Tue, 10 Nov 2026 15:59:15 +0100 Subject: [PATCH 06/11] Remove use of production server for equality test --- tests/test_datasets/test_dataset.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/test_datasets/test_dataset.py b/tests/test_datasets/test_dataset.py index 724091f61f..79b43276ba 100644 --- a/tests/test_datasets/test_dataset.py +++ b/tests/test_datasets/test_dataset.py @@ -13,7 +13,6 @@ import openml from openml.datasets import OpenMLDataFeature, OpenMLDataset - SPARSE_DATASET_ID = 4136 @@ -309,12 +308,15 @@ def test_lazy_loading_metadata(mocker): ) -@pytest.mark.production_server -def test_equality_comparison(iris_dataset, titanic_dataset): +@pytest.mark.test_server +def test_equality_comparison(): """Test dataset equality comparison.""" - assert iris_dataset == iris_dataset - assert iris_dataset != titanic_dataset - assert titanic_dataset != "Wrong_object" + dataset_a = openml.datasets.get_dataset(1) + dataset_b = openml.datasets.get_dataset(2) + + assert dataset_a == dataset_a + assert dataset_a != dataset_b + assert dataset_a != "not any dataset" @pytest.mark.test_server From f75a8fc884e99e3b0b5359e7562d788a16050393 Mon Sep 17 00:00:00 2001 From: PGijsbers Date: Tue, 10 Nov 2026 16:15:52 +0100 Subject: [PATCH 07/11] Avoid module fixtures because cache interactions are complex --- tests/test_datasets/test_dataset.py | 80 +++++++++-------------------- 1 file changed, 25 insertions(+), 55 deletions(-) diff --git a/tests/test_datasets/test_dataset.py b/tests/test_datasets/test_dataset.py index 79b43276ba..885a30f0b3 100644 --- a/tests/test_datasets/test_dataset.py +++ b/tests/test_datasets/test_dataset.py @@ -16,47 +16,6 @@ SPARSE_DATASET_ID = 4136 -# Fixtures for datasets -@pytest.fixture(scope="module") -def production_server(static_cache_dir): - """Configure to use production server.""" - original_server = openml.config.server - openml.config.server = "https://www.openml.org/api/v1/xml" - openml.config.set_root_cache_directory(static_cache_dir) - yield - openml.config.server = original_server - - -@pytest.fixture(scope="module") -def anneal_dataset(production_server): - """Load dataset id 2 - contains missing values, categorical features etc.""" - return openml.datasets.get_dataset(2, download_data=False) - - -@pytest.fixture(scope="module") -def titanic_dataset(production_server): - """Titanic dataset - has missing values, categories, and string.""" - return openml.datasets.get_dataset(40945, download_data=False) - - -@pytest.fixture(scope="module") -def pc4_dataset(production_server): - """PC4 dataset - has some boolean features.""" - return openml.datasets.get_dataset(1049, download_data=False) - - -@pytest.fixture(scope="module") -def jm1_dataset(production_server): - """JM1 dataset - has some boolean features.""" - return openml.datasets.get_dataset(1053, download_data=False) - - -@pytest.fixture(scope="module") -def iris_dataset(production_server): - """Iris dataset.""" - return openml.datasets.get_dataset(61, download_data=False) - - def test_repr(): """Test dataset repr doesn't crash.""" # create a bare-bones dataset as would be returned by @@ -95,8 +54,9 @@ def test__unpack_categories_with_nan_likes(): @pytest.mark.production_server -def test_get_data_pandas(titanic_dataset): +def test_get_data_pandas(): """Test get_data returns correct pandas DataFrame.""" + titanic_dataset = openml.datasetes.get_dataset(40945) data, _, _, _ = titanic_dataset.get_data() assert isinstance(data, pd.DataFrame) assert data.shape[1] == len(titanic_dataset.features) @@ -136,15 +96,16 @@ def test_get_data_pandas(titanic_dataset): @pytest.mark.production_server -@pytest.mark.skip("https://github.com/openml/openml-python/issues/1157") -def test_get_data_boolean_pandas(jm1_dataset, pc4_dataset): +def test_get_data_boolean_pandas(): """Test boolean data is correctly converted.""" # test to check that we are converting properly True and False even # with some inconsistency when dumping the data on openml + jm1_dataset = openml.datasets.get_dataset(1053) data, _, _, _ = jm1_dataset.get_data() assert data["defects"].dtype.name == "category" assert set(data["defects"].cat.categories) == {True, False} + pc4_dataset = openml.datasets.get_dataset(1049) data, _, _, _ = pc4_dataset.get_data() assert data["c"].dtype.name == "category" assert set(data["c"].cat.categories) == {True, False} @@ -162,10 +123,12 @@ def _check_expected_type(dtype, is_cat, col): assert dtype.name == expected_type -@pytest.mark.production_server -@pytest.mark.skip("https://github.com/openml/openml-python/issues/1157") -def test_get_data_with_rowid(anneal_dataset): +@pytest.mark.test_server +def test_get_data_with_rowid(): """Test get_data with row_id_attribute.""" + if "localhost" in openml.config.server: + pytest.skip(reason="This test doesn't currently work with local services.") + anneal_dataset = openml.datasets.get_dataset(138) anneal_dataset.row_id_attribute = "condition" rval, _, categorical, _ = anneal_dataset.get_data(include_row_id=True) assert isinstance(rval, pd.DataFrame) @@ -182,10 +145,12 @@ def test_get_data_with_rowid(anneal_dataset): assert len(categorical) == 38 -@pytest.mark.production_server -@pytest.mark.skip("https://github.com/openml/openml-python/issues/1157") -def test_get_data_with_target_pandas(anneal_dataset): +@pytest.mark.test_server +def test_get_data_with_target_pandas(): """Test get_data with target specified.""" + if "localhost" in openml.config.server: + pytest.skip(reason="This test doesn't currently work with local services.") + anneal_dataset = openml.datasets.get_dataset(138) X, y, categorical, attribute_names = anneal_dataset.get_data(target="class") assert isinstance(X, pd.DataFrame) for dtype, is_cat, col in zip(X.dtypes, categorical, X, strict=False): @@ -200,9 +165,12 @@ def test_get_data_with_target_pandas(anneal_dataset): assert "class" not in attribute_names -@pytest.mark.production_server -def test_get_data_rowid_and_ignore_and_target(anneal_dataset): +@pytest.mark.test_server +def test_get_data_rowid_and_ignore_and_target(): """Test get_data with rowid, ignore and target attributes.""" + if "localhost" in openml.config.server: + pytest.skip(reason="This test doesn't currently work with local services.") + anneal_dataset = openml.datasets.get_dataset(138) anneal_dataset.ignore_attribute = ["condition"] anneal_dataset.row_id_attribute = ["hardness"] X, y, categorical, _names = anneal_dataset.get_data(target="class") @@ -213,10 +181,12 @@ def test_get_data_rowid_and_ignore_and_target(anneal_dataset): assert y.shape == (898,) -@pytest.mark.production_server -@pytest.mark.skip("https://github.com/openml/openml-python/issues/1157") -def test_get_data_with_ignore_attributes(anneal_dataset): +@pytest.mark.test_server +def test_get_data_with_ignore_attributes(): """Test get_data with ignore_attribute.""" + if "localhost" in openml.config.server: + pytest.skip(reason="This test doesn't currently work with local services.") + anneal_dataset = openml.datasets.get_dataset(138) anneal_dataset.ignore_attribute = ["condition"] rval, _, categorical, _ = anneal_dataset.get_data(include_ignore_attribute=True) for dtype, is_cat, col in zip(rval.dtypes, categorical, rval, strict=False): From a5a84323f57fd7697022adfaebcc7f19489b4ac3 Mon Sep 17 00:00:00 2001 From: PGijsbers Date: Wed, 11 Nov 2026 10:24:50 +0100 Subject: [PATCH 08/11] Use the cached version of the anneal dataset --- tests/test_datasets/test_dataset.py | 34 +++++++++++------------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/tests/test_datasets/test_dataset.py b/tests/test_datasets/test_dataset.py index 885a30f0b3..182bd731dd 100644 --- a/tests/test_datasets/test_dataset.py +++ b/tests/test_datasets/test_dataset.py @@ -56,7 +56,7 @@ def test__unpack_categories_with_nan_likes(): @pytest.mark.production_server def test_get_data_pandas(): """Test get_data returns correct pandas DataFrame.""" - titanic_dataset = openml.datasetes.get_dataset(40945) + titanic_dataset = openml.datasets.get_dataset(40945) data, _, _, _ = titanic_dataset.get_data() assert isinstance(data, pd.DataFrame) assert data.shape[1] == len(titanic_dataset.features) @@ -123,12 +123,10 @@ def _check_expected_type(dtype, is_cat, col): assert dtype.name == expected_type -@pytest.mark.test_server -def test_get_data_with_rowid(): +def test_get_data_with_rowid(static_cache_dir): """Test get_data with row_id_attribute.""" - if "localhost" in openml.config.server: - pytest.skip(reason="This test doesn't currently work with local services.") - anneal_dataset = openml.datasets.get_dataset(138) + openml.config.set_root_cache_directory(static_cache_dir) + anneal_dataset = openml.datasets.get_dataset(2) anneal_dataset.row_id_attribute = "condition" rval, _, categorical, _ = anneal_dataset.get_data(include_row_id=True) assert isinstance(rval, pd.DataFrame) @@ -145,12 +143,10 @@ def test_get_data_with_rowid(): assert len(categorical) == 38 -@pytest.mark.test_server -def test_get_data_with_target_pandas(): +def test_get_data_with_target_pandas(static_cache_dir): """Test get_data with target specified.""" - if "localhost" in openml.config.server: - pytest.skip(reason="This test doesn't currently work with local services.") - anneal_dataset = openml.datasets.get_dataset(138) + openml.config.set_root_cache_directory(static_cache_dir) + anneal_dataset = openml.datasets.get_dataset(2) X, y, categorical, attribute_names = anneal_dataset.get_data(target="class") assert isinstance(X, pd.DataFrame) for dtype, is_cat, col in zip(X.dtypes, categorical, X, strict=False): @@ -165,12 +161,10 @@ def test_get_data_with_target_pandas(): assert "class" not in attribute_names -@pytest.mark.test_server -def test_get_data_rowid_and_ignore_and_target(): +def test_get_data_rowid_and_ignore_and_target(static_cache_dir): """Test get_data with rowid, ignore and target attributes.""" - if "localhost" in openml.config.server: - pytest.skip(reason="This test doesn't currently work with local services.") - anneal_dataset = openml.datasets.get_dataset(138) + openml.config.set_root_cache_directory(static_cache_dir) + anneal_dataset = openml.datasets.get_dataset(2) anneal_dataset.ignore_attribute = ["condition"] anneal_dataset.row_id_attribute = ["hardness"] X, y, categorical, _names = anneal_dataset.get_data(target="class") @@ -181,12 +175,10 @@ def test_get_data_rowid_and_ignore_and_target(): assert y.shape == (898,) -@pytest.mark.test_server -def test_get_data_with_ignore_attributes(): +def test_get_data_with_ignore_attributes(static_cache_dir): """Test get_data with ignore_attribute.""" - if "localhost" in openml.config.server: - pytest.skip(reason="This test doesn't currently work with local services.") - anneal_dataset = openml.datasets.get_dataset(138) + openml.config.set_root_cache_directory(static_cache_dir) + anneal_dataset = openml.datasets.get_dataset(2) anneal_dataset.ignore_attribute = ["condition"] rval, _, categorical, _ = anneal_dataset.get_data(include_ignore_attribute=True) for dtype, is_cat, col in zip(rval.dtypes, categorical, rval, strict=False): From d1ade1c8f096907dc48568e7b27a81552a505cfe Mon Sep 17 00:00:00 2001 From: PGijsbers Date: Wed, 11 Nov 2026 11:12:46 +0100 Subject: [PATCH 09/11] Fix test that broke after default parquet loading --- tests/test_datasets/test_dataset.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/test_datasets/test_dataset.py b/tests/test_datasets/test_dataset.py index 182bd731dd..e21ce4eb29 100644 --- a/tests/test_datasets/test_dataset.py +++ b/tests/test_datasets/test_dataset.py @@ -96,10 +96,14 @@ def test_get_data_pandas(): @pytest.mark.production_server -def test_get_data_boolean_pandas(): - """Test boolean data is correctly converted.""" - # test to check that we are converting properly True and False even - # with some inconsistency when dumping the data on openml +def test_get_data_boolean_pandas(monkeypatch): + """Test boolean data is converted to categorical when loading from arff.""" + # At some point we decided to convert bool-ey features to + # categories, because from the ARFF file we technically can't + # specify which is which (#1106, #1157). + # This seems mostly historical after conversion to parquet, + # which does load as boolean. + monkeypatch.setenv(openml.config.OPENML_SKIP_PARQUET_ENV_VAR, "true") jm1_dataset = openml.datasets.get_dataset(1053) data, _, _, _ = jm1_dataset.get_data() assert data["defects"].dtype.name == "category" @@ -127,6 +131,7 @@ def test_get_data_with_rowid(static_cache_dir): """Test get_data with row_id_attribute.""" openml.config.set_root_cache_directory(static_cache_dir) anneal_dataset = openml.datasets.get_dataset(2) + anneal_dataset.row_id_attribute = "condition" rval, _, categorical, _ = anneal_dataset.get_data(include_row_id=True) assert isinstance(rval, pd.DataFrame) @@ -246,8 +251,9 @@ def test_lazy_loading_metadata(mocker): assert spy.call_count == eager_download_call_count, ( "Lazy instantiation with description in cache shouldn't make network call." ) + assert _dataset.features == _compare_dataset.features - assert _dataset.qualities == _compare_dataset.qualities + assert _dataset.qualities == pytest.approx(_compare_dataset.qualities, nan_ok=True) assert spy.call_count == eager_download_call_count, ( "Lazy loading with files in cache shouldn't make network calls." ) @@ -262,7 +268,7 @@ def test_lazy_loading_metadata(mocker): ) assert _dataset.features == _compare_dataset.features - assert _dataset.qualities == _compare_dataset.qualities + assert _dataset.qualities == pytest.approx(_compare_dataset.qualities, nan_ok=True) lazy_download_call_count = spy.call_count - eager_download_call_count assert lazy_download_call_count == eager_download_call_count, ( "Lazy fetching of files should result in the same number of calls " From e630c8714b39e6ad109fe5440fcb60dd5733539d Mon Sep 17 00:00:00 2001 From: PGijsbers Date: Wed, 11 Nov 2026 11:16:17 +0100 Subject: [PATCH 10/11] Use pathlib over os --- tests/test_datasets/test_dataset.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test_datasets/test_dataset.py b/tests/test_datasets/test_dataset.py index e21ce4eb29..e82c508ede 100644 --- a/tests/test_datasets/test_dataset.py +++ b/tests/test_datasets/test_dataset.py @@ -2,6 +2,7 @@ from __future__ import annotations import os +from pathlib import Path import shutil from time import time @@ -211,11 +212,11 @@ def test_get_data_corrupt_pickle(): iris_dataset = openml.datasets.get_dataset(128, download_data=True) # Only on first load would the pickle file actually be created. iris_dataset.get_data() - assert os.stat(iris_dataset.data_pickle_file).st_size > 0 + iris_data_file = Path(iris_dataset.data_pickle_file) + assert iris_data_file.stat().st_size > 0 - with open(iris_dataset.data_pickle_file, "w") as fh: - fh.write("") - assert os.stat(iris_dataset.data_pickle_file).st_size == 0 + iris_data_file.write_bytes(b"") + assert iris_data_file.stat().st_size == 0 # Despite the corrupt file, the data should be loaded from the ARFF file. # A warning message is written to the python logger. From 512a484b4a5062a7a06001b2771dc2a22f62c7a0 Mon Sep 17 00:00:00 2001 From: PGijsbers Date: Wed, 11 Nov 2026 11:17:31 +0100 Subject: [PATCH 11/11] update equality test --- tests/test_datasets/test_dataset.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_datasets/test_dataset.py b/tests/test_datasets/test_dataset.py index e82c508ede..724a24ca44 100644 --- a/tests/test_datasets/test_dataset.py +++ b/tests/test_datasets/test_dataset.py @@ -2,8 +2,8 @@ from __future__ import annotations import os -from pathlib import Path import shutil +from pathlib import Path from time import time import numpy as np @@ -281,9 +281,10 @@ def test_lazy_loading_metadata(mocker): def test_equality_comparison(): """Test dataset equality comparison.""" dataset_a = openml.datasets.get_dataset(1) + dataset_a2 = openml.datasets.get_dataset(1) dataset_b = openml.datasets.get_dataset(2) - assert dataset_a == dataset_a + assert dataset_a == dataset_a2 assert dataset_a != dataset_b assert dataset_a != "not any dataset"