Skip to content

Commit

Permalink
Remove support for py.path objects in IO readers (pandas-dev#57091)
Browse files Browse the repository at this point in the history
* CLN: Remove testing for py.path objects

* Add whatsnew

* Missed annotation

* Add whatsnew
  • Loading branch information
mroeschke authored and pmhatre1 committed May 7, 2024
1 parent fbdcc02 commit 5af42bc
Show file tree
Hide file tree
Showing 18 changed files with 10 additions and 181 deletions.
1 change: 0 additions & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
4 changes: 2 additions & 2 deletions doc/source/user_guide/io.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
-

.. ---------------------------------------------------------------------------
Expand Down
2 changes: 0 additions & 2 deletions pandas/_testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
Series,
)
from pandas._testing._io import (
round_trip_localpath,
round_trip_pathlib,
round_trip_pickle,
write_to_compressed,
Expand Down Expand Up @@ -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",
Expand Down
29 changes: 0 additions & 29 deletions pandas/_testing/_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion pandas/io/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
2 changes: 1 addition & 1 deletion pandas/io/excel/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions pandas/io/stata.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
13 changes: 0 additions & 13 deletions pandas/tests/io/excel/test_readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 0 additions & 12 deletions pandas/tests/io/excel/test_writers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
14 changes: 0 additions & 14 deletions pandas/tests/io/parser/common/test_file_buffer_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 0 additions & 20 deletions pandas/tests/io/pytables/test_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
_maybe_remove,
ensure_clean_store,
)
from pandas.util import _test_decorators as td

from pandas.io.pytables import TableIterator

Expand Down Expand Up @@ -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
Expand Down
19 changes: 0 additions & 19 deletions pandas/tests/io/pytables/test_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
12 changes: 0 additions & 12 deletions pandas/tests/io/sas/test_sas7bdat.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand Down
21 changes: 1 addition & 20 deletions pandas/tests/io/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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__))


Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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:
Expand Down
9 changes: 0 additions & 9 deletions pandas/tests/io/test_feather.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down
10 changes: 0 additions & 10 deletions pandas/tests/io/test_pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
# ---------------------
Expand Down
11 changes: 0 additions & 11 deletions pandas/tests/io/test_stata.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 5af42bc

Please sign in to comment.