Skip to content

Commit 36624fc

Browse files
keep everything in method for minimal change
1 parent f901d8d commit 36624fc

File tree

9 files changed

+50
-87
lines changed

9 files changed

+50
-87
lines changed

pandas/core/arrays/arrow/array.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ def _cast_pointwise_result(self, values) -> ArrayLike:
442442
# e.g. test_by_column_values_with_same_starting_value with nested
443443
# values, one entry of which is an ArrowStringArray
444444
# or test_agg_lambda_complex128_dtype_conversion for complex values
445-
return values
445+
return super()._cast_pointwise_result(values)
446446

447447
if pa.types.is_null(arr.type):
448448
if lib.infer_dtype(values) == "decimal":
@@ -498,7 +498,7 @@ def _cast_pointwise_result(self, values) -> ArrayLike:
498498
if self.dtype.na_value is np.nan:
499499
# ArrowEA has different semantics, so we return numpy-based
500500
# result instead
501-
return values
501+
return super()._cast_pointwise_result(values)
502502
return ArrowExtensionArray(arr)
503503
return self._from_pyarrow_array(arr)
504504

pandas/core/arrays/base.py

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,36 @@ def _from_sequence_of_strings(
356356
"""
357357
raise AbstractMethodError(cls)
358358

359+
@classmethod
360+
def _from_factorized(cls, values, original):
361+
"""
362+
Reconstruct an ExtensionArray after factorization.
363+
364+
Parameters
365+
----------
366+
values : ndarray
367+
An integer ndarray with the factorized values.
368+
original : ExtensionArray
369+
The original ExtensionArray that factorize was called on.
370+
371+
See Also
372+
--------
373+
factorize : Top-level factorize method that dispatches here.
374+
ExtensionArray.factorize : Encode the extension array as an enumerated type.
375+
376+
Examples
377+
--------
378+
>>> interv_arr = pd.arrays.IntervalArray(
379+
... [pd.Interval(0, 1), pd.Interval(1, 5), pd.Interval(1, 5)]
380+
... )
381+
>>> codes, uniques = pd.factorize(interv_arr)
382+
>>> pd.arrays.IntervalArray._from_factorized(uniques, interv_arr)
383+
<IntervalArray>
384+
[(0, 1], (1, 5]]
385+
Length: 2, dtype: interval[int64, right]
386+
"""
387+
raise AbstractMethodError(cls)
388+
359389
@classmethod
360390
def _from_scalars(cls, scalars, *, dtype: DtypeObj) -> Self:
361391
"""
@@ -374,7 +404,7 @@ def _from_scalars(cls, scalars, *, dtype: DtypeObj) -> Self:
374404
Notes
375405
-----
376406
This is called in a try/except block when casting the result of a
377-
pointwise operation.
407+
pointwise operation in ExtensionArray._cast_pointwise_result.
378408
"""
379409
try:
380410
return cls._from_sequence(scalars, dtype=dtype, copy=False)
@@ -388,37 +418,7 @@ def _from_scalars(cls, scalars, *, dtype: DtypeObj) -> Self:
388418
)
389419
raise
390420

391-
@classmethod
392-
def _from_factorized(cls, values, original):
393-
"""
394-
Reconstruct an ExtensionArray after factorization.
395-
396-
Parameters
397-
----------
398-
values : ndarray
399-
An integer ndarray with the factorized values.
400-
original : ExtensionArray
401-
The original ExtensionArray that factorize was called on.
402-
403-
See Also
404-
--------
405-
factorize : Top-level factorize method that dispatches here.
406-
ExtensionArray.factorize : Encode the extension array as an enumerated type.
407-
408-
Examples
409-
--------
410-
>>> interv_arr = pd.arrays.IntervalArray(
411-
... [pd.Interval(0, 1), pd.Interval(1, 5), pd.Interval(1, 5)]
412-
... )
413-
>>> codes, uniques = pd.factorize(interv_arr)
414-
>>> pd.arrays.IntervalArray._from_factorized(uniques, interv_arr)
415-
<IntervalArray>
416-
[(0, 1], (1, 5]]
417-
Length: 2, dtype: interval[int64, right]
418-
"""
419-
raise AbstractMethodError(cls)
420-
421-
def _cast_pointwise_result(self, values: ArrayLike) -> ArrayLike:
421+
def _cast_pointwise_result(self, values) -> ArrayLike:
422422
"""
423423
Construct an ExtensionArray after a pointwise operation.
424424
@@ -437,7 +437,8 @@ def _cast_pointwise_result(self, values: ArrayLike) -> ArrayLike:
437437
try:
438438
return type(self)._from_scalars(values, dtype=self.dtype)
439439
except (ValueError, TypeError):
440-
return values
440+
values = np.asarray(values, dtype=object)
441+
return lib.maybe_convert_objects(values, convert_non_numeric=True)
441442

442443
# ------------------------------------------------------------------------
443444
# Must be a Sequence

pandas/core/arrays/sparse/array.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ def _from_factorized(cls, values, original) -> Self:
622622
return cls(values, dtype=original.dtype)
623623

624624
def _cast_pointwise_result(self, values):
625+
values = np.asarray(values, dtype=object)
625626
result = lib.maybe_convert_objects(values, convert_non_numeric=True)
626627
if result.dtype.kind == self.dtype.kind:
627628
try:

pandas/core/dtypes/cast.py

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -414,42 +414,6 @@ def maybe_upcast_numeric_to_64bit(arr: NumpyIndexT) -> NumpyIndexT:
414414
return arr
415415

416416

417-
def cast_pointwise_result(
418-
result: ArrayLike,
419-
original_array: ArrayLike,
420-
) -> ArrayLike:
421-
"""
422-
Try casting result of a pointwise operation back to the original dtype if
423-
appropriate.
424-
425-
Parameters
426-
----------
427-
result : array-like
428-
Result to cast.
429-
original_array : array-like
430-
Input array from which result was calculated.
431-
432-
Returns
433-
-------
434-
array-like
435-
"""
436-
if isinstance(original_array.dtype, ExtensionDtype):
437-
try:
438-
result = original_array._cast_pointwise_result(result)
439-
except (TypeError, ValueError):
440-
pass
441-
442-
if isinstance(result.dtype, ExtensionDtype):
443-
return result
444-
445-
if not isinstance(result, np.ndarray):
446-
result = np.asarray(result, dtype=object)
447-
448-
if result.dtype != object:
449-
return result
450-
return lib.maybe_convert_objects(result, convert_non_numeric=True)
451-
452-
453417
@overload
454418
def ensure_dtype_can_hold_na(dtype: np.dtype) -> np.dtype: ...
455419

pandas/core/frame.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@
8484
from pandas.core.dtypes.cast import (
8585
LossySetitemError,
8686
can_hold_element,
87-
cast_pointwise_result,
8887
construct_1d_arraylike_from_scalar,
8988
construct_2d_arraylike_from_scalar,
9089
find_common_type,
@@ -11201,7 +11200,7 @@ def _append_internal(
1120111200
if isinstance(self.index.dtype, ExtensionDtype):
1120211201
# GH#41626 retain e.g. CategoricalDtype if reached via
1120311202
# df.loc[key] = item
11204-
row_df.index = cast_pointwise_result(row_df.index._values, self.index.array)
11203+
row_df.index = self.index.array._cast_pointwise_result(row_df.index._values)
1120511204

1120611205
# infer_objects is needed for
1120711206
# test_append_empty_frame_to_series_with_dateutil_tz

pandas/core/groupby/ops.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
from pandas.util._decorators import cache_readonly
3636

3737
from pandas.core.dtypes.cast import (
38-
cast_pointwise_result,
3938
maybe_downcast_to_dtype,
4039
)
4140
from pandas.core.dtypes.common import (
@@ -964,7 +963,7 @@ def agg_series(
964963
np.ndarray or ExtensionArray
965964
"""
966965
result = self._aggregate_series_pure_python(obj, func)
967-
return cast_pointwise_result(result, obj.array)
966+
return obj.array._cast_pointwise_result(result)
968967

969968
@final
970969
def _aggregate_series_pure_python(

pandas/core/indexes/base.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@
8989
from pandas.core.dtypes.cast import (
9090
LossySetitemError,
9191
can_hold_element,
92-
cast_pointwise_result,
9392
common_dtype_categorical_compat,
9493
find_result_type,
9594
infer_dtype_from,
@@ -6544,7 +6543,7 @@ def map(self, mapper, na_action: Literal["ignore"] | None = None):
65446543
# e.g. if we are floating and new_values is all ints, then we
65456544
# don't want to cast back to floating. But if we are UInt64
65466545
# and new_values is all ints, we want to try.
6547-
new_values = cast_pointwise_result(new_values, arr)
6546+
new_values = arr._cast_pointwise_result(new_values)
65486547
dtype = new_values.dtype
65496548
return Index(new_values, dtype=dtype, copy=False, name=self.name)
65506549

pandas/core/series.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@
6969
from pandas.core.dtypes.astype import astype_is_view
7070
from pandas.core.dtypes.cast import (
7171
LossySetitemError,
72-
cast_pointwise_result,
7372
construct_1d_arraylike_from_scalar,
7473
find_common_type,
7574
infer_dtype_from,
@@ -3257,7 +3256,7 @@ def combine(
32573256
new_values[:] = [func(lv, other) for lv in self._values]
32583257
new_name = self.name
32593258

3260-
res_values = cast_pointwise_result(new_values, self.array)
3259+
res_values = self.array._cast_pointwise_result(new_values)
32613260
return self._constructor(
32623261
res_values,
32633262
dtype=res_values.dtype,

pandas/tests/extension/decimal/array.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,15 @@ def _from_sequence_of_strings(cls, strings, *, dtype: ExtensionDtype, copy=False
111111
def _from_factorized(cls, values, original):
112112
return cls(values)
113113

114-
def _cast_pointwise_result(self, values):
115-
try:
116-
# If this were ever made a non-test EA, special-casing could
117-
# be avoided by handling Decimal in maybe_convert_objects
118-
res = type(self)._from_sequence(values, dtype=self.dtype)
119-
except (ValueError, TypeError):
120-
return values
121-
return res
114+
# test to ensure that the base class _cast_pointwise_result works as expected
115+
# def _cast_pointwise_result(self, values):
116+
# try:
117+
# # If this were ever made a non-test EA, special-casing could
118+
# # be avoided by handling Decimal in maybe_convert_objects
119+
# res = type(self)._from_sequence(values, dtype=self.dtype)
120+
# except (ValueError, TypeError):
121+
# return values
122+
# return res
122123

123124
_HANDLED_TYPES = (decimal.Decimal, numbers.Number, np.ndarray)
124125

0 commit comments

Comments
 (0)