Skip to content

Commit

Permalink
DEPR: Deprecate Series.view (#56054)
Browse files Browse the repository at this point in the history
Co-authored-by: Joris Van den Bossche <[email protected]>
  • Loading branch information
phofl and jorisvandenbossche authored Nov 27, 2023
1 parent 6f080bd commit 368643f
Show file tree
Hide file tree
Showing 16 changed files with 37 additions and 48 deletions.
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 @@ -362,6 +362,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 @@ -877,6 +877,10 @@ def view(self, dtype: Dtype | None = None) -> Series:
"""
Create a new view of the Series.
.. deprecated:: 2.2.0
``Series.view`` is deprecated and will be removed in a future version.
Use :meth:`Series.astype` as an alternative to change the dtype.
This function will return a new Series with a view of the same
underlying values in memory, optionally reinterpreted with a new data
type. The new data type must preserve the same size in bytes as to not
Expand Down Expand Up @@ -907,38 +911,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 @@ -1934,7 +1934,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 @@ -726,7 +726,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 @@ -1908,7 +1908,7 @@ def test_api_timedelta(conn, request):
name="foo",
)
else:
expected = df["foo"].view("int64")
expected = df["foo"].astype("int64")
tm.assert_series_equal(result["foo"], expected)


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 @@ -976,7 +976,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

0 comments on commit 368643f

Please sign in to comment.