Skip to content

Commit 0f2c5d4

Browse files
authored
BUG: setting td64 value into Series[numeric] (#39086)
1 parent ec4a644 commit 0f2c5d4

File tree

4 files changed

+36
-16
lines changed

4 files changed

+36
-16
lines changed

doc/source/whatsnew/v1.3.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ Indexing
251251
- Bug in :meth:`DataFrame.__setitem__` raising ``ValueError`` with empty :class:`DataFrame` and specified columns for string indexer and non empty :class:`DataFrame` to set (:issue:`38831`)
252252
- Bug in :meth:`DataFrame.iloc.__setitem__` and :meth:`DataFrame.loc.__setitem__` with mixed dtypes when setting with a dictionary value (:issue:`38335`)
253253
- Bug in :meth:`DataFrame.loc` dropping levels of :class:`MultiIndex` when :class:`DataFrame` used as input has only one row (:issue:`10521`)
254-
-
254+
- Bug in setting ``timedelta64`` values into numeric :class:`Series` failing to cast to object dtype (:issue:`39086`)
255255

256256
Missing
257257
^^^^^^^

pandas/core/dtypes/cast.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -1874,9 +1874,9 @@ def validate_numeric_casting(dtype: np.dtype, value: Scalar) -> None:
18741874
):
18751875
raise ValueError("Cannot assign nan to integer series")
18761876

1877-
if (
1878-
issubclass(dtype.type, (np.integer, np.floating, complex))
1879-
and not issubclass(dtype.type, np.bool_)
1880-
and is_bool(value)
1881-
):
1882-
raise ValueError("Cannot assign bool to float/integer series")
1877+
if dtype.kind in ["i", "u", "f", "c"]:
1878+
if is_bool(value) or isinstance(value, np.timedelta64):
1879+
# numpy will cast td64 to integer if we're not careful
1880+
raise ValueError(
1881+
f"Cannot assign {type(value).__name__} to float/integer series"
1882+
)

pandas/core/internals/blocks.py

+5-9
Original file line numberDiff line numberDiff line change
@@ -678,11 +678,7 @@ def convert(
678678

679679
def _can_hold_element(self, element: Any) -> bool:
680680
""" require the same dtype as ourselves """
681-
dtype = self.values.dtype.type
682-
tipo = maybe_infer_dtype_type(element)
683-
if tipo is not None:
684-
return issubclass(tipo.type, dtype)
685-
return isinstance(element, dtype)
681+
raise NotImplementedError("Implemented on subclasses")
686682

687683
def should_store(self, value: ArrayLike) -> bool:
688684
"""
@@ -1969,10 +1965,10 @@ class ComplexBlock(NumericBlock):
19691965
def _can_hold_element(self, element: Any) -> bool:
19701966
tipo = maybe_infer_dtype_type(element)
19711967
if tipo is not None:
1972-
return issubclass(tipo.type, (np.floating, np.integer, np.complexfloating))
1973-
return isinstance(
1974-
element, (float, int, complex, np.float_, np.int_)
1975-
) and not isinstance(element, (bool, np.bool_))
1968+
return tipo.kind in ["c", "f", "i", "u"]
1969+
return (
1970+
lib.is_integer(element) or lib.is_complex(element) or lib.is_float(element)
1971+
)
19761972

19771973

19781974
class IntBlock(NumericBlock):

pandas/tests/series/indexing/test_setitem.py

+24
Original file line numberDiff line numberDiff line change
@@ -395,3 +395,27 @@ def test_setitem_slice_into_readonly_backing_data():
395395
series[1:3] = 1
396396

397397
assert not array.any()
398+
399+
400+
@pytest.mark.parametrize(
401+
"key", [0, slice(0, 1), [0], np.array([0]), range(1)], ids=type
402+
)
403+
@pytest.mark.parametrize("dtype", [complex, int, float])
404+
def test_setitem_td64_into_complex(key, dtype, indexer_sli):
405+
# timedelta64 should not be treated as integers
406+
arr = np.arange(5).astype(dtype)
407+
ser = Series(arr)
408+
td = np.timedelta64(4, "ns")
409+
410+
indexer_sli(ser)[key] = td
411+
assert ser.dtype == object
412+
assert arr[0] == 0 # original array is unchanged
413+
414+
if not isinstance(key, int) and not (
415+
indexer_sli is tm.loc and isinstance(key, slice)
416+
):
417+
# skip key/indexer_sli combinations that will have mismatched lengths
418+
ser = Series(arr)
419+
indexer_sli(ser)[key] = np.full((1,), td)
420+
assert ser.dtype == object
421+
assert arr[0] == 0 # original array is unchanged

0 commit comments

Comments
 (0)