diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 21e59805fa143..c00c5ac867f38 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -340,6 +340,7 @@ I/O - Bug in :class:`HDFStore` that caused it to set to ``int64`` the dtype of a ``datetime64`` column when reading a DataFrame in Python 3 from fixed format written in Python 2 (:issue:`31750`) - Bug in :meth:`read_excel` where a UTF-8 string with a high surrogate would cause a segmentation violation (:issue:`23809`) - Bug in :meth:`read_csv` was causing a file descriptor leak on an empty file (:issue:`31488`) +- :meth:`HDFStore.keys` now tries to get the list of native pandas tables first, and if there are none, it gets the native HDF5 table names (:issue:`29916`) Plotting diff --git a/pandas/io/pytables.py b/pandas/io/pytables.py index 7aeed5c316d7f..916b3149f091e 100644 --- a/pandas/io/pytables.py +++ b/pandas/io/pytables.py @@ -583,13 +583,20 @@ def __exit__(self, exc_type, exc_value, traceback): def keys(self) -> List[str]: """ Return a list of keys corresponding to objects stored in HDFStore. + If the store contains pandas native tables, it will return their names. + Otherwise the list of names of HDF5 Table objects will be returned. Returns ------- list List of ABSOLUTE path-names (e.g. have the leading '/'). """ - return [n._v_pathname for n in self.groups()] + objects = [n._v_pathname for n in self.groups()] + if objects: + return objects + + assert self._handle is not None # mypy + return [n._v_pathname for n in self._handle.walk_nodes("/", classname="Table")] def __iter__(self): return iter(self.keys()) diff --git a/pandas/tests/io/pytables/test_store.py b/pandas/tests/io/pytables/test_store.py index 61ca2e7f5f19d..e55c9157cac1f 100644 --- a/pandas/tests/io/pytables/test_store.py +++ b/pandas/tests/io/pytables/test_store.py @@ -296,6 +296,29 @@ def test_keys(self, setup_path): assert set(store.keys()) == expected assert set(store) == expected + def test_non_pandas_keys(self, setup_path): + # GH 29916 + class Table1(tables.IsDescription): + value1 = tables.Float32Col() + + class Table2(tables.IsDescription): + value2 = tables.Float32Col() + + class Table3(tables.IsDescription): + value3 = tables.Float32Col() + + with ensure_clean_path(setup_path) as path: + with tables.open_file(path, mode="w") as h5file: + group = h5file.create_group("/", "group") + h5file.create_table(group, "table1", Table1, "Table 1") + h5file.create_table(group, "table2", Table2, "Table 2") + h5file.create_table(group, "table3", Table3, "Table 3") + with HDFStore(path) as store: + assert len(store.keys()) == 3 + expected = {"/group/table1", "/group/table2", "/group/table3"} + assert set(store.keys()) == expected + assert set(store) == expected + def test_keys_ignore_hdf_softlink(self, setup_path): # GH 20523