Skip to content

Commit 679cb6f

Browse files
committed
BUG: df.replace over pd.Period columns (pandas-dev#34904)
1 parent 407fd14 commit 679cb6f

File tree

3 files changed

+25
-4
lines changed

3 files changed

+25
-4
lines changed

pandas/core/internals/blocks.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import pandas._libs.internals as libinternals
1111
from pandas._libs.internals import BlockPlacement
1212
from pandas._libs.tslibs import conversion
13+
from pandas._libs.tslibs.period import Period
1314
from pandas._libs.tslibs.timezones import tz_compare
1415
from pandas._typing import ArrayLike, Scalar
1516
from pandas.util._validators import validate_bool_kwarg
@@ -1975,6 +1976,18 @@ def external_values(self):
19751976
return self.values.astype(object)
19761977

19771978

1979+
class PeriodExtensionBlock(ObjectValuesExtensionBlock):
1980+
"""
1981+
Used by PeriodArray to ensure proper type conversions
1982+
"""
1983+
1984+
def _can_hold_element(self, element: Any) -> bool:
1985+
tipo = maybe_infer_dtype_type(element)
1986+
if tipo is not None:
1987+
return issubclass(tipo.type, Period)
1988+
return isinstance(element, Period)
1989+
1990+
19781991
class NumericBlock(Block):
19791992
__slots__ = ()
19801993
is_numeric = True
@@ -2747,8 +2760,10 @@ def get_block_type(values, dtype=None):
27472760
cls = DatetimeBlock
27482761
elif is_datetime64tz_dtype(values.dtype):
27492762
cls = DatetimeTZBlock
2750-
elif is_interval_dtype(dtype) or is_period_dtype(dtype):
2763+
elif is_interval_dtype(dtype):
27512764
cls = ObjectValuesExtensionBlock
2765+
elif is_period_dtype(dtype):
2766+
cls = PeriodExtensionBlock
27522767
elif is_extension_array_dtype(values.dtype):
27532768
cls = ExtensionBlock
27542769
elif issubclass(vtype, np.floating):

pandas/core/internals/managers.py

+9
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
DatetimeTZBlock,
4848
ExtensionBlock,
4949
ObjectValuesExtensionBlock,
50+
PeriodExtensionBlock,
5051
extend_blocks,
5152
get_block_type,
5253
make_block,
@@ -1743,6 +1744,14 @@ def form_blocks(arrays, names: Index, axes) -> List[Block]:
17431744

17441745
blocks.extend(external_blocks)
17451746

1747+
if len(items_dict["PeriodExtensionBlock"]):
1748+
external_blocks = [
1749+
make_block(array, klass=PeriodExtensionBlock, placement=i)
1750+
for i, _, array in items_dict["PeriodExtensionBlock"]
1751+
]
1752+
1753+
blocks.extend(external_blocks)
1754+
17461755
if len(extra_locs):
17471756
shape = (len(extra_locs),) + tuple(len(x) for x in axes[1:])
17481757

pandas/tests/frame/methods/test_replace.py

-3
Original file line numberDiff line numberDiff line change
@@ -1517,9 +1517,6 @@ def test_replace_with_duplicate_columns(self, replacement):
15171517

15181518
tm.assert_frame_equal(result, expected)
15191519

1520-
@pytest.mark.xfail(
1521-
reason="replace() changes dtype from period to object, see GH34871", strict=True
1522-
)
15231520
def test_replace_period_ignore_float(self):
15241521
"""
15251522
Regression test for GH#34871: if df.replace(1.0, 0.0) is called on a df

0 commit comments

Comments
 (0)