diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 414794dd6a56e..37f560807f1ca 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -948,6 +948,8 @@ Numeric - Bug in :meth:`Series.count` would result in an ``int32`` result on 32-bit platforms when argument ``level=None`` (:issue:`40908`) - Bug in :class:`Series` and :class:`DataFrame` reductions with methods ``any`` and ``all`` not returning Boolean results for object data (:issue:`12863`, :issue:`35450`, :issue:`27709`) - Bug in :meth:`Series.clip` would fail if the Series contains NA values and has nullable int or float as a data type (:issue:`40851`) +- Bug in :meth:`UInt64Index.where` and :meth:`UInt64Index.putmask` with an ``np.int64`` dtype ``other`` incorrectly raising ``TypeError`` (:issue:`41974`) + Conversion ^^^^^^^^^^ diff --git a/pandas/core/indexes/numeric.py b/pandas/core/indexes/numeric.py index ea2d5d9eec6ac..ce93cdff09ae0 100644 --- a/pandas/core/indexes/numeric.py +++ b/pandas/core/indexes/numeric.py @@ -370,6 +370,16 @@ class UInt64Index(IntegerIndex): _default_dtype = np.dtype(np.uint64) _dtype_validation_metadata = (is_unsigned_integer_dtype, "unsigned integer") + def _validate_fill_value(self, value): + # e.g. np.array([1]) we want np.array([1], dtype=np.uint64) + # see test_where_uin64 + super()._validate_fill_value(value) + if hasattr(value, "dtype") and is_signed_integer_dtype(value.dtype): + if (value >= 0).all(): + return value.astype(self.dtype) + raise TypeError + return value + class Float64Index(NumericIndex): _index_descr_args = { diff --git a/pandas/tests/indexes/numeric/test_indexing.py b/pandas/tests/indexes/numeric/test_indexing.py index 5f2f8f75045bb..540dbde609470 100644 --- a/pandas/tests/indexes/numeric/test_indexing.py +++ b/pandas/tests/indexes/numeric/test_indexing.py @@ -376,6 +376,19 @@ def test_where(self, klass, index): result = index.where(klass(cond)) tm.assert_index_equal(result, expected) + def test_where_uin64(self): + idx = UInt64Index([0, 6, 2]) + mask = np.array([False, True, False]) + other = np.array([1], dtype=np.int64) + + expected = UInt64Index([1, 6, 1]) + + result = idx.where(mask, other) + tm.assert_index_equal(result, expected) + + result = idx.putmask(~mask, other) + tm.assert_index_equal(result, expected) + class TestTake: @pytest.mark.parametrize("klass", [Float64Index, Int64Index, UInt64Index])