Skip to content
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

DEPR: Deprecate Series.view #56054

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`, use ``astype`` instead to change the dtype (:issue:`20251`)
- Deprecated ``core.internals`` members ``Block``, ``ExtensionBlock``, and ``DatetimeTZBlock``, use public APIs instead (:issue:`55139`)
- 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-integer ``periods`` argument in :func:`date_range`, :func:`timedelta_range`, :func:`period_range`, and :func:`interval_range` (:issue:`56036`)
Expand Down
42 changes: 11 additions & 31 deletions pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,10 @@ def view(self, dtype: Dtype | None = None) -> Series:
type. The new data type must preserve the same size in bytes as to not
cause index misalignment.

.. deprecated:: 2.2.0
phofl marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

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

Apparently this block needs to be placed between the short and extended summary, so after the first sentence above.

Maybe somehow the first error is tripping up further checks ...

``Series.view`` is deprecated and will be removed in a future version.
Use :meth:`Series.astype` as an alternative to change the dtype.

Parameters
----------
dtype : data type
Expand All @@ -906,38 +910,14 @@ def view(self, dtype: Dtype | None = None) -> Series:

Examples
--------
>>> s = pd.Series([-2, -1, 0, 1, 2], dtype='int8')
>>> s
0 -2
1 -1
2 0
3 1
4 2
dtype: int8

The 8 bit signed integer representation of `-1` is `0b11111111`, but
the same bytes represent 255 if read as an 8 bit unsigned integer:

>>> us = s.view('uint8')
>>> us
0 254
1 255
2 0
3 1
4 2
dtype: uint8

The views share the same underlying values:

>>> us[0] = 128
>>> s
0 -128
1 -1
2 0
3 1
4 2
dtype: int8
Use ``astype`` to change the dtype instead.
"""
warnings.warn(
"Series.view is deprecated and will be removed in a future version. "
"Use ``astype`` as an alternative to change the dtype.",
FutureWarning,
stacklevel=2,
)
# 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 @@ -969,7 +969,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
2 changes: 1 addition & 1 deletion pandas/tests/test_algos.py
Original file line number Diff line number Diff line change
Expand Up @@ -957,7 +957,7 @@ def test_isin_datetimelike_values_numeric_comps(self, dtype, dtype1):
# Anything but object and we get all-False shortcut

dta = date_range("2013-01-01", periods=3)._values
arr = Series(dta.view("i8")).view(dtype1)._values
arr = Series(dta.view("i8")).array.view(dtype1)

comps = arr.view("i8").astype(dtype)

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
Loading