Skip to content

Commit 3333eec

Browse files
jbrockmendelproost
authored andcommitted
BUG+DEPR: undeprecate item, fix dt64/td64 output type (pandas-dev#30175)
1 parent 03abe49 commit 3333eec

File tree

5 files changed

+69
-44
lines changed

5 files changed

+69
-44
lines changed

doc/source/whatsnew/v1.0.0.rst

+3
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ Documentation Improvements
486486
Deprecations
487487
~~~~~~~~~~~~
488488

489+
- :meth:`Series.item` and :meth:`Index.item` have been _undeprecated_ (:issue:`29250`)
489490
- ``Index.set_value`` has been deprecated. For a given index ``idx``, array ``arr``,
490491
value in ``idx`` of ``idx_val`` and a new value of ``val``, ``idx.set_value(arr, idx_val, val)``
491492
is equivalent to ``arr[idx.get_loc(idx_val)] = val``, which should be used instead (:issue:`28621`).
@@ -703,6 +704,8 @@ Datetimelike
703704
- Bug in :attr:`Timestamp.resolution` being a property instead of a class attribute (:issue:`29910`)
704705
- Bug in :func:`pandas.to_datetime` when called with ``None`` raising ``TypeError`` instead of returning ``NaT`` (:issue:`30011`)
705706
- Bug in :func:`pandas.to_datetime` failing for `deques` when using ``cache=True`` (the default) (:issue:`29403`)
707+
- Bug in :meth:`Series.item` with ``datetime64`` or ``timedelta64`` dtype, :meth:`DatetimeIndex.item`, and :meth:`TimedeltaIndex.item` returning an integer instead of a :class:`Timestamp` or :class:`Timedelta` (:issue:`30175`)
708+
-
706709

707710
Timedelta
708711
^^^^^^^^^

pandas/core/base.py

+17-9
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from collections import OrderedDict
66
import textwrap
77
from typing import Dict, FrozenSet, List, Optional
8-
import warnings
98

109
import numpy as np
1110

@@ -26,6 +25,7 @@
2625
is_object_dtype,
2726
is_scalar,
2827
is_timedelta64_ns_dtype,
28+
needs_i8_conversion,
2929
)
3030
from pandas.core.dtypes.generic import ABCDataFrame, ABCIndexClass, ABCSeries
3131
from pandas.core.dtypes.missing import isna
@@ -659,19 +659,27 @@ def item(self):
659659
"""
660660
Return the first element of the underlying data as a python scalar.
661661
662-
.. deprecated:: 0.25.0
663-
664662
Returns
665663
-------
666664
scalar
667665
The first element of %(klass)s.
666+
667+
Raises
668+
------
669+
ValueError
670+
If the data is not length-1.
668671
"""
669-
warnings.warn(
670-
"`item` has been deprecated and will be removed in a future version",
671-
FutureWarning,
672-
stacklevel=2,
673-
)
674-
return self.values.item()
672+
if not (
673+
is_extension_array_dtype(self.dtype) or needs_i8_conversion(self.dtype)
674+
):
675+
# numpy returns ints instead of datetime64/timedelta64 objects,
676+
# which we need to wrap in Timestamp/Timedelta/Period regardless.
677+
return self.values.item()
678+
679+
if len(self) == 1:
680+
return next(iter(self))
681+
else:
682+
raise ValueError("can only convert an array of size 1 to a Python scalar")
675683

676684
@property
677685
def nbytes(self):

pandas/core/indexes/period.py

-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from datetime import datetime, timedelta
2-
import warnings
32
import weakref
43

54
import numpy as np
@@ -862,27 +861,6 @@ def __setstate__(self, state):
862861

863862
_unpickle_compat = __setstate__
864863

