@@ -355,8 +355,14 @@ def shape(self) -> Shape:
355
355
def dtype (self ) -> DtypeObj :
356
356
return self .values .dtype
357
357
358
- def iget (self , i ):
359
- return self .values [i ]
358
+ def iget (self , i : int | tuple [int , int ] | tuple [slice , int ]):
359
+ # In the case where we have a tuple[slice, int], the slice will always
360
+ # be slice(None)
361
+ # Note: only reached with self.ndim == 2
362
+ # Invalid index type "Union[int, Tuple[int, int], Tuple[slice, int]]"
363
+ # for "Union[ndarray[Any, Any], ExtensionArray]"; expected type
364
+ # "Union[int, integer[Any]]"
365
+ return self .values [i ] # type: ignore[index]
360
366
361
367
def set_inplace (self , locs , values ) -> None :
362
368
"""
@@ -1166,19 +1172,17 @@ def where(self, other, cond) -> list[Block]:
1166
1172
values = values .T
1167
1173
1168
1174
icond , noop = validate_putmask (values , ~ cond )
1175
+ if noop :
1176
+ # GH-39595: Always return a copy; short-circuit up/downcasting
1177
+ return self .copy ()
1169
1178
1170
1179
if other is lib .no_default :
1171
1180
other = self .fill_value
1172
1181
1173
1182
if is_valid_na_for_dtype (other , self .dtype ) and self .dtype != _dtype_obj :
1174
1183
other = self .fill_value
1175
1184
1176
- if noop :
1177
- # TODO: avoid the downcasting at the end in this case?
1178
- # GH-39595: Always return a copy
1179
- result = values .copy ()
1180
-
1181
- elif not self ._can_hold_element (other ):
1185
+ if not self ._can_hold_element (other ):
1182
1186
# we cannot coerce, return a compat dtype
1183
1187
block = self .coerce_to_target_dtype (other )
1184
1188
blocks = block .where (orig_other , cond )
@@ -1350,11 +1354,7 @@ def where(self, other, cond) -> list[Block]:
1350
1354
try :
1351
1355
res_values = arr ._where (cond , other ).T
1352
1356
except (ValueError , TypeError ) as err :
1353
- if isinstance (err , ValueError ):
1354
- # TODO(2.0): once DTA._validate_setitem_value deprecation
1355
- # is enforced, stop catching ValueError here altogether
1356
- if "Timezones don't match" not in str (err ):
1357
- raise
1357
+ _catch_deprecated_value_error (err )
1358
1358
1359
1359
if is_interval_dtype (self .dtype ):
1360
1360
# TestSetitemFloatIntervalWithIntIntervalValues
@@ -1397,10 +1397,7 @@ def putmask(self, mask, new) -> list[Block]:
1397
1397
# Caller is responsible for ensuring matching lengths
1398
1398
values ._putmask (mask , new )
1399
1399
except (TypeError , ValueError ) as err :
1400
- if isinstance (err , ValueError ) and "Timezones don't match" not in str (err ):
1401
- # TODO(2.0): remove catching ValueError at all since
1402
- # DTA raising here is deprecated
1403
- raise
1400
+ _catch_deprecated_value_error (err )
1404
1401
1405
1402
if is_interval_dtype (self .dtype ):
1406
1403
# Discussion about what we want to support in the general
@@ -1490,11 +1487,18 @@ def shape(self) -> Shape:
1490
1487
return (len (self .values ),)
1491
1488
return len (self ._mgr_locs ), len (self .values )
1492
1489
1493
- def iget (self , col ):
1490
+ def iget (self , i : int | tuple [int , int ] | tuple [slice , int ]):
1491
+ # In the case where we have a tuple[slice, int], the slice will always
1492
+ # be slice(None)
1493
+ # We _could_ make the annotation more specific, but mypy would
1494
+ # complain about override mismatch:
1495
+ # Literal[0] | tuple[Literal[0], int] | tuple[slice, int]
1494
1496
1495
- if self .ndim == 2 and isinstance (col , tuple ):
1497
+ # Note: only reached with self.ndim == 2
1498
+
1499
+ if isinstance (i , tuple ):
1496
1500
# TODO(EA2D): unnecessary with 2D EAs
1497
- col , loc = col
1501
+ col , loc = i
1498
1502
if not com .is_null_slice (col ) and col != 0 :
1499
1503
raise IndexError (f"{ self } only contains one item" )
1500
1504
elif isinstance (col , slice ):
@@ -1503,7 +1507,7 @@ def iget(self, col):
1503
1507
return self .values [[loc ]]
1504
1508
return self .values [loc ]
1505
1509
else :
1506
- if col != 0 :
1510
+ if i != 0 :
1507
1511
raise IndexError (f"{ self } only contains one item" )
1508
1512
return self .values
1509
1513
@@ -1829,6 +1833,18 @@ def fillna(
1829
1833
return [self .make_block_same_class (values = new_values )]
1830
1834
1831
1835
1836
+ def _catch_deprecated_value_error (err : Exception ) -> None :
1837
+ """
1838
+ We catch ValueError for now, but only a specific one raised by DatetimeArray
1839
+ which will no longer be raised in version.2.0.
1840
+ """
1841
+ if isinstance (err , ValueError ):
1842
+ # TODO(2.0): once DTA._validate_setitem_value deprecation
1843
+ # is enforced, stop catching ValueError here altogether
1844
+ if "Timezones don't match" not in str (err ):
1845
+ raise
1846
+
1847
+
1832
1848
class DatetimeLikeBlock (NDArrayBackedExtensionBlock ):
1833
1849
"""Block for datetime64[ns], timedelta64[ns]."""
1834
1850
0 commit comments