Skip to content

Commit ac37895

Browse files
committed
ENH: add __fspath__ to pandas own file-like objects
- HDFStore - ExcelFile (cherry picked from commit f9baec385e2513234a69a05031d2753899290d38)
1 parent 961a314 commit ac37895

File tree

6 files changed

+46
-8
lines changed

6 files changed

+46
-8
lines changed

doc/source/whatsnew/v0.21.0.txt

+4-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ Check the :ref:`API Changes <whatsnew_0210.api_breaking>` and :ref:`deprecations
2020
New features
2121
~~~~~~~~~~~~
2222

23-
- Support for `PEP 519 -- Adding a file system path protocol <https://www.python.org/dev/peps/pep-0519/>`_ on most readers and writers (:issue:`13823`)
24-
23+
- Support for `PEP 519 -- Adding a file system path protocol
24+
<https://www.python.org/dev/peps/pep-0519/>`_ on most readers and writers (:issue:`13823`)
25+
- Added `__fspath__` method to :class`:pandas.HDFStore`, :class:`pandas.ExcelFile`,
26+
and :class:`pandas.ExcelWriter` to work properly with the file system path protocol (:issue:`13823`)
2527

2628

2729
.. _whatsnew_0210.enhancements.other:

pandas/io/excel.py

+6
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ def __init__(self, io, **kwds):
263263
raise ValueError('Must explicitly set engine if not passing in'
264264
' buffer or path for io.')
265265

266+
def __fspath__(self):
267+
return self._io
268+
266269
def parse(self, sheetname=0, header=0, skiprows=None, skip_footer=0,
267270
names=None, index_col=None, parse_cols=None, parse_dates=False,
268271
date_parser=None, na_values=None, thousands=None,
@@ -758,6 +761,9 @@ def __init__(self, path, engine=None,
758761
else:
759762
self.datetime_format = datetime_format
760763

764+
def __fspath__(self):
765+
return _stringify_path(self.path)
766+
761767
def _get_sheet_name(self, sheet_name):
762768
if sheet_name is None:
763769
sheet_name = self.cur_sheet

pandas/io/formats/excel.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import numpy as np
99

10-
from pandas.compat import reduce, string_types
10+
from pandas.compat import reduce
1111
from pandas.io.formats.css import CSSResolver, CSSWarning
1212
from pandas.io.formats.printing import pprint_thing
1313
from pandas.core.dtypes.common import is_float
@@ -619,10 +619,10 @@ def write(self, writer, sheet_name='Sheet1', startrow=0,
619619
from pandas.io.excel import ExcelWriter
620620
from pandas.io.common import _stringify_path
621621

622-
writer = _stringify_path(writer)
623-
need_save = False
624-
if isinstance(writer, string_types):
625-
writer = ExcelWriter(writer, engine=engine)
622+
if isinstance(writer, ExcelWriter):
623+
need_save = False
624+
else:
625+
writer = ExcelWriter(_stringify_path(writer), engine=engine)
626626
need_save = True
627627

628628
formatted_cells = self.get_formatted_cells()

pandas/io/pytables.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ def __init__(self, path, mode=None, complevel=None, complib=None,
437437
"complib only supports {libs} compression.".format(
438438
libs=tables.filters.all_complibs))
439439

440-
self._path = path
440+
self._path = _stringify_path(path)
441441
if mode is None:
442442
mode = 'a'
443443
self._mode = mode
@@ -448,6 +448,9 @@ def __init__(self, path, mode=None, complevel=None, complib=None,
448448
self._filters = None
449449
self.open(mode=mode, **kwargs)
450450

451+
def __fspath__(self):
452+
return self._path
453+
451454
@property
452455
def root(self):
453456
""" return the root node """

pandas/tests/io/test_excel.py

+21
Original file line numberDiff line numberDiff line change
@@ -2499,3 +2499,24 @@ def custom_converter(css):
24992499
n_cells += 1
25002500

25012501
assert n_cells == (10 + 1) * (3 + 1)
2502+
2503+
2504+
class TestFSPath(object):
2505+
2506+
@pytest.mark.skipif(sys.version_info < (3, 6), reason='requires fspath')
2507+
def test_excelfile_fspath(self):
2508+
_skip_if_no_openpyxl()
2509+
with tm.ensure_clean('foo.xlsx') as path:
2510+
df = DataFrame({"A": [1, 2]})
2511+
df.to_excel(path)
2512+
xl = ExcelFile(path)
2513+
result = os.fspath(xl)
2514+
assert result == path
2515+
2516+
@pytest.mark.skipif(sys.version_info < (3, 6), reason='requires fspath')
2517+
# @pytest.mark.xfail
2518+
def test_excelwriter_fspath(self):
2519+
_skip_if_no_openpyxl()
2520+
with tm.ensure_clean('foo.xlsx') as path:
2521+
writer = ExcelWriter(path)
2522+
assert os.fspath(writer) == str(path)

pandas/tests/io/test_pytables.py

+6
Original file line numberDiff line numberDiff line change
@@ -5155,6 +5155,12 @@ def test_query_compare_column_type(self):
51555155
expected = df.loc[[], :]
51565156
tm.assert_frame_equal(expected, result)
51575157

5158+
@pytest.mark.skipif(sys.version_info < (3, 6), reason="Need python 3.6")
5159+
def test_fspath(self):
5160+
with tm.ensure_clean('foo.h5') as path:
5161+
with pd.HDFStore(path) as store:
5162+
assert os.fspath(store) == str(path)
5163+
51585164

51595165
class TestHDFComplexValues(Base):
51605166
# GH10447

0 commit comments

Comments
 (0)