Skip to content

Commit fca15ab

Browse files
jbrockmendelKevin D Smith
authored and
Kevin D Smith
committed
ENH/BUG: consistently cast strs to datetimelike for searchsorted (pandas-dev#36346)
1 parent d0e95b4 commit fca15ab

File tree

4 files changed

+43
-10
lines changed

4 files changed

+43
-10
lines changed

doc/source/whatsnew/v1.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ Other enhancements
119119
- :meth:`DataFrame.explode` and :meth:`Series.explode` now support exploding of sets (:issue:`35614`)
120120
- `Styler` now allows direct CSS class name addition to individual data cells (:issue:`36159`)
121121
- :meth:`Rolling.mean()` and :meth:`Rolling.sum()` use Kahan summation to calculate the mean to avoid numerical problems (:issue:`10319`, :issue:`11645`, :issue:`13254`, :issue:`32761`, :issue:`36031`)
122+
- :meth:`DatetimeIndex.searchsorted`, :meth:`TimedeltaIndex.searchsorted`, :meth:`PeriodIndex.searchsorted`, and :meth:`Series.searchsorted` with datetimelike dtypes will now try to cast string arguments (listlike and scalar) to the matching datetimelike type (:issue:`36346`)
122123

123124
.. _whatsnew_120.api_breaking.python:
124125

pandas/core/arrays/datetimelike.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -845,8 +845,7 @@ def _validate_searchsorted_value(self, value):
845845
if not is_list_like(value):
846846
value = self._validate_scalar(value, msg, cast_str=True)
847847
else:
848-
# TODO: cast_str? we accept it for scalar
849-
value = self._validate_listlike(value, "searchsorted")
848+
value = self._validate_listlike(value, "searchsorted", cast_str=True)
850849

851850
rv = self._unbox(value)
852851
return self._rebox_native(rv)

pandas/core/indexes/datetimelike.py

-8
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,6 @@ def take(self, indices, axis=0, allow_fill=True, fill_value=None, **kwargs):
178178

179179
@doc(IndexOpsMixin.searchsorted, klass="Datetime-like Index")
180180
def searchsorted(self, value, side="left", sorter=None):
181-
if isinstance(value, str):
182-
raise TypeError(
183-
"searchsorted requires compatible dtype or scalar, "
184-
f"not {type(value).__name__}"
185-
)
186-
if isinstance(value, Index):
187-
value = value._data
188-
189181
return self._data.searchsorted(value, side=side, sorter=sorter)
190182

191183
_can_hold_na = True

pandas/tests/arrays/test_datetimelike.py

+41
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,47 @@ def test_searchsorted(self):
252252
else:
253253
assert result == 10
254254

255+
@pytest.mark.parametrize("box", [None, "index", "series"])
256+
def test_searchsorted_castable_strings(self, arr1d, box):
257+
if isinstance(arr1d, DatetimeArray):
258+
tz = arr1d.tz
259+
if (
260+
tz is not None
261+
and tz is not pytz.UTC
262+
and not isinstance(tz, pytz._FixedOffset)
263+
):
264+
# If we have e.g. tzutc(), when we cast to string and parse
265+
# back we get pytz.UTC, and then consider them different timezones
266+
# so incorrectly raise.
267+
pytest.xfail(reason="timezone comparisons inconsistent")
268+
269+
arr = arr1d
270+
if box is None:
271+
pass
272+
elif box == "index":
273+
# Test the equivalent Index.searchsorted method while we're here
274+
arr = self.index_cls(arr)
275+
else:
276+
# Test the equivalent Series.searchsorted method while we're here
277+
arr = pd.Series(arr)
278+
279+
# scalar
280+
result = arr.searchsorted(str(arr[1]))
281+
assert result == 1
282+
283+
result = arr.searchsorted(str(arr[2]), side="right")
284+
assert result == 3
285+
286+
result = arr.searchsorted([str(x) for x in arr[1:3]])
287+
expected = np.array([1, 2], dtype=np.intp)
288+
tm.assert_numpy_array_equal(result, expected)
289+
290+
with pytest.raises(TypeError):
291+
arr.searchsorted("foo")
292+
293+
with pytest.raises(TypeError):
294+
arr.searchsorted([str(arr[1]), "baz"])
295+
255296
def test_getitem_2d(self, arr1d):
256297
# 2d slicing on a 1D array
257298
expected = type(arr1d)(arr1d._data[:, np.newaxis], dtype=arr1d.dtype)

0 commit comments

Comments
 (0)