Skip to content

Commit 37d4c31

Browse files
authored
REF: do masking in checked_add_with_arr (#47396)
* REF: do masking in checked_add_with_arr * mypy fixup
1 parent 820a065 commit 37d4c31

File tree

3 files changed

+23
-24
lines changed

3 files changed

+23
-24
lines changed

pandas/core/algorithms.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -1017,10 +1017,10 @@ def rank(
10171017

10181018
def checked_add_with_arr(
10191019
arr: npt.NDArray[np.int64],
1020-
b,
1020+
b: int | npt.NDArray[np.int64],
10211021
arr_mask: npt.NDArray[np.bool_] | None = None,
10221022
b_mask: npt.NDArray[np.bool_] | None = None,
1023-
) -> np.ndarray:
1023+
) -> npt.NDArray[np.int64]:
10241024
"""
10251025
Perform array addition that checks for underflow and overflow.
10261026
@@ -1098,7 +1098,12 @@ def checked_add_with_arr(
10981098

10991099
if to_raise:
11001100
raise OverflowError("Overflow in int64 addition")
1101-
return arr + b
1101+
1102+
result = arr + b
1103+
if arr_mask is not None or b2_mask is not None:
1104+
np.putmask(result, ~not_nan, iNaT)
1105+
1106+
return result
11021107

11031108

11041109
# --------------- #

pandas/core/arrays/datetimelike.py

+15-19
Original file line numberDiff line numberDiff line change
@@ -1105,8 +1105,12 @@ def _add_datetimelike_scalar(self, other):
11051105
return DatetimeArray(result)
11061106

11071107
i8 = self.asi8
1108-
result = checked_add_with_arr(i8, other.value, arr_mask=self._isnan)
1109-
result = self._maybe_mask_results(result)
1108+
# Incompatible types in assignment (expression has type "ndarray[Any,
1109+
# dtype[signedinteger[_64Bit]]]", variable has type
1110+
# "ndarray[Any, dtype[datetime64]]")
1111+
result = checked_add_with_arr( # type: ignore[assignment]
1112+
i8, other.value, arr_mask=self._isnan
1113+
)
11101114
dtype = DatetimeTZDtype(tz=other.tz) if other.tz else DT64NS_DTYPE
11111115
return DatetimeArray(result, dtype=dtype, freq=self.freq)
11121116

@@ -1147,7 +1151,6 @@ def _sub_datetimelike_scalar(self, other: datetime | np.datetime64):
11471151

11481152
i8 = self.asi8
11491153
result = checked_add_with_arr(i8, -other.value, arr_mask=self._isnan)
1150-
result = self._maybe_mask_results(result)
11511154
return result.view("timedelta64[ns]")
11521155

11531156
@final
@@ -1169,31 +1172,30 @@ def _sub_datetime_arraylike(self, other):
11691172

11701173
self_i8 = self.asi8
11711174
other_i8 = other.asi8
1172-
arr_mask = self._isnan | other._isnan
1173-
new_values = checked_add_with_arr(self_i8, -other_i8, arr_mask=arr_mask)
1174-
if self._hasna or other._hasna:
1175-
np.putmask(new_values, arr_mask, iNaT)
1175+
new_values = checked_add_with_arr(
1176+
self_i8, -other_i8, arr_mask=self._isnan, b_mask=other._isnan
1177+
)
11761178
return new_values.view("timedelta64[ns]")
11771179

11781180
@final
1179-
def _sub_period(self, other: Period):
1181+
def _sub_period(self, other: Period) -> npt.NDArray[np.object_]:
11801182
if not is_period_dtype(self.dtype):
11811183
raise TypeError(f"cannot subtract Period from a {type(self).__name__}")
11821184

11831185
# If the operation is well-defined, we return an object-dtype ndarray
11841186
# of DateOffsets. Null entries are filled with pd.NaT
11851187
self._check_compatible_with(other)
11861188
asi8 = self.asi8
1187-
new_data = asi8 - other.ordinal
1188-
new_data = np.array([self.freq.base * x for x in new_data])
1189+
new_i8_data = asi8 - other.ordinal # TODO: checked_add_with_arr
1190+
new_data = np.array([self.freq.base * x for x in new_i8_data])
11891191

11901192
if self._hasna:
11911193
new_data[self._isnan] = NaT
11921194

11931195
return new_data
11941196

11951197
@final
1196-
def _add_period(self, other: Period):
1198+
def _add_period(self, other: Period) -> PeriodArray:
11971199
if not is_timedelta64_dtype(self.dtype):
11981200
raise TypeError(f"cannot add Period to a {type(self).__name__}")
11991201

@@ -1226,8 +1228,6 @@ def _add_timedeltalike_scalar(self, other):
12261228
inc = delta_to_nanoseconds(other, reso=self._reso) # type: ignore[attr-defined]
12271229

12281230
new_values = checked_add_with_arr(self.asi8, inc, arr_mask=self._isnan)
1229-
new_values = new_values.view("i8")
1230-
new_values = self._maybe_mask_results(new_values)
12311231
new_values = new_values.view(self._ndarray.dtype)
12321232

12331233
new_freq = None
@@ -1263,10 +1263,6 @@ def _add_timedelta_arraylike(
12631263
new_values = checked_add_with_arr(
12641264
self_i8, other_i8, arr_mask=self._isnan, b_mask=other._isnan
12651265
)
1266-
if self._hasna or other._hasna:
1267-
mask = self._isnan | other._isnan
1268-
np.putmask(new_values, mask, iNaT)
1269-
12701266
return type(self)(new_values, dtype=self.dtype)
12711267

12721268
@final
@@ -1310,11 +1306,11 @@ def _sub_period_array(self, other: PeriodArray) -> npt.NDArray[np.object_]:
13101306
self = cast("PeriodArray", self)
13111307
self._require_matching_freq(other)
13121308

1313-
new_values = checked_add_with_arr(
1309+
new_i8_values = checked_add_with_arr(
13141310
self.asi8, -other.asi8, arr_mask=self._isnan, b_mask=other._isnan
13151311
)
13161312

1317-
new_values = np.array([self.freq.base * x for x in new_values])
1313+
new_values = np.array([self.freq.base * x for x in new_i8_values])
13181314
if self._hasna or other._hasna:
13191315
mask = self._isnan | other._isnan
13201316
new_values[mask] = NaT

pandas/core/arrays/period.py

-2
Original file line numberDiff line numberDiff line change
@@ -734,8 +734,6 @@ def _addsub_int_array_or_scalar(
734734
if op is operator.sub:
735735
other = -other
736736
res_values = algos.checked_add_with_arr(self.asi8, other, arr_mask=self._isnan)
737-
res_values = res_values.view("i8")
738-
np.putmask(res_values, self._isnan, iNaT)
739737
return type(self)(res_values, freq=self.freq)
740738

741739
def _add_offset(self, other: BaseOffset):

0 commit comments

Comments
 (0)