diff --git a/doc/source/conf.py b/doc/source/conf.py index be6150d4e54ba..cb7352341eedd 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -460,7 +460,6 @@ "dateutil": ("https://dateutil.readthedocs.io/en/latest/", None), "matplotlib": ("https://matplotlib.org/stable/", None), "numpy": ("https://numpy.org/doc/stable/", None), - "py": ("https://pylib.readthedocs.io/en/latest/", None), "python": ("https://docs.python.org/3/", None), "scipy": ("https://docs.scipy.org/doc/scipy/", None), "pyarrow": ("https://arrow.apache.org/docs/", None), diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index bb5b4e056d527..8adbb53227586 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -61,8 +61,8 @@ Basic +++++ filepath_or_buffer : various - Either a path to a file (a :class:`python:str`, :class:`python:pathlib.Path`, - or :class:`py:py._path.local.LocalPath`), URL (including http, ftp, and S3 + Either a path to a file (a :class:`python:str`, :class:`python:pathlib.Path`) + URL (including http, ftp, and S3 locations), or any object with a ``read()`` method (such as an open file or :class:`~python:io.StringIO`). sep : str, defaults to ``','`` for :func:`read_csv`, ``\t`` for :func:`read_table` diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 950082f9281c5..73201fa93a8aa 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -84,7 +84,7 @@ See :ref:`install.dependencies` and :ref:`install.optional_dependencies` for mor Other API changes ^^^^^^^^^^^^^^^^^ -- +- 3rd party ``py.path`` objects are no longer explicitly supported in IO methods. Use :py:class:`pathlib.Path` objects instead (:issue:`57091`) - .. --------------------------------------------------------------------------- diff --git a/pandas/_testing/__init__.py b/pandas/_testing/__init__.py index 672c16a85086c..3f5fd2e61b0cb 100644 --- a/pandas/_testing/__init__.py +++ b/pandas/_testing/__init__.py @@ -34,7 +34,6 @@ Series, ) from pandas._testing._io import ( - round_trip_localpath, round_trip_pathlib, round_trip_pickle, write_to_compressed, @@ -609,7 +608,6 @@ def shares_memory(left, right) -> bool: "OBJECT_DTYPES", "raise_assert_detail", "raises_chained_assignment_error", - "round_trip_localpath", "round_trip_pathlib", "round_trip_pickle", "setitem", diff --git a/pandas/_testing/_io.py b/pandas/_testing/_io.py index 95977edb600ad..2955108d3db1a 100644 --- a/pandas/_testing/_io.py +++ b/pandas/_testing/_io.py @@ -89,35 +89,6 @@ def round_trip_pathlib(writer, reader, path: str | None = None): return obj -def round_trip_localpath(writer, reader, path: str | None = None): - """ - Write an object to file specified by a py.path LocalPath and read it back. - - Parameters - ---------- - writer : callable bound to pandas object - IO writing function (e.g. DataFrame.to_csv ) - reader : callable - IO reading function (e.g. pd.read_csv ) - path : str, default None - The path where the object is written and then read. - - Returns - ------- - pandas object - The original object that was serialized and then re-read. - """ - import pytest - - LocalPath = pytest.importorskip("py.path").local - if path is None: - path = "___localpath___" - with ensure_clean(path) as path: - writer(LocalPath(path)) - obj = reader(LocalPath(path)) - return obj - - def write_to_compressed(compression, path, data, dest: str = "test") -> None: """ Write data to a compressed file. diff --git a/pandas/io/common.py b/pandas/io/common.py index 576bf7215f363..16d7cb76f9ce9 100644 --- a/pandas/io/common.py +++ b/pandas/io/common.py @@ -318,7 +318,7 @@ def _get_filepath_or_buffer( Parameters ---------- - filepath_or_buffer : a url, filepath (str, py.path.local or pathlib.Path), + filepath_or_buffer : a url, filepath (str or pathlib.Path), or buffer {compression_options} diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index 2189f54263dec..c7642236d4b2a 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -1441,7 +1441,7 @@ class ExcelFile: Parameters ---------- - path_or_buffer : str, bytes, path object (pathlib.Path or py._path.local.LocalPath), + path_or_buffer : str, bytes, pathlib.Path, A file-like object, xlrd workbook or openpyxl workbook. If a string or path object, expected to be a path to a .xls, .xlsx, .xlsb, .xlsm, .odf, .ods, or .odt file. diff --git a/pandas/io/stata.py b/pandas/io/stata.py index 576e27f202524..2ac49600d4d7e 100644 --- a/pandas/io/stata.py +++ b/pandas/io/stata.py @@ -216,7 +216,7 @@ Parameters ---------- path_or_buf : path (string), buffer or path object - string, path object (pathlib.Path or py._path.local.LocalPath) or object + string, pathlib.Path or object implementing a binary read() functions. {_statafile_processing_params1} {_statafile_processing_params2} @@ -2258,7 +2258,7 @@ class StataWriter(StataParser): Parameters ---------- fname : path (string), buffer or path object - string, path object (pathlib.Path or py._path.local.LocalPath) or + string, pathlib.Path or object implementing a binary write() functions. If using a buffer then the buffer will not be automatically closed after the file is written. @@ -3208,7 +3208,7 @@ class StataWriter117(StataWriter): Parameters ---------- fname : path (string), buffer or path object - string, path object (pathlib.Path or py._path.local.LocalPath) or + string, pathlib.Path or object implementing a binary write() functions. If using a buffer then the buffer will not be automatically closed after the file is written. @@ -3594,7 +3594,7 @@ class StataWriterUTF8(StataWriter117): Parameters ---------- fname : path (string), buffer or path object - string, path object (pathlib.Path or py._path.local.LocalPath) or + string, pathlib.Path or object implementing a binary write() functions. If using a buffer then the buffer will not be automatically closed after the file is written. diff --git a/pandas/tests/io/excel/test_readers.py b/pandas/tests/io/excel/test_readers.py index 04a25317c8017..708f01839a23c 100644 --- a/pandas/tests/io/excel/test_readers.py +++ b/pandas/tests/io/excel/test_readers.py @@ -966,19 +966,6 @@ def test_read_from_pathlib_path(self, read_ext): tm.assert_frame_equal(expected, actual) - @td.skip_if_no("py.path") - def test_read_from_py_localpath(self, read_ext): - # GH12655 - from py.path import local as LocalPath - - str_path = os.path.join("test1" + read_ext) - expected = pd.read_excel(str_path, sheet_name="Sheet1", index_col=0) - - path_obj = LocalPath().join("test1" + read_ext) - actual = pd.read_excel(path_obj, sheet_name="Sheet1", index_col=0) - - tm.assert_frame_equal(expected, actual) - def test_close_from_py_localpath(self, read_ext): # GH31467 str_path = os.path.join("test1" + read_ext) diff --git a/pandas/tests/io/excel/test_writers.py b/pandas/tests/io/excel/test_writers.py index 76a138a295bda..6aea7464ee8dc 100644 --- a/pandas/tests/io/excel/test_writers.py +++ b/pandas/tests/io/excel/test_writers.py @@ -1319,18 +1319,6 @@ def test_path_path_lib(self, engine, ext): result = tm.round_trip_pathlib(writer, reader, path=f"foo{ext}") tm.assert_frame_equal(result, df) - def test_path_local_path(self, engine, ext): - df = DataFrame( - 1.1 * np.arange(120).reshape((30, 4)), - columns=Index(list("ABCD")), - index=Index([f"i-{i}" for i in range(30)]), - ) - writer = partial(df.to_excel, engine=engine) - - reader = partial(pd.read_excel, index_col=0) - result = tm.round_trip_localpath(writer, reader, path=f"foo{ext}") - tm.assert_frame_equal(result, df) - def test_merged_cell_custom_objects(self, path): # see GH-27006 mi = MultiIndex.from_tuples( diff --git a/pandas/tests/io/parser/common/test_file_buffer_url.py b/pandas/tests/io/parser/common/test_file_buffer_url.py index 5e31b4c6b644d..774f6b61df517 100644 --- a/pandas/tests/io/parser/common/test_file_buffer_url.py +++ b/pandas/tests/io/parser/common/test_file_buffer_url.py @@ -79,20 +79,6 @@ def test_path_path_lib(all_parsers): tm.assert_frame_equal(df, result) -@xfail_pyarrow # AssertionError: DataFrame.index are different -def test_path_local_path(all_parsers): - parser = all_parsers - df = DataFrame( - 1.1 * np.arange(120).reshape((30, 4)), - columns=Index(list("ABCD"), dtype=object), - index=Index([f"i-{i}" for i in range(30)], dtype=object), - ) - result = tm.round_trip_localpath( - df.to_csv, lambda p: parser.read_csv(p, index_col=0) - ) - tm.assert_frame_equal(df, result) - - def test_nonexistent_path(all_parsers): # gh-2428: pls no segfault # gh-14086: raise more helpful FileNotFoundError diff --git a/pandas/tests/io/pytables/test_read.py b/pandas/tests/io/pytables/test_read.py index e4a3ea1fc9db8..c8563ee4af4a8 100644 --- a/pandas/tests/io/pytables/test_read.py +++ b/pandas/tests/io/pytables/test_read.py @@ -22,7 +22,6 @@ _maybe_remove, ensure_clean_store, ) -from pandas.util import _test_decorators as td from pandas.io.pytables import TableIterator @@ -337,25 +336,6 @@ def test_read_from_pathlib_path(tmp_path, setup_path): tm.assert_frame_equal(expected, actual) -@td.skip_if_no("py.path") -def test_read_from_py_localpath(tmp_path, setup_path): - # GH11773 - from py.path import local as LocalPath - - expected = DataFrame( - np.random.default_rng(2).random((4, 5)), - index=list("abcd"), - columns=list("ABCDE"), - ) - filename = tmp_path / setup_path - path_obj = LocalPath(filename) - - expected.to_hdf(path_obj, key="df", mode="a") - actual = read_hdf(path_obj, key="df") - - tm.assert_frame_equal(expected, actual) - - @pytest.mark.parametrize("format", ["fixed", "table"]) def test_read_hdf_series_mode_r(tmp_path, format, setup_path): # GH 16583 diff --git a/pandas/tests/io/pytables/test_store.py b/pandas/tests/io/pytables/test_store.py index 82d3052e7f5d6..de56ab614dcd4 100644 --- a/pandas/tests/io/pytables/test_store.py +++ b/pandas/tests/io/pytables/test_store.py @@ -958,25 +958,6 @@ def test_pickle_path_localpath(): tm.assert_frame_equal(df, result) -def test_path_localpath_hdfstore(): - df = DataFrame( - 1.1 * np.arange(120).reshape((30, 4)), - columns=Index(list("ABCD"), dtype=object), - index=Index([f"i-{i}" for i in range(30)], dtype=object), - ) - - def writer(path): - with HDFStore(path) as store: - df.to_hdf(store, key="df") - - def reader(path): - with HDFStore(path) as store: - return read_hdf(store, "df") - - result = tm.round_trip_localpath(writer, reader) - tm.assert_frame_equal(df, result) - - @pytest.mark.parametrize("propindexes", [True, False]) def test_copy(propindexes): df = DataFrame( diff --git a/pandas/tests/io/sas/test_sas7bdat.py b/pandas/tests/io/sas/test_sas7bdat.py index b71896c77ffb5..889ef61740a2c 100644 --- a/pandas/tests/io/sas/test_sas7bdat.py +++ b/pandas/tests/io/sas/test_sas7bdat.py @@ -9,7 +9,6 @@ from pandas.compat import IS64 from pandas.errors import EmptyDataError -import pandas.util._test_decorators as td import pandas as pd import pandas._testing as tm @@ -82,17 +81,6 @@ def test_path_pathlib(self, dirpath, data_test_ix): df = pd.read_sas(fname, encoding="utf-8") tm.assert_frame_equal(df, expected) - @td.skip_if_no("py.path") - @pytest.mark.slow - def test_path_localpath(self, dirpath, data_test_ix): - from py.path import local as LocalPath - - expected, test_ix = data_test_ix - for k in test_ix: - fname = LocalPath(os.path.join(dirpath, f"test{k}.sas7bdat")) - df = pd.read_sas(fname, encoding="utf-8") - tm.assert_frame_equal(df, expected) - @pytest.mark.slow @pytest.mark.parametrize("chunksize", (3, 5, 10, 11)) @pytest.mark.parametrize("k", range(1, 17)) diff --git a/pandas/tests/io/test_common.py b/pandas/tests/io/test_common.py index 074033868635a..b43f430b8895b 100644 --- a/pandas/tests/io/test_common.py +++ b/pandas/tests/io/test_common.py @@ -19,7 +19,6 @@ import pytest from pandas.compat import is_platform_windows -import pandas.util._test_decorators as td import pandas as pd import pandas._testing as tm @@ -41,16 +40,6 @@ def __fspath__(self): return self.path -# Functions that consume a string path and return a string or path-like object -path_types = [str, CustomFSPath, Path] - -try: - from py.path import local as LocalPath - - path_types.append(LocalPath) -except ImportError: - pass - HERE = os.path.abspath(os.path.dirname(__file__)) @@ -86,13 +75,6 @@ def test_stringify_path_pathlib(self): redundant_path = icom.stringify_path(Path("foo//bar")) assert redundant_path == os.path.join("foo", "bar") - @td.skip_if_no("py.path") - def test_stringify_path_localpath(self): - path = os.path.join("foo", "bar") - abs_path = os.path.abspath(path) - lpath = LocalPath(path) - assert icom.stringify_path(lpath) == abs_path - def test_stringify_path_fspath(self): p = CustomFSPath("foo/bar.csv") result = icom.stringify_path(p) @@ -105,7 +87,7 @@ def test_stringify_file_and_path_like(self): with fsspec.open(f"file://{path}", mode="wb") as fsspec_obj: assert fsspec_obj == icom.stringify_path(fsspec_obj) - @pytest.mark.parametrize("path_type", path_types) + @pytest.mark.parametrize("path_type", [str, CustomFSPath, Path]) def test_infer_compression_from_path(self, compression_format, path_type): extension, expected = compression_format path = path_type("foo/bar.csv" + extension) @@ -114,7 +96,6 @@ def test_infer_compression_from_path(self, compression_format, path_type): @pytest.mark.parametrize("path_type", [str, CustomFSPath, Path]) def test_get_handle_with_path(self, path_type): - # ignore LocalPath: it creates strange paths: /absolute/~/sometest with tempfile.TemporaryDirectory(dir=Path.home()) as tmp: filename = path_type("~/" + Path(tmp).name + "/sometest") with icom.get_handle(filename, "w") as handles: diff --git a/pandas/tests/io/test_feather.py b/pandas/tests/io/test_feather.py index 22a7d3b83a459..f012fcadc5592 100644 --- a/pandas/tests/io/test_feather.py +++ b/pandas/tests/io/test_feather.py @@ -140,15 +140,6 @@ def test_path_pathlib(self): result = tm.round_trip_pathlib(df.to_feather, read_feather) tm.assert_frame_equal(df, result) - def test_path_localpath(self): - df = pd.DataFrame( - 1.1 * np.arange(120).reshape((30, 4)), - columns=pd.Index(list("ABCD"), dtype=object), - index=pd.Index([f"i-{i}" for i in range(30)], dtype=object), - ).reset_index() - result = tm.round_trip_localpath(df.to_feather, read_feather) - tm.assert_frame_equal(df, result) - def test_passthrough_keywords(self): df = pd.DataFrame( 1.1 * np.arange(120).reshape((30, 4)), diff --git a/pandas/tests/io/test_pickle.py b/pandas/tests/io/test_pickle.py index f6c7f66abe5d3..57c7829924531 100644 --- a/pandas/tests/io/test_pickle.py +++ b/pandas/tests/io/test_pickle.py @@ -229,16 +229,6 @@ def test_pickle_path_pathlib(): tm.assert_frame_equal(df, result) -def test_pickle_path_localpath(): - df = DataFrame( - 1.1 * np.arange(120).reshape((30, 4)), - columns=Index(list("ABCD"), dtype=object), - index=Index([f"i-{i}" for i in range(30)], dtype=object), - ) - result = tm.round_trip_localpath(df.to_pickle, pd.read_pickle) - tm.assert_frame_equal(df, result) - - # --------------------- # test pickle compression # --------------------- diff --git a/pandas/tests/io/test_stata.py b/pandas/tests/io/test_stata.py index 5c6377349304c..4aa0b2f5ae8c9 100644 --- a/pandas/tests/io/test_stata.py +++ b/pandas/tests/io/test_stata.py @@ -1546,17 +1546,6 @@ def test_path_pathlib(self): result = tm.round_trip_pathlib(df.to_stata, reader) tm.assert_frame_equal(df, result) - def test_pickle_path_localpath(self): - df = DataFrame( - 1.1 * np.arange(120).reshape((30, 4)), - columns=pd.Index(list("ABCD"), dtype=object), - index=pd.Index([f"i-{i}" for i in range(30)], dtype=object), - ) - df.index.name = "index" - reader = lambda x: read_stata(x).set_index("index") - result = tm.round_trip_localpath(df.to_stata, reader) - tm.assert_frame_equal(df, result) - @pytest.mark.parametrize("write_index", [True, False]) def test_value_labels_iterator(self, write_index): # GH 16923