|
17 | 17 |
|
18 | 18 | from pandas._libs import (
|
19 | 19 | Timestamp,
|
20 |
| - algos as libalgos, |
21 | 20 | internals as libinternals,
|
22 | 21 | lib,
|
23 | 22 | writers,
|
@@ -448,36 +447,42 @@ def _split_op_result(self, result: ArrayLike) -> list[Block]:
|
448 | 447 | return [nb]
|
449 | 448 |
|
450 | 449 | def fillna(
|
451 |
| - self, value, limit=None, inplace: bool = False, downcast=None |
| 450 | + self, value, limit: int | None = None, inplace: bool = False, downcast=None |
452 | 451 | ) -> list[Block]:
|
453 | 452 | """
|
454 | 453 | fillna on the block with the value. If we fail, then convert to
|
455 | 454 | ObjectBlock and try again
|
456 | 455 | """
|
| 456 | + # Caller is responsible for validating limit; if int it is strictly positive |
457 | 457 | inplace = validate_bool_kwarg(inplace, "inplace")
|
458 | 458 |
|
459 |
| - mask = isna(self.values) |
460 |
| - mask, noop = validate_putmask(self.values, mask) |
461 |
| - |
462 |
| - if limit is not None: |
463 |
| - limit = libalgos.validate_limit(None, limit=limit) |
464 |
| - mask[mask.cumsum(self.ndim - 1) > limit] = False |
465 |
| - |
466 | 459 | if not self._can_hold_na:
|
| 460 | + # can short-circuit the isna call |
| 461 | + noop = True |
| 462 | + else: |
| 463 | + mask = isna(self.values) |
| 464 | + mask, noop = validate_putmask(self.values, mask) |
| 465 | + |
| 466 | + if noop: |
| 467 | + # we can't process the value, but nothing to do |
467 | 468 | if inplace:
|
| 469 | + # Arbitrarily imposing the convention that we ignore downcast |
| 470 | + # on no-op when inplace=True |
468 | 471 | return [self]
|
469 | 472 | else:
|
470 |
| - return [self.copy()] |
| 473 | + # GH#45423 consistent downcasting on no-ops. |
| 474 | + nb = self.copy() |
| 475 | + nbs = nb._maybe_downcast([nb], downcast=downcast) |
| 476 | + return nbs |
| 477 | + |
| 478 | + if limit is not None: |
| 479 | + mask[mask.cumsum(self.ndim - 1) > limit] = False |
471 | 480 |
|
472 | 481 | if self._can_hold_element(value):
|
473 | 482 | nb = self if inplace else self.copy()
|
474 | 483 | putmask_inplace(nb.values, mask, value)
|
475 | 484 | return nb._maybe_downcast([nb], downcast)
|
476 | 485 |
|
477 |
| - if noop: |
478 |
| - # we can't process the value, but nothing to do |
479 |
| - return [self] if inplace else [self.copy()] |
480 |
| - |
481 | 486 | elif self.ndim == 1 or self.shape[0] == 1:
|
482 | 487 | blk = self.coerce_to_target_dtype(value)
|
483 | 488 | # bc we have already cast, inplace=True may avoid an extra copy
|
@@ -1449,8 +1454,9 @@ def putmask(self, mask, new) -> list[Block]:
|
1449 | 1454 | return [self]
|
1450 | 1455 |
|
1451 | 1456 | def fillna(
|
1452 |
| - self, value, limit=None, inplace: bool = False, downcast=None |
| 1457 | + self, value, limit: int | None = None, inplace: bool = False, downcast=None |
1453 | 1458 | ) -> list[Block]:
|
| 1459 | + # Caller is responsible for validating limit; if int it is strictly positive |
1454 | 1460 |
|
1455 | 1461 | try:
|
1456 | 1462 | new_values = self.values.fillna(value=value, limit=limit)
|
|
0 commit comments