2222 writers ,
2323)
2424from pandas ._libs .internals import BlockPlacement
25+ from pandas ._libs .tslibs import IncompatibleFrequency
2526from pandas ._typing import (
2627 ArrayLike ,
2728 DtypeObj ,
105106 ensure_wrapped_if_datetimelike ,
106107 extract_array ,
107108)
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
113110import pandas .core .missing as missing
114111
115112if TYPE_CHECKING :
@@ -919,32 +916,29 @@ def setitem(self, indexer, value):
919916
920917 value = self ._standardize_fill_value (value )
921918
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
928919 values = cast (np .ndarray , self .values )
929920 if self .ndim == 2 :
930921 values = values .T
931922
932923 # length checking
933924 check_setitem_lengths (indexer , value , values )
934925
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 )
944933 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
948942 return self
949943
950944 def putmask (self , mask , new ) -> list [Block ]:
@@ -1348,10 +1342,8 @@ def setitem(self, indexer, value):
13481342 `indexer` is a direct slice/positional indexer. `value` must
13491343 be a compatible shape.
13501344 """
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
13551347
13561348 indexer = self ._unwrap_setitem_indexer (indexer )
13571349 value = self ._maybe_squeeze_arg (value )
@@ -1362,8 +1354,26 @@ def setitem(self, indexer, value):
13621354 # unconditionally
13631355 values = values .T
13641356 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
13671377
13681378 def where (self , other , cond ) -> list [Block ]:
13691379 arr = self .values .T
@@ -1870,7 +1880,12 @@ def _catch_deprecated_value_error(err: Exception) -> None:
18701880 if isinstance (err , ValueError ):
18711881 # TODO(2.0): once DTA._validate_setitem_value deprecation
18721882 # 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 ):
18741889 raise
18751890
18761891
0 commit comments