Skip to content

Commit 38f701e

Browse files
authored
REF: implement ensure_can_hold_na (#39714)
1 parent 2b490df commit 38f701e

File tree

2 files changed

+23
-9
lines changed

2 files changed

+23
-9
lines changed

pandas/core/dtypes/cast.py

+18-3
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,8 @@ def maybe_upcast_putmask(result: np.ndarray, mask: np.ndarray) -> np.ndarray:
475475
# upcast (possibly), otherwise we DON't want to upcast (e.g. if we
476476
# have values, say integers, in the success portion then it's ok to not
477477
# upcast)
478-
new_dtype, _ = maybe_promote(result.dtype, np.nan)
478+
new_dtype = ensure_dtype_can_hold_na(result.dtype)
479+
479480
if new_dtype != result.dtype:
480481
result = result.astype(new_dtype, copy=True)
481482

@@ -484,7 +485,21 @@ def maybe_upcast_putmask(result: np.ndarray, mask: np.ndarray) -> np.ndarray:
484485
return result
485486

486487

487-
def maybe_promote(dtype, fill_value=np.nan):
488+
def ensure_dtype_can_hold_na(dtype: DtypeObj) -> DtypeObj:
489+
"""
490+
If we have a dtype that cannot hold NA values, find the best match that can.
491+
"""
492+
if isinstance(dtype, ExtensionDtype):
493+
# TODO: ExtensionDtype.can_hold_na?
494+
return dtype
495+
elif dtype.kind == "b":
496+
return np.dtype(object)
497+
elif dtype.kind in ["i", "u"]:
498+
return np.dtype(np.float64)
499+
return dtype
500+
501+
502+
def maybe_promote(dtype: DtypeObj, fill_value=np.nan):
488503
"""
489504
Find the minimal dtype that can hold both the given dtype and fill_value.
490505
@@ -565,7 +580,7 @@ def maybe_promote(dtype, fill_value=np.nan):
565580
fill_value = np.timedelta64("NaT", "ns")
566581
else:
567582
fill_value = fv.to_timedelta64()
568-
elif is_datetime64tz_dtype(dtype):
583+
elif isinstance(dtype, DatetimeTZDtype):
569584
if isna(fill_value):
570585
fill_value = NaT
571586
elif not isinstance(fill_value, datetime):

pandas/core/internals/concat.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@
1111
from pandas._typing import ArrayLike, DtypeObj, Manager, Shape
1212
from pandas.util._decorators import cache_readonly
1313

14-
from pandas.core.dtypes.cast import find_common_type, maybe_promote
14+
from pandas.core.dtypes.cast import ensure_dtype_can_hold_na, find_common_type
1515
from pandas.core.dtypes.common import (
16-
get_dtype,
1716
is_categorical_dtype,
1817
is_datetime64_dtype,
1918
is_datetime64tz_dtype,
@@ -225,13 +224,13 @@ def needs_filling(self) -> bool:
225224

226225
@cache_readonly
227226
def dtype(self):
228-
if self.block is None:
227+
blk = self.block
228+
if blk is None:
229229
raise AssertionError("Block is None, no dtype")
230230

231231
if not self.needs_filling:
232-
return self.block.dtype
233-
else:
234-
return get_dtype(maybe_promote(self.block.dtype, self.block.fill_value)[0])
232+
return blk.dtype
233+
return ensure_dtype_can_hold_na(blk.dtype)
235234

236235
@cache_readonly
237236
def is_na(self) -> bool:

0 commit comments

Comments
 (0)