Skip to content

Commit 9008ee5

Browse files
authored
Remove support for py.path objects in IO readers (#57091)
* CLN: Remove testing for py.path objects * Add whatsnew * Missed annotation * Add whatsnew
1 parent 8288b9b commit 9008ee5

File tree

18 files changed

+10
-181
lines changed

18 files changed

+10
-181
lines changed

doc/source/conf.py

-1
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,6 @@
460460
"dateutil": ("https://dateutil.readthedocs.io/en/latest/", None),
461461
"matplotlib": ("https://matplotlib.org/stable/", None),
462462
"numpy": ("https://numpy.org/doc/stable/", None),
463-
"py": ("https://pylib.readthedocs.io/en/latest/", None),
464463
"python": ("https://docs.python.org/3/", None),
465464
"scipy": ("https://docs.scipy.org/doc/scipy/", None),
466465
"pyarrow": ("https://arrow.apache.org/docs/", None),

doc/source/user_guide/io.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ Basic
6161
+++++
6262

6363
filepath_or_buffer : various
64-
Either a path to a file (a :class:`python:str`, :class:`python:pathlib.Path`,
65-
or :class:`py:py._path.local.LocalPath`), URL (including http, ftp, and S3
64+
Either a path to a file (a :class:`python:str`, :class:`python:pathlib.Path`)
65+
URL (including http, ftp, and S3
6666
locations), or any object with a ``read()`` method (such as an open file or
6767
:class:`~python:io.StringIO`).
6868
sep : str, defaults to ``','`` for :func:`read_csv`, ``\t`` for :func:`read_table`

doc/source/whatsnew/v3.0.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ See :ref:`install.dependencies` and :ref:`install.optional_dependencies` for mor
8484

8585
Other API changes
8686
^^^^^^^^^^^^^^^^^
87-
-
87+
- 3rd party ``py.path`` objects are no longer explicitly supported in IO methods. Use :py:class:`pathlib.Path` objects instead (:issue:`57091`)
8888
-
8989

9090
.. ---------------------------------------------------------------------------

pandas/_testing/__init__.py

-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
Series,
3535
)
3636
from pandas._testing._io import (
37-
round_trip_localpath,
3837
round_trip_pathlib,
3938
round_trip_pickle,
4039
write_to_compressed,
@@ -609,7 +608,6 @@ def shares_memory(left, right) -> bool:
609608
"OBJECT_DTYPES",
610609
"raise_assert_detail",
611610
"raises_chained_assignment_error",
612-
"round_trip_localpath",
613611
"round_trip_pathlib",
614612
"round_trip_pickle",
615613
"setitem",

pandas/_testing/_io.py

-29
Original file line numberDiff line numberDiff line change
@@ -89,35 +89,6 @@ def round_trip_pathlib(writer, reader, path: str | None = None):
8989
return obj
9090

9191

92-
def round_trip_localpath(writer, reader, path: str | None = None):
93-
"""
94-
Write an object to file specified by a py.path LocalPath and read it back.
95-
96-
Parameters
97-
----------
98-
writer : callable bound to pandas object
99-
IO writing function (e.g. DataFrame.to_csv )
100-
reader : callable
101-
IO reading function (e.g. pd.read_csv )
102-
path : str, default None
103-
The path where the object is written and then read.
104-
105-
Returns
106-
-------
107-
pandas object
108-
The original object that was serialized and then re-read.
109-
"""
110-
import pytest
111-
112-
LocalPath = pytest.importorskip("py.path").local
113-
if path is None:
114-
path = "___localpath___"
115-
with ensure_clean(path) as path:
116-
writer(LocalPath(path))
117-
obj = reader(LocalPath(path))
118-
return obj
119-
120-
12192
def write_to_compressed(compression, path, data, dest: str = "test") -> None:
12293
"""
12394
Write data to a compressed file.

pandas/io/common.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ def _get_filepath_or_buffer(
318318
319319
Parameters
320320
----------
321-
filepath_or_buffer : a url, filepath (str, py.path.local or pathlib.Path),
321+
filepath_or_buffer : a url, filepath (str or pathlib.Path),
322322
or buffer
323323
{compression_options}
324324

pandas/io/excel/_base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1441,7 +1441,7 @@ class ExcelFile:
14411441
14421442
Parameters
14431443
----------
1444-
path_or_buffer : str, bytes, path object (pathlib.Path or py._path.local.LocalPath),
1444+
path_or_buffer : str, bytes, pathlib.Path,
14451445
A file-like object, xlrd workbook or openpyxl workbook.
14461446
If a string or path object, expected to be a path to a
14471447
.xls, .xlsx, .xlsb, .xlsm, .odf, .ods, or .odt file.

pandas/io/stata.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@
216216
Parameters
217217
----------
218218
path_or_buf : path (string), buffer or path object
219-
string, path object (pathlib.Path or py._path.local.LocalPath) or object
219+
string, pathlib.Path or object
220220
implementing a binary read() functions.
221221
{_statafile_processing_params1}
222222
{_statafile_processing_params2}
@@ -2258,7 +2258,7 @@ class StataWriter(StataParser):
22582258
Parameters
22592259
----------
22602260
fname : path (string), buffer or path object
2261-
string, path object (pathlib.Path or py._path.local.LocalPath) or
2261+
string, pathlib.Path or
22622262
object implementing a binary write() functions. If using a buffer
22632263
then the buffer will not be automatically closed after the file
22642264
is written.
@@ -3208,7 +3208,7 @@ class StataWriter117(StataWriter):
32083208
Parameters
32093209
----------
32103210
fname : path (string), buffer or path object
3211-
string, path object (pathlib.Path or py._path.local.LocalPath) or
3211+
string, pathlib.Path or
32123212
object implementing a binary write() functions. If using a buffer
32133213
then the buffer will not be automatically closed after the file
32143214
is written.
@@ -3594,7 +3594,7 @@ class StataWriterUTF8(StataWriter117):
35943594
Parameters
35953595
----------
35963596
fname : path (string), buffer or path object
3597-
string, path object (pathlib.Path or py._path.local.LocalPath) or
3597+
string, pathlib.Path or
35983598
object implementing a binary write() functions. If using a buffer
35993599
then the buffer will not be automatically closed after the file
36003600
is written.

pandas/tests/io/excel/test_readers.py

-13
Original file line numberDiff line numberDiff line change
@@ -966,19 +966,6 @@ def test_read_from_pathlib_path(self, read_ext):
966966

967967
tm.assert_frame_equal(expected, actual)
968968

969-
@td.skip_if_no("py.path")
970-
def test_read_from_py_localpath(self, read_ext):
971-
# GH12655
972-
from py.path import local as LocalPath
973-
974-
str_path = os.path.join("test1" + read_ext)
975-
expected = pd.read_excel(str_path, sheet_name="Sheet1", index_col=0)
976-
977-
path_obj = LocalPath().join("test1" + read_ext)
978-
actual = pd.read_excel(path_obj, sheet_name="Sheet1", index_col=0)
979-
980-
tm.assert_frame_equal(expected, actual)
981-
982969
def test_close_from_py_localpath(self, read_ext):
983970
# GH31467
984971
str_path = os.path.join("test1" + read_ext)

pandas/tests/io/excel/test_writers.py

-12
Original file line numberDiff line numberDiff line change
@@ -1319,18 +1319,6 @@ def test_path_path_lib(self, engine, ext):
13191319
result = tm.round_trip_pathlib(writer, reader, path=f"foo{ext}")
13201320
tm.assert_frame_equal(result, df)
13211321

1322-
def test_path_local_path(self, engine, ext):
1323-
df = DataFrame(
1324-
1.1 * np.arange(120).reshape((30, 4)),
1325-
columns=Index(list("ABCD")),
1326-
index=Index([f"i-{i}" for i in range(30)]),
1327-
)
1328-
writer = partial(df.to_excel, engine=engine)
1329-
1330-
reader = partial(pd.read_excel, index_col=0)
1331-
result = tm.round_trip_localpath(writer, reader, path=f"foo{ext}")
1332-
tm.assert_frame_equal(result, df)
1333-
13341322
def test_merged_cell_custom_objects(self, path):
13351323
# see GH-27006
13361324
mi = MultiIndex.from_tuples(

pandas/tests/io/parser/common/test_file_buffer_url.py

-14
Original file line numberDiff line numberDiff line change
@@ -79,20 +79,6 @@ def test_path_path_lib(all_parsers):
7979
tm.assert_frame_equal(df, result)
8080

8181

82-
@xfail_pyarrow # AssertionError: DataFrame.index are different
83-
def test_path_local_path(all_parsers):
84-
parser = all_parsers
85-
df = DataFrame(
86-
1.1 * np.arange(120).reshape((30, 4)),
87-
columns=Index(list("ABCD"), dtype=object),
88-
index=Index([f"i-{i}" for i in range(30)], dtype=object),
89-
)
90-
result = tm.round_trip_localpath(
91-
df.to_csv, lambda p: parser.read_csv(p, index_col=0)
92-
)
93-
tm.assert_frame_equal(df, result)
94-
95-
9682
def test_nonexistent_path(all_parsers):
9783
# gh-2428: pls no segfault
9884
# gh-14086: raise more helpful FileNotFoundError

pandas/tests/io/pytables/test_read.py

-20
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
_maybe_remove,
2323
ensure_clean_store,
2424
)
25-
from pandas.util import _test_decorators as td
2625

2726
from pandas.io.pytables import TableIterator
2827

@@ -337,25 +336,6 @@ def test_read_from_pathlib_path(tmp_path, setup_path):
337336
tm.assert_frame_equal(expected, actual)
338337

339338

340-
@td.skip_if_no("py.path")
341-
def test_read_from_py_localpath(tmp_path, setup_path):
342-
# GH11773
343-
from py.path import local as LocalPath
344-
345-
expected = DataFrame(
346-
np.random.default_rng(2).random((4, 5)),
347-
index=list("abcd"),
348-
columns=list("ABCDE"),
349-
)
350-
filename = tmp_path / setup_path
351-
path_obj = LocalPath(filename)
352-
353-
expected.to_hdf(path_obj, key="df", mode="a")
354-
actual = read_hdf(path_obj, key="df")
355-
356-
tm.assert_frame_equal(expected, actual)
357-
358-
359339
@pytest.mark.parametrize("format", ["fixed", "table"])
360340
def test_read_hdf_series_mode_r(tmp_path, format, setup_path):
361341
# GH 16583

pandas/tests/io/pytables/test_store.py

-19
Original file line numberDiff line numberDiff line change
@@ -958,25 +958,6 @@ def test_pickle_path_localpath():
958958
tm.assert_frame_equal(df, result)
959959

960960

961-
def test_path_localpath_hdfstore():
962-
df = DataFrame(
963-
1.1 * np.arange(120).reshape((30, 4)),
964-
columns=Index(list("ABCD"), dtype=object),
965-
index=Index([f"i-{i}" for i in range(30)], dtype=object),
966-
)
967-
968-
def writer(path):
969-
with HDFStore(path) as store:
970-
df.to_hdf(store, key="df")
971-
972-
def reader(path):
973-
with HDFStore(path) as store:
974-
return read_hdf(store, "df")
975-
976-
result = tm.round_trip_localpath(writer, reader)
977-
tm.assert_frame_equal(df, result)
978-
979-
980961
@pytest.mark.parametrize("propindexes", [True, False])
981962
def test_copy(propindexes):
982963
df = DataFrame(

pandas/tests/io/sas/test_sas7bdat.py

-12
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
from pandas.compat import IS64
1111
from pandas.errors import EmptyDataError
12-
import pandas.util._test_decorators as td
1312

1413
import pandas as pd
1514
import pandas._testing as tm
@@ -82,17 +81,6 @@ def test_path_pathlib(self, dirpath, data_test_ix):
8281
df = pd.read_sas(fname, encoding="utf-8")
8382
tm.assert_frame_equal(df, expected)
8483

85-
@td.skip_if_no("py.path")
86-
@pytest.mark.slow
87-
def test_path_localpath(self, dirpath, data_test_ix):
88-
from py.path import local as LocalPath
89-
90-
expected, test_ix = data_test_ix
91-
for k in test_ix:
92-
fname = LocalPath(os.path.join(dirpath, f"test{k}.sas7bdat"))
93-
df = pd.read_sas(fname, encoding="utf-8")
94-
tm.assert_frame_equal(df, expected)
95-
9684
@pytest.mark.slow
9785
@pytest.mark.parametrize("chunksize", (3, 5, 10, 11))
9886
@pytest.mark.parametrize("k", range(1, 17))

pandas/tests/io/test_common.py

+1-20
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import pytest
2020

2121
from pandas.compat import is_platform_windows
22-
import pandas.util._test_decorators as td
2322

2423
import pandas as pd
2524
import pandas._testing as tm
@@ -41,16 +40,6 @@ def __fspath__(self):
4140
return self.path
4241

4342

44-
# Functions that consume a string path and return a string or path-like object
45-
path_types = [str, CustomFSPath, Path]
46-
47-
try:
48-
from py.path import local as LocalPath
49-
50-
path_types.append(LocalPath)
51-
except ImportError:
52-
pass
53-
5443
HERE = os.path.abspath(os.path.dirname(__file__))
5544

5645

@@ -86,13 +75,6 @@ def test_stringify_path_pathlib(self):
8675
redundant_path = icom.stringify_path(Path("foo//bar"))
8776
assert redundant_path == os.path.join("foo", "bar")
8877

89-
@td.skip_if_no("py.path")
90-
def test_stringify_path_localpath(self):
91-
path = os.path.join("foo", "bar")
92-
abs_path = os.path.abspath(path)
93-
lpath = LocalPath(path)
94-
assert icom.stringify_path(lpath) == abs_path
95-
9678
def test_stringify_path_fspath(self):
9779
p = CustomFSPath("foo/bar.csv")
9880
result = icom.stringify_path(p)
@@ -105,7 +87,7 @@ def test_stringify_file_and_path_like(self):
10587
with fsspec.open(f"file://{path}", mode="wb") as fsspec_obj:
10688
assert fsspec_obj == icom.stringify_path(fsspec_obj)
10789

108-
@pytest.mark.parametrize("path_type", path_types)
90+
@pytest.mark.parametrize("path_type", [str, CustomFSPath, Path])
10991
def test_infer_compression_from_path(self, compression_format, path_type):
11092
extension, expected = compression_format
11193
path = path_type("foo/bar.csv" + extension)
@@ -114,7 +96,6 @@ def test_infer_compression_from_path(self, compression_format, path_type):
11496

11597
@pytest.mark.parametrize("path_type", [str, CustomFSPath, Path])
11698
def test_get_handle_with_path(self, path_type):
117-
# ignore LocalPath: it creates strange paths: /absolute/~/sometest
11899
with tempfile.TemporaryDirectory(dir=Path.home()) as tmp:
119100
filename = path_type("~/" + Path(tmp).name + "/sometest")
120101
with icom.get_handle(filename, "w") as handles:

pandas/tests/io/test_feather.py

-9
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,6 @@ def test_path_pathlib(self):
140140
result = tm.round_trip_pathlib(df.to_feather, read_feather)
141141
tm.assert_frame_equal(df, result)
142142

143-
def test_path_localpath(self):
144-
df = pd.DataFrame(
145-
1.1 * np.arange(120).reshape((30, 4)),
146-
columns=pd.Index(list("ABCD"), dtype=object),
147-
index=pd.Index([f"i-{i}" for i in range(30)], dtype=object),
148-
).reset_index()
149-
result = tm.round_trip_localpath(df.to_feather, read_feather)
150-
tm.assert_frame_equal(df, result)
151-
152143
def test_passthrough_keywords(self):
153144
df = pd.DataFrame(
154145
1.1 * np.arange(120).reshape((30, 4)),

pandas/tests/io/test_pickle.py

-10
Original file line numberDiff line numberDiff line change
@@ -229,16 +229,6 @@ def test_pickle_path_pathlib():
229229
tm.assert_frame_equal(df, result)
230230

231231

232-
def test_pickle_path_localpath():
233-
df = DataFrame(
234-
1.1 * np.arange(120).reshape((30, 4)),
235-
columns=Index(list("ABCD"), dtype=object),
236-
index=Index([f"i-{i}" for i in range(30)], dtype=object),
237-
)
238-
result = tm.round_trip_localpath(df.to_pickle, pd.read_pickle)
239-
tm.assert_frame_equal(df, result)
240-
241-
242232
# ---------------------
243233
# test pickle compression
244234
# ---------------------

pandas/tests/io/test_stata.py

-11
Original file line numberDiff line numberDiff line change
@@ -1546,17 +1546,6 @@ def test_path_pathlib(self):
15461546
result = tm.round_trip_pathlib(df.to_stata, reader)
15471547
tm.assert_frame_equal(df, result)
15481548

1549-
def test_pickle_path_localpath(self):
1550-
df = DataFrame(
1551-
1.1 * np.arange(120).reshape((30, 4)),
1552-
columns=pd.Index(list("ABCD"), dtype=object),
1553-
index=pd.Index([f"i-{i}" for i in range(30)], dtype=object),
1554-
)
1555-
df.index.name = "index"
1556-
reader = lambda x: read_stata(x).set_index("index")
1557-
result = tm.round_trip_localpath(df.to_stata, reader)
1558-
tm.assert_frame_equal(df, result)
1559-
15601549
@pytest.mark.parametrize("write_index", [True, False])
15611550
def test_value_labels_iterator(self, write_index):
15621551
# GH 16923

0 commit comments

Comments
 (0)