Skip to content

DEPR: Deprecate Series.view #56054

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Nov 27, 2023
1 change: 1 addition & 0 deletions doc/source/whatsnew/v2.2.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ Other Deprecations
- Deprecated :func:`read_gbq` and :meth:`DataFrame.to_gbq`. Use ``pandas_gbq.read_gbq`` and ``pandas_gbq.to_gbq`` instead https://pandas-gbq.readthedocs.io/en/latest/api.html (:issue:`55525`)
- Deprecated :meth:`.DataFrameGroupBy.fillna` and :meth:`.SeriesGroupBy.fillna`; use :meth:`.DataFrameGroupBy.ffill`, :meth:`.DataFrameGroupBy.bfill` for forward and backward filling or :meth:`.DataFrame.fillna` to fill with a single value (or the Series equivalents) (:issue:`55718`)
- Deprecated :meth:`Index.format`, use ``index.astype(str)`` or ``index.map(formatter)`` instead (:issue:`55413`)
- Deprecated :meth:`Series.view` (:issue:`20251`)
- Deprecated ``year``, ``month``, ``quarter``, ``day``, ``hour``, ``minute``, and ``second`` keywords in the :class:`PeriodIndex` constructor, use :meth:`PeriodIndex.from_fields` instead (:issue:`55960`)
- Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_clipboard`. (:issue:`54229`)
- Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_csv` except ``path_or_buf``. (:issue:`54229`)
Expand Down
5 changes: 5 additions & 0 deletions pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,11 @@ def view(self, dtype: Dtype | None = None) -> Series:
4 2
dtype: int8
"""
warnings.warn(
"Series.view is deprecated and will be removed in a future version.",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Point to astype instead if the goal was to change the dtype?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah

FutureWarning,
stacklevel=find_stack_level(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
stacklevel=find_stack_level(),
stacklevel=2,

(see my comment on the ravel PR at #56053 (comment))

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

)
# self.array instead of self._values so we piggyback on NumpyExtensionArray
# implementation
res_values = self.array.view(dtype)
Expand Down
3 changes: 3 additions & 0 deletions pandas/core/window/ewm.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
is_datetime64_ns_dtype,
is_numeric_dtype,
)
from pandas.core.dtypes.generic import ABCSeries
from pandas.core.dtypes.missing import isna

from pandas.core import common
Expand Down Expand Up @@ -118,6 +119,8 @@ def _calculate_deltas(
np.ndarray
Diff of the times divided by the half-life
"""
if isinstance(times, ABCSeries):
times = times._values
_times = np.asarray(times.view(np.int64), dtype=np.float64)
# TODO: generalize to non-nano?
_halflife = float(Timedelta(halflife).as_unit("ns")._value)
Expand Down
4 changes: 2 additions & 2 deletions pandas/io/stata.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,9 +429,9 @@ def parse_dates_safe(
d["year"] = date_index._data.year
d["month"] = date_index._data.month
if days:
days_in_ns = dates.view(np.int64) - to_datetime(
days_in_ns = dates._values.view(np.int64) - to_datetime(
d["year"], format="%Y"
).view(np.int64)
)._values.view(np.int64)
d["days"] = days_in_ns // NS_PER_DAY

elif infer_dtype(dates, skipna=False) == "datetime":
Expand Down
3 changes: 2 additions & 1 deletion pandas/tests/copy_view/test_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -1922,7 +1922,8 @@ def test_series_view(using_copy_on_write, warn_copy_on_write):
ser = Series([1, 2, 3])
ser_orig = ser.copy()

ser2 = ser.view()
with tm.assert_produces_warning(FutureWarning, match="is deprecated"):
ser2 = ser.view()
assert np.shares_memory(get_array(ser), get_array(ser2))
if using_copy_on_write:
assert not ser2._mgr._has_no_reference(0)
Expand Down
3 changes: 2 additions & 1 deletion pandas/tests/frame/indexing/test_where.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,8 @@ def test_where_datetimelike_noop(self, dtype):
# GH#45135, analogue to GH#44181 for Period don't raise on no-op
# For td64/dt64/dt64tz we already don't raise, but also are
# checking that we don't unnecessarily upcast to object.
ser = Series(np.arange(3) * 10**9, dtype=np.int64).view(dtype)
with tm.assert_produces_warning(FutureWarning, match="is deprecated"):
ser = Series(np.arange(3) * 10**9, dtype=np.int64).view(dtype)
df = ser.to_frame()
mask = np.array([False, False, False])

Expand Down
4 changes: 2 additions & 2 deletions pandas/tests/frame/test_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -1101,8 +1101,8 @@ def test_constructor_maskedarray_nonfloat(self):
mat2[0, 0] = 1
mat2[1, 2] = 2
frame = DataFrame(mat2, columns=["A", "B", "C"], index=[1, 2])
assert 1 == frame["A"].view("i8")[1]
assert 2 == frame["C"].view("i8")[2]
assert 1 == frame["A"].astype("i8")[1]
assert 2 == frame["C"].astype("i8")[2]

# masked bool promoted to object
mat = ma.masked_all((2, 3), dtype=bool)
Expand Down
5 changes: 0 additions & 5 deletions pandas/tests/generic/test_finalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@
# - Callable: pass the constructed value with attrs set to this.

_all_methods = [
(
pd.Series,
(np.array([0], dtype="float64")),
operator.methodcaller("view", "int64"),
),
(pd.Series, ([0],), operator.methodcaller("take", [])),
(pd.Series, ([0],), operator.methodcaller("__getitem__", [True])),
(pd.Series, ([0],), operator.methodcaller("repeat", 2)),
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/groupby/test_cumulative.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ def test_cummax_i8_at_implementation_bound():
# the minimum value used to be treated as NPY_NAT+1 instead of NPY_NAT
# for int64 dtype GH#46382
ser = Series([pd.NaT._value + n for n in range(5)])
df = DataFrame({"A": 1, "B": ser, "C": ser.view("M8[ns]")})
df = DataFrame({"A": 1, "B": ser, "C": ser._values.view("M8[ns]")})
gb = df.groupby("A")

res = gb.cummax()
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/groupby/test_timegrouper.py
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ def test_groupby_groups_periods(self):

def test_groupby_first_datetime64(self):
df = DataFrame([(1, 1351036800000000000), (2, 1351036800000000000)])
df[1] = df[1].view("M8[ns]")
df[1] = df[1].astype("M8[ns]")

assert issubclass(df[1].dtype.type, np.datetime64)

Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/io/json/test_pandas.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def test_frame_non_unique_columns(self, orient, data):
# in milliseconds; these are internally stored in nanosecond,
# so divide to get where we need
# TODO: a to_epoch method would also solve; see GH 14772
expected.iloc[:, 0] = expected.iloc[:, 0].view(np.int64) // 1000000
expected.iloc[:, 0] = expected.iloc[:, 0].astype(np.int64) // 1000000
elif orient == "split":
expected = df
expected.columns = ["x", "x.1"]
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/io/test_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -1527,7 +1527,7 @@ def test_api_timedelta(conn, request):
result_count = df.to_sql(name="test_timedelta", con=conn)
assert result_count == 2
result = sql.read_sql_query("SELECT * FROM test_timedelta", conn)
tm.assert_series_equal(result["foo"], df["foo"].view("int64"))
tm.assert_series_equal(result["foo"], df["foo"].astype("int64"))


@pytest.mark.parametrize("conn", all_connectable)
Expand Down
4 changes: 4 additions & 0 deletions pandas/tests/series/methods/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
)
import pandas._testing as tm

pytestmark = pytest.mark.filterwarnings(
"ignore:Series.view is deprecated and will be removed in a future version.:FutureWarning" # noqa: E501
)


class TestView:
def test_view_i8_to_datetimelike(self):
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/series/test_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ def test_constructor_dtype_datetime64_10(self):
# GH3414 related
expected = Series(pydates, dtype="datetime64[ms]")

result = Series(Series(dates).view(np.int64) / 1000000, dtype="M8[ms]")
result = Series(Series(dates).astype(np.int64) / 1000000, dtype="M8[ms]")
tm.assert_series_equal(result, expected)

result = Series(dates, dtype="datetime64[ms]")
Expand Down
4 changes: 4 additions & 0 deletions pandas/tests/test_algos.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
)
import pandas.core.common as com

pytestmark = pytest.mark.filterwarnings(
"ignore:Series.view is deprecated and will be removed in a future version.:FutureWarning" # noqa: E501
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a bit a "dangerous" ignore, because we want to be sure the algos itself aren't raising the warning, and algos seems a part of the codebase that is using view() regularly (although already not with Series objects apparently, assuming it is correct no change is needed there)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can ignore them specifically, will update later

)


class TestFactorize:
def test_factorize_complex(self):
Expand Down
4 changes: 4 additions & 0 deletions pandas/tests/test_nanops.py
Original file line number Diff line number Diff line change
Expand Up @@ -1114,12 +1114,16 @@ def test_nanmean(self, unit):
expected = dti[1]

for obj in [dti, DatetimeArray(dti), Series(dti)]:
if isinstance(obj, Series):
obj = obj._values
result = nanops.nanmean(obj)
assert result == expected

dti2 = dti.insert(1, pd.NaT)

for obj in [dti2, DatetimeArray(dti2), Series(dti2)]:
if isinstance(obj, Series):
obj = obj._values
result = nanops.nanmean(obj)
assert result == expected

Expand Down