865-
def item(self):
866-
"""
867-
Return the first element of the underlying data as a python
868-
scalar
869-
870-
.. deprecated:: 0.25.0
871-
872-
"""
873-
warnings.warn(
874-
"`item` has been deprecated and will be removed in a future version",
875-
FutureWarning,
876-
stacklevel=2,
877-
)
878-
# TODO(DatetimeArray): remove
879-
if len(self) == 1:
880-
return self[0]
881-
else:
882-
# TODO: is this still necessary?
883-
# copy numpy's message here because Py26 raises an IndexError
884-
raise ValueError("can only convert an array of size 1 to a Python scalar")
885-
886864
def memory_usage(self, deep=False):
887865
result = super().memory_usage(deep=deep)
888866
if hasattr(self, "_cache") and "_int64index" in self._cache:

pandas/tests/base/test_ops.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -236,15 +236,13 @@ def test_ndarray_compat_properties(self):
236236
assert not hasattr(o, p)
237237

238238
with pytest.raises(ValueError):
239-
with tm.assert_produces_warning(FutureWarning):
240-
o.item() # len > 1
239+
o.item() # len > 1
241240

242241
assert o.ndim == 1
243242
assert o.size == len(o)
244243

245-
with tm.assert_produces_warning(FutureWarning):
246-
assert Index([1]).item() == 1
247-
assert Series([1]).item() == 1
244+
assert Index([1]).item() == 1
245+
assert Series([1]).item() == 1
248246

249247
def test_value_counts_unique_nunique(self):
250248
for orig in self.objs:

pandas/tests/series/test_api.py

+46-8
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@
1212
DatetimeIndex,
1313
Index,
1414
Series,
15+
Timedelta,
1516
TimedeltaIndex,
17+
Timestamp,
1618
date_range,
1719
period_range,
1820
timedelta_range,
1921
)
2022
from pandas.core.arrays import PeriodArray
21-
from pandas.core.indexes.datetimes import Timestamp
2223
import pandas.util.testing as tm
2324

2425
import pandas.io.formats.printing as printing
@@ -398,6 +399,50 @@ def test_numpy_unique(self, datetime_series):
398399
# it works!
399400
np.unique(datetime_series)
400401

402+
def test_item(self):
403+
s = Series([1])
404+
result = s.item()
405+
assert result == 1
406+
assert result == s.iloc[0]
407+
assert isinstance(result, int) # i.e. not np.int64
408+
409+
ser = Series([0.5], index=[3])
410+
result = ser.item()
411+
assert isinstance(result, float)
412+
assert result == 0.5
413+
414+
ser = Series([1, 2])
415+
msg = "can only convert an array of size 1"
416+
with pytest.raises(ValueError, match=msg):
417+
ser.item()
418+
419+
dti = pd.date_range("2016-01-01", periods=2)
420+
with pytest.raises(ValueError, match=msg):
421+
dti.item()
422+
with pytest.raises(ValueError, match=msg):
423+
Series(dti).item()
424+
425+
val = dti[:1].item()
426+
assert isinstance(val, Timestamp)
427+
val = Series(dti)[:1].item()
428+
assert isinstance(val, Timestamp)
429+
430+
tdi = dti - dti
431+
with pytest.raises(ValueError, match=msg):
432+
tdi.item()
433+
with pytest.raises(ValueError, match=msg):
434+
Series(tdi).item()
435+
436+
val = tdi[:1].item()
437+
assert isinstance(val, Timedelta)
438+
val = Series(tdi)[:1].item()
439+
assert isinstance(val, Timedelta)
440+
441+
# Case where ser[0] would not work
442+
ser = Series(dti, index=[5, 6])
443+
val = ser[:1].item()
444+
assert val == dti[0]
445+
401446
def test_ndarray_compat(self):
402447

403448
# test numpy compat with Series as sub-class of NDFrame
@@ -414,13 +459,6 @@ def f(x):
414459
expected = tsdf.max()
415460
tm.assert_series_equal(result, expected)
416461

417-
# .item()
418-
with tm.assert_produces_warning(FutureWarning):
419-
s = Series([1])
420-
result = s.item()
421-
assert result == 1
422-
assert s.item() == s.iloc[0]
423-
424462
# using an ndarray like function
425463
s = Series(np.random.randn(10))
426464
result = Series(np.ones_like(s))

0 commit comments

Comments
 (0)