3
3
"""
4
4
from __future__ import annotations
5
5
6
- from functools import partial
6
+ from functools import (
7
+ partial ,
8
+ wraps ,
9
+ )
7
10
from typing import (
8
11
TYPE_CHECKING ,
9
12
Any ,
10
13
List ,
11
14
Optional ,
12
15
Set ,
13
16
Union ,
17
+ cast ,
14
18
)
15
19
16
20
import numpy as np
22
26
from pandas ._typing import (
23
27
ArrayLike ,
24
28
Axis ,
25
- DtypeObj ,
29
+ F ,
26
30
)
27
31
from pandas .compat ._optional import import_optional_dependency
28
32
29
33
from pandas .core .dtypes .cast import infer_dtype_from
30
34
from pandas .core .dtypes .common import (
31
- ensure_float64 ,
32
35
is_array_like ,
33
- is_integer_dtype ,
34
36
is_numeric_v_string_like ,
35
37
needs_i8_conversion ,
36
38
)
@@ -674,54 +676,53 @@ def interpolate_2d(
674
676
return result
675
677
676
678
677
- def _cast_values_for_fillna (values , dtype : DtypeObj , has_mask : bool ):
678
- """
679
- Cast values to a dtype that algos.pad and algos.backfill can handle.
680
- """
681
- # TODO: for int-dtypes we make a copy, but for everything else this
682
- # alters the values in-place. Is this intentional?
679
+ def _fillna_prep (values , mask = None ):
680
+ # boilerplate for _pad_1d, _backfill_1d, _pad_2d, _backfill_2d
683
681
684
- if needs_i8_conversion ( dtype ) :
685
- values = values . view ( np . int64 )
682
+ if mask is None :
683
+ mask = isna ( values )
686
684
687
- elif is_integer_dtype (values ) and not has_mask :
688
- # NB: this check needs to come after the datetime64 check above
689
- # has_mask check to avoid casting i8 values that have already
690
- # been cast from PeriodDtype
691
- values = ensure_float64 (values )
685
+ mask = mask .view (np .uint8 )
686
+ return mask
692
687
693
- return values
694
688
689
+ def _datetimelike_compat (func : F ) -> F :
690
+ """
691
+ Wrapper to handle datetime64 and timedelta64 dtypes.
692
+ """
695
693
696
- def _fillna_prep (values , mask = None ):
697
- # boilerplate for _pad_1d, _backfill_1d, _pad_2d, _backfill_2d
698
- dtype = values .dtype
694
+ @wraps (func )
695
+ def new_func (values , limit = None , mask = None ):
696
+ if needs_i8_conversion (values .dtype ):
697
+ if mask is None :
698
+ # This needs to occur before casting to int64
699
+ mask = isna (values )
699
700
700
- has_mask = mask is not None
701
- if not has_mask :
702
- # This needs to occur before datetime/timedeltas are cast to int64
703
- mask = isna (values )
701
+ result = func (values .view ("i8" ), limit = limit , mask = mask )
702
+ return result .view (values .dtype )
704
703
705
- values = _cast_values_for_fillna (values , dtype , has_mask )
704
+ return func (values , limit = limit , mask = mask )
706
705
707
- mask = mask .view (np .uint8 )
708
- return values , mask
706
+ return cast (F , new_func )
709
707
710
708
709
+ @_datetimelike_compat
711
710
def _pad_1d (values , limit = None , mask = None ):
712
- values , mask = _fillna_prep (values , mask )
711
+ mask = _fillna_prep (values , mask )
713
712
algos .pad_inplace (values , mask , limit = limit )
714
713
return values
715
714
716
715
716
+ @_datetimelike_compat
717
717
def _backfill_1d (values , limit = None , mask = None ):
718
- values , mask = _fillna_prep (values , mask )
718
+ mask = _fillna_prep (values , mask )
719
719
algos .backfill_inplace (values , mask , limit = limit )
720
720
return values
721
721
722
722
723
+ @_datetimelike_compat
723
724
def _pad_2d (values , limit = None , mask = None ):
724
- values , mask = _fillna_prep (values , mask )
725
+ mask = _fillna_prep (values , mask )
725
726
726
727
if np .all (values .shape ):
727
728
algos .pad_2d_inplace (values , mask , limit = limit )
@@ -731,8 +732,9 @@ def _pad_2d(values, limit=None, mask=None):
731
732
return values
732
733
733
734
735
+ @_datetimelike_compat
734
736
def _backfill_2d (values , limit = None , mask = None ):
735
- values , mask = _fillna_prep (values , mask )
737
+ mask = _fillna_prep (values , mask )
736
738
737
739
if np .all (values .shape ):
738
740
algos .backfill_2d_inplace (values , mask , limit = limit )
0 commit comments