diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index 09bd09b06d9b9..fb63dc16249b2 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -1098,6 +1098,7 @@ I/O - Bug in :func:`read_pickle` when unpickling objects with :class:`TimedeltaIndex` or :class:`Float64Index` created with pandas prior to version 0.20 (:issue:`19939`) - Bug in :meth:`pandas.io.json.json_normalize` where subrecords are not properly normalized if any subrecords values are NoneType (:issue:`20030`) - Bug in ``usecols`` parameter in :func:`pandas.io.read_csv` and :func:`pandas.io.read_table` where error is not raised correctly when passing a string. (:issue:`20529`) +- Bug in :func:`HDFStore.keys` when reading a file with a softlink causes exception (:issue:`20523`) Plotting ^^^^^^^^ diff --git a/pandas/io/pytables.py b/pandas/io/pytables.py index 2437b7d396e84..f9a496edb45a3 100644 --- a/pandas/io/pytables.py +++ b/pandas/io/pytables.py @@ -1073,10 +1073,11 @@ def groups(self): self._check_if_open() return [ g for g in self._handle.walk_nodes() - if (getattr(g._v_attrs, 'pandas_type', None) or - getattr(g, 'table', None) or + if (not isinstance(g, _table_mod.link.Link) and + (getattr(g._v_attrs, 'pandas_type', None) or + getattr(g, 'table', None) or (isinstance(g, _table_mod.table.Table) and - g._v_name != u('table'))) + g._v_name != u('table')))) ] def get_node(self, key): diff --git a/pandas/tests/io/test_pytables.py b/pandas/tests/io/test_pytables.py index e690b1e302d8b..b34723d6cf72c 100644 --- a/pandas/tests/io/test_pytables.py +++ b/pandas/tests/io/test_pytables.py @@ -373,6 +373,23 @@ def test_keys(self): assert set(store.keys()) == expected assert set(store) == expected + def test_keys_ignore_hdf_softlink(self): + + # GH 20523 + # Puts a softlink into HDF file and rereads + + with ensure_clean_store(self.path) as store: + + df = DataFrame(dict(A=lrange(5), B=lrange(5))) + store.put("df", df) + + assert store.keys() == ["/df"] + + store._handle.create_soft_link(store._handle.root, "symlink", "df") + + # Should ignore the softlink + assert store.keys() == ["/df"] + def test_iter_empty(self): with ensure_clean_store(self.path) as store: