Skip to content

Commit 4acf0b8

Browse files
authored
Merge pull request #136 from rstudio/fix-compat-r-arrow
fix: support reading type arrow
2 parents a3a3a10 + 6a7f77a commit 4acf0b8

File tree

5 files changed

+69
-7
lines changed

5 files changed

+69
-7
lines changed

pins/boards.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from .meta import Meta, MetaRaw, MetaFactory
1616
from .errors import PinsError
1717
from .drivers import load_data, save_data, default_title
18-
from .utils import inform, ExtendMethodDoc
18+
from .utils import inform, warn_deprecated, ExtendMethodDoc
1919
from .config import get_allow_rsc_short_name
2020

2121

@@ -255,6 +255,14 @@ def pin_write(
255255
part of the pin version name.
256256
"""
257257

258+
if type == "feather":
259+
warn_deprecated(
260+
'Writing pin type "feather" is unsupported. Switching type to "arrow".'
261+
" This produces the exact same behavior, and also works with R pins."
262+
' Please switch to pin_write using type="arrow".'
263+
)
264+
type = "arrow"
265+
258266
pin_name = self.path_to_pin(name)
259267

260268
# TODO(docs): describe options for type argument

pins/drivers.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ def load_data(
7676

7777
return pd.read_csv(fs.open(path_to_file))
7878

79+
elif meta.type == "arrow":
80+
import pandas as pd
81+
82+
return pd.read_feather(fs.open(path_to_file))
83+
7984
elif meta.type == "feather":
8085
import pandas as pd
8186

@@ -123,11 +128,20 @@ def save_data(
123128

124129
obj.to_csv(final_name, index=False)
125130

126-
elif type == "feather":
131+
elif type == "arrow":
132+
# NOTE: R pins accepts the type arrow, and saves it as feather.
133+
# we allow reading this type, but raise an error for writing.
127134
_assert_is_pandas_df(obj)
128135

129136
obj.to_feather(final_name)
130137

138+
elif type == "feather":
139+
_assert_is_pandas_df(obj)
140+
141+
raise NotImplementedError(
142+
'Saving data as type "feather" no longer supported. Use type "arrow" instead.'
143+
)
144+
131145
elif type == "parquet":
132146
_assert_is_pandas_df(obj)
133147

pins/tests/test_boards.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ class C:
9696
assert "MY_TYPE" in exc_info.value.args[0]
9797

9898

99+
def test_board_pin_write_feather_deprecated(board):
100+
df = pd.DataFrame({"x": [1, 2, 3]})
101+
102+
with pytest.warns(DeprecationWarning):
103+
board.pin_write(df, "cool_pin", type="feather")
104+
105+
99106
def test_board_pin_write_rsc_index_html(board, tmp_dir2, snapshot):
100107
if board.fs.protocol != "rsc":
101108
pytest.skip()

pins/tests/test_drivers.py

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ def test_default_title(obj, dst_title):
4949
"type_",
5050
[
5151
"csv",
52-
"feather",
52+
"arrow",
5353
"parquet",
54+
"joblib",
5455
],
5556
)
5657
def test_driver_roundtrip(tmp_dir2, type_):
@@ -71,14 +72,41 @@ def test_driver_roundtrip(tmp_dir2, type_):
7172
assert Path(res_fname).name == full_file
7273

7374
meta = MetaRaw(full_file, type_, "my_pin")
74-
obj = load_data(meta, fsspec.filesystem("file"), tmp_dir2)
75+
obj = load_data(meta, fsspec.filesystem("file"), tmp_dir2, allow_pickle_read=True)
7576

7677
assert df.equals(obj)
7778

7879

79-
@pytest.mark.skip("TODO: complete once driver story is fleshed out")
80-
def test_driver_roundtrip_joblib(tmp_dir2):
81-
pass
80+
def test_driver_feather_write_error(tmp_dir2):
81+
import pandas as pd
82+
83+
df = pd.DataFrame({"x": [1, 2, 3]})
84+
85+
fname = "some_df"
86+
87+
p_obj = tmp_dir2 / fname
88+
89+
with pytest.raises(NotImplementedError) as exc_info:
90+
save_data(df, p_obj, "feather")
91+
92+
assert '"feather" no longer supported.' in exc_info.value.args[0]
93+
94+
95+
def test_driver_feather_read_backwards_compat(tmp_dir2):
96+
import pandas as pd
97+
98+
df = pd.DataFrame({"x": [1, 2, 3]})
99+
100+
fname = "some_df"
101+
full_file = f"{fname}.feather"
102+
103+
df.to_feather(tmp_dir2 / full_file)
104+
105+
obj = load_data(
106+
MetaRaw(full_file, "feather", "my_pin"), fsspec.filesystem("file"), tmp_dir2
107+
)
108+
109+
assert df.equals(obj)
82110

83111

84112
def test_driver_pickle_read_fail_explicit(some_joblib):

pins/utils.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from functools import update_wrapper
44
from types import MethodType
5+
from warnings import warn
56

67
from .config import pins_options
78

@@ -14,6 +15,10 @@ def inform(log, msg):
1415
print(msg, file=sys.stderr)
1516

1617

18+
def warn_deprecated(msg):
19+
warn(msg, DeprecationWarning)
20+
21+
1722
class ExtendMethodDoc:
1823
# Note that the indentation assumes these are top-level method docstrings,
1924
# so are indented 8 spaces (after the initial sentence).

0 commit comments

Comments
 (0)