22
22
writers ,
23
23
)
24
24
from pandas ._libs .internals import BlockPlacement
25
+ from pandas ._libs .tslibs import IncompatibleFrequency
25
26
from pandas ._typing import (
26
27
ArrayLike ,
27
28
DtypeObj ,
105
106
ensure_wrapped_if_datetimelike ,
106
107
extract_array ,
107
108
)
108
- from pandas .core .indexers import (
109
- check_setitem_lengths ,
110
- is_empty_indexer ,
111
- is_scalar_indexer ,
112
- )
109
+ from pandas .core .indexers import check_setitem_lengths
113
110
import pandas .core .missing as missing
114
111
115
112
if TYPE_CHECKING :
@@ -919,32 +916,29 @@ def setitem(self, indexer, value):
919
916
920
917
value = self ._standardize_fill_value (value )
921
918
922
- # coerce if block dtype can store value
923
- if not self ._can_hold_element (value ):
924
- # current dtype cannot store value, coerce to common dtype
925
- return self .coerce_to_target_dtype (value ).setitem (indexer , value )
926
-
927
- # value must be storable at this moment
928
919
values = cast (np .ndarray , self .values )
929
920
if self .ndim == 2 :
930
921
values = values .T
931
922
932
923
# length checking
933
924
check_setitem_lengths (indexer , value , values )
934
925
935
- if is_empty_indexer (indexer ):
936
- # GH#8669 empty indexers, test_loc_setitem_boolean_mask_allfalse
937
- values [indexer ] = value
938
-
939
- elif is_scalar_indexer (indexer , self .ndim ):
940
- # setting a single element for each dim and with a rhs that could
941
- # be e.g. a list; see GH#6043
942
- values [indexer ] = value
943
-
926
+ value = extract_array (value , extract_numpy = True )
927
+ try :
928
+ casted = np_can_hold_element (values .dtype , value )
929
+ except ValueError :
930
+ # current dtype cannot store value, coerce to common dtype
931
+ nb = self .coerce_to_target_dtype (value )
932
+ return nb .setitem (indexer , value )
944
933
else :
945
- value = setitem_datetimelike_compat (values , len (values [indexer ]), value )
946
- values [indexer ] = value
947
-
934
+ if self .dtype == _dtype_obj :
935
+ # TODO: avoid having to construct values[indexer]
936
+ vi = values [indexer ]
937
+ if lib .is_list_like (vi ):
938
+ # checking lib.is_scalar here fails on
939
+ # test_iloc_setitem_custom_object
940
+ casted = setitem_datetimelike_compat (values , len (vi ), casted )
941
+ values [indexer ] = casted
948
942
return self
949
943
950
944
def putmask (self , mask , new ) -> list [Block ]:
@@ -1348,10 +1342,8 @@ def setitem(self, indexer, value):
1348
1342
`indexer` is a direct slice/positional indexer. `value` must
1349
1343
be a compatible shape.
1350
1344
"""
1351
- if not self ._can_hold_element (value ):
1352
- # see TestSetitemFloatIntervalWithIntIntervalValues
1353
- nb = self .coerce_to_target_dtype (value )
1354
- return nb .setitem (indexer , value )
1345
+ orig_indexer = indexer
1346
+ orig_value = value
1355
1347
1356
1348
indexer = self ._unwrap_setitem_indexer (indexer )
1357
1349
value = self ._maybe_squeeze_arg (value )
@@ -1362,8 +1354,26 @@ def setitem(self, indexer, value):
1362
1354
# unconditionally
1363
1355
values = values .T
1364
1356
check_setitem_lengths (indexer , value , values )
1365
- values [indexer ] = value
1366
- return self
1357
+
1358
+ try :
1359
+ values [indexer ] = value
1360
+ except (ValueError , TypeError ) as err :
1361
+ _catch_deprecated_value_error (err )
1362
+
1363
+ if is_interval_dtype (self .dtype ):
1364
+ # see TestSetitemFloatIntervalWithIntIntervalValues
1365
+ nb = self .coerce_to_target_dtype (orig_value )
1366
+ return nb .setitem (orig_indexer , orig_value )
1367
+
1368
+ elif isinstance (self , NDArrayBackedExtensionBlock ):
1369
+ nb = self .coerce_to_target_dtype (orig_value )
1370
+ return nb .setitem (orig_indexer , orig_value )
1371
+
1372
+ else :
1373
+ raise
1374
+
1375
+ else :
1376
+ return self
1367
1377
1368
1378
def where (self , other , cond ) -> list [Block ]:
1369
1379
arr = self .values .T
@@ -1870,7 +1880,12 @@ def _catch_deprecated_value_error(err: Exception) -> None:
1870
1880
if isinstance (err , ValueError ):
1871
1881
# TODO(2.0): once DTA._validate_setitem_value deprecation
1872
1882
# is enforced, stop catching ValueError here altogether
1873
- if "Timezones don't match" not in str (err ):
1883
+ if isinstance (err , IncompatibleFrequency ):
1884
+ pass
1885
+ elif "'value.closed' is" in str (err ):
1886
+ # IntervalDtype mismatched 'closed'
1887
+ pass
1888
+ elif "Timezones don't match" not in str (err ):
1874
1889
raise
1875
1890
1876
1891
0 commit comments