@@ -654,6 +654,20 @@ def _can_hold_element(self, element: Any) -> bool:
654
654
return issubclass (tipo .type , dtype )
655
655
return isinstance (element , dtype )
656
656
657
+ def should_store (self , value : ArrayLike ) -> bool :
658
+ """
659
+ Should we set self.values[indexer] = value inplace or do we need to cast?
660
+
661
+ Parameters
662
+ ----------
663
+ value : np.ndarray or ExtensionArray
664
+
665
+ Returns
666
+ -------
667
+ bool
668
+ """
669
+ return is_dtype_equal (value .dtype , self .dtype )
670
+
657
671
def to_native_types (self , slicer = None , na_rep = "nan" , quoting = None , ** kwargs ):
658
672
""" convert to our native types format, slicing if desired """
659
673
values = self .values
@@ -1747,10 +1761,7 @@ def setitem(self, indexer, value):
1747
1761
1748
1762
def get_values (self , dtype = None ):
1749
1763
# ExtensionArrays must be iterable, so this works.
1750
- values = np .asarray (self .values )
1751
- if values .ndim == self .ndim - 1 :
1752
- values = values .reshape ((1 ,) + values .shape )
1753
- return values
1764
+ return np .asarray (self .values ).reshape (self .shape )
1754
1765
1755
1766
def array_values (self ) -> ExtensionArray :
1756
1767
return self .values
@@ -2016,11 +2027,6 @@ def to_native_types(
2016
2027
)
2017
2028
return formatter .get_result_as_array ()
2018
2029
2019
- def should_store (self , value : ArrayLike ) -> bool :
2020
- # when inserting a column should not coerce integers to floats
2021
- # unnecessarily
2022
- return issubclass (value .dtype .type , np .floating ) and value .dtype == self .dtype
2023
-
2024
2030
2025
2031
class ComplexBlock (FloatOrComplexBlock ):
2026
2032
__slots__ = ()
@@ -2053,9 +2059,6 @@ def _can_hold_element(self, element: Any) -> bool:
2053
2059
)
2054
2060
return is_integer (element )
2055
2061
2056
- def should_store (self , value : ArrayLike ) -> bool :
2057
- return is_integer_dtype (value ) and value .dtype == self .dtype
2058
-
2059
2062
2060
2063
class DatetimeLikeBlockMixin :
2061
2064
"""Mixin class for DatetimeBlock, DatetimeTZBlock, and TimedeltaBlock."""
@@ -2064,9 +2067,6 @@ class DatetimeLikeBlockMixin:
2064
2067
def _holder (self ):
2065
2068
return DatetimeArray
2066
2069
2067
- def should_store (self , value ):
2068
- return is_dtype_equal (self .dtype , value .dtype )
2069
-
2070
2070
@property
2071
2071
def fill_value (self ):
2072
2072
return np .datetime64 ("NaT" , "ns" )
@@ -2076,15 +2076,17 @@ def get_values(self, dtype=None):
2076
2076
return object dtype as boxed values, such as Timestamps/Timedelta
2077
2077
"""
2078
2078
if is_object_dtype (dtype ):
2079
- values = self .values .ravel ()
2080
- result = self ._holder (values ).astype (object )
2081
- return result .reshape (self .values .shape )
2079
+ # DTA/TDA constructor and astype can handle 2D
2080
+ return self ._holder (self .values ).astype (object )
2082
2081
return self .values
2083
2082
2084
2083
def internal_values (self ):
2085
2084
# Override to return DatetimeArray and TimedeltaArray
2086
2085
return self .array_values ()
2087
2086
2087
+ def array_values (self ):
2088
+ return self ._holder ._simple_new (self .values )
2089
+
2088
2090
def iget (self , key ):
2089
2091
# GH#31649 we need to wrap scalars in Timestamp/Timedelta
2090
2092
# TODO(EA2D): this can be removed if we ever have 2D EA
@@ -2211,12 +2213,6 @@ def set(self, locs, values):
2211
2213
2212
2214
self .values [locs ] = values
2213
2215
2214
- def external_values (self ):
2215
- return np .asarray (self .values .astype ("datetime64[ns]" , copy = False ))
2216
-
2217
- def array_values (self ) -> ExtensionArray :
2218
- return DatetimeArray ._simple_new (self .values )
2219
-
2220
2216
2221
2217
class DatetimeTZBlock (ExtensionBlock , DatetimeBlock ):
2222
2218
""" implement a datetime64 block with a tz attribute """
@@ -2229,7 +2225,8 @@ class DatetimeTZBlock(ExtensionBlock, DatetimeBlock):
2229
2225
_can_hold_element = DatetimeBlock ._can_hold_element
2230
2226
to_native_types = DatetimeBlock .to_native_types
2231
2227
fill_value = np .datetime64 ("NaT" , "ns" )
2232
- should_store = DatetimeBlock .should_store
2228
+ should_store = Block .should_store
2229
+ array_values = ExtensionBlock .array_values
2233
2230
2234
2231
@property
2235
2232
def _holder (self ):
@@ -2288,14 +2285,16 @@ def get_values(self, dtype=None):
2288
2285
if is_object_dtype (dtype ):
2289
2286
values = values .astype (object )
2290
2287
2291
- values = np .asarray (values )
2288
+ # TODO(EA2D): reshape unnecessary with 2D EAs
2289
+ # Ensure that our shape is correct for DataFrame.
2290
+ # ExtensionArrays are always 1-D, even in a DataFrame when
2291
+ # the analogous NumPy-backed column would be a 2-D ndarray.
2292
+ return np .asarray (values ).reshape (self .shape )
2292
2293
2293
- if self .ndim == 2 :
2294
- # Ensure that our shape is correct for DataFrame.
2295
- # ExtensionArrays are always 1-D, even in a DataFrame when
2296
- # the analogous NumPy-backed column would be a 2-D ndarray.
2297
- values = values .reshape (1 , - 1 )
2298
- return values
2294
+ def external_values (self ):
2295
+ # NB: this is different from np.asarray(self.values), since that
2296
+ # return an object-dtype ndarray of Timestamps.
2297
+ return np .asarray (self .values .astype ("datetime64[ns]" , copy = False ))
2299
2298
2300
2299
def _slice (self , slicer ):
2301
2300
""" return a slice of my values """
@@ -2462,12 +2461,6 @@ def to_native_types(self, slicer=None, na_rep=None, quoting=None, **kwargs):
2462
2461
)
2463
2462
return rvalues
2464
2463
2465
- def external_values (self ):
2466
- return np .asarray (self .values .astype ("timedelta64[ns]" , copy = False ))
2467
-
2468
- def array_values (self ) -> ExtensionArray :
2469
- return TimedeltaArray ._simple_new (self .values )
2470
-
2471
2464
2472
2465
class BoolBlock (NumericBlock ):
2473
2466
__slots__ = ()
@@ -2480,11 +2473,6 @@ def _can_hold_element(self, element: Any) -> bool:
2480
2473
return issubclass (tipo .type , np .bool_ )
2481
2474
return isinstance (element , (bool , np .bool_ ))
2482
2475
2483
- def should_store (self , value : ArrayLike ) -> bool :
2484
- return issubclass (value .dtype .type , np .bool_ ) and not is_extension_array_dtype (
2485
- value
2486
- )
2487
-
2488
2476
def replace (
2489
2477
self , to_replace , value , inplace = False , filter = None , regex = False , convert = True
2490
2478
):
@@ -2572,15 +2560,6 @@ def _maybe_downcast(self, blocks: List["Block"], downcast=None) -> List["Block"]
2572
2560
def _can_hold_element (self , element : Any ) -> bool :
2573
2561
return True
2574
2562
2575
- def should_store (self , value : ArrayLike ) -> bool :
2576
- return not (
2577
- issubclass (
2578
- value .dtype .type ,
2579
- (np .integer , np .floating , np .complexfloating , np .datetime64 , np .bool_ ),
2580
- )
2581
- or is_extension_array_dtype (value )
2582
- )
2583
-
2584
2563
def replace (
2585
2564
self , to_replace , value , inplace = False , filter = None , regex = False , convert = True
2586
2565
):
@@ -2811,6 +2790,8 @@ class CategoricalBlock(ExtensionBlock):
2811
2790
_can_hold_na = True
2812
2791
_concatenator = staticmethod (concat_categorical )
2813
2792
2793
+ should_store = Block .should_store
2794
+
2814
2795
def __init__ (self , values , placement , ndim = None ):
2815
2796
# coerce to categorical if we can
2816
2797
values = extract_array (values )
@@ -2821,9 +2802,6 @@ def __init__(self, values, placement, ndim=None):
2821
2802
def _holder (self ):
2822
2803
return Categorical
2823
2804
2824
- def should_store (self , arr : ArrayLike ):
2825
- return isinstance (arr , self ._holder ) and is_dtype_equal (self .dtype , arr .dtype )
2826
-
2827
2805
def to_native_types (self , slicer = None , na_rep = "" , quoting = None , ** kwargs ):
2828
2806
""" convert to our native types format, slicing if desired """
2829
2807
values = self .values
0 commit comments