8
8
from pandas ._libs import NaT , NaTType , Timestamp , algos , iNaT , lib
9
9
from pandas ._libs .tslibs .c_timestamp import integer_op_not_supported
10
10
from pandas ._libs .tslibs .period import DIFFERENT_FREQ , IncompatibleFrequency , Period
11
- from pandas ._libs .tslibs .timedeltas import Timedelta , delta_to_nanoseconds
11
+ from pandas ._libs .tslibs .timedeltas import delta_to_nanoseconds
12
12
from pandas ._libs .tslibs .timestamps import RoundTo , round_nsint64
13
13
from pandas ._typing import DatetimeLikeScalar
14
14
from pandas .compat import set_function_name
52
52
from pandas .tseries import frequencies
53
53
from pandas .tseries .offsets import DateOffset , Tick
54
54
55
+ DTScalarOrNaT = Union [DatetimeLikeScalar , NaTType ]
56
+
55
57
56
58
def _datetimelike_array_cmp (cls , op ):
57
59
"""
@@ -122,12 +124,7 @@ def wrapper(self, other):
122
124
result = ops .comp_method_OBJECT_ARRAY (op , self .astype (object ), other )
123
125
return result
124
126
125
- if isinstance (other , self ._scalar_type ) or other is NaT :
126
- other_i8 = self ._unbox_scalar (other )
127
- else :
128
- # Then type(other) == type(self)
129
- other_i8 = other .asi8
130
-
127
+ other_i8 = self ._unbox (other )
131
128
result = op (self .asi8 , other_i8 )
132
129
133
130
o_mask = isna (other )
@@ -157,9 +154,7 @@ def _scalar_type(self) -> Type[DatetimeLikeScalar]:
157
154
"""
158
155
raise AbstractMethodError (self )
159
156
160
- def _scalar_from_string (
161
- self , value : str
162
- ) -> Union [Period , Timestamp , Timedelta , NaTType ]:
157
+ def _scalar_from_string (self , value : str ) -> DTScalarOrNaT :
163
158
"""
164
159
Construct a scalar type from a string.
165
160
@@ -179,13 +174,14 @@ def _scalar_from_string(
179
174
"""
180
175
raise AbstractMethodError (self )
181
176
182
- def _unbox_scalar (self , value : Union [ Period , Timestamp , Timedelta , NaTType ] ) -> int :
177
+ def _unbox_scalar (self , value : DTScalarOrNaT ) -> int :
183
178
"""
184
179
Unbox the integer value of a scalar `value`.
185
180
186
181
Parameters
187
182
----------
188
- value : Union[Period, Timestamp, Timedelta]
183
+ value : Period, Timestamp, Timedelta, or NaT
184
+ Depending on subclass.
189
185
190
186
Returns
191
187
-------
@@ -199,7 +195,7 @@ def _unbox_scalar(self, value: Union[Period, Timestamp, Timedelta, NaTType]) ->
199
195
raise AbstractMethodError (self )
200
196
201
197
def _check_compatible_with (
202
- self , other : Union [ Period , Timestamp , Timedelta , NaTType ] , setitem : bool = False
198
+ self , other : DTScalarOrNaT , setitem : bool = False
203
199
) -> None :
204
200
"""
205
201
Verify that `self` and `other` are compatible.
@@ -727,17 +723,16 @@ def _validate_fill_value(self, fill_value):
727
723
ValueError
728
724
"""
729
725
if is_valid_nat_for_dtype (fill_value , self .dtype ):
730
- fill_value = iNaT
726
+ fill_value = NaT
731
727
elif isinstance (fill_value , self ._recognized_scalars ):
732
- self ._check_compatible_with (fill_value )
733
728
fill_value = self ._scalar_type (fill_value )
734
- fill_value = self ._unbox_scalar (fill_value )
735
729
else :
736
730
raise ValueError (
737
731
f"'fill_value' should be a { self ._scalar_type } . "
738
732
f"Got '{ str (fill_value )} '."
739
733
)
740
- return fill_value
734
+
735
+ return self ._unbox (fill_value )
741
736
742
737
def _validate_shift_value (self , fill_value ):
743
738
# TODO(2.0): once this deprecation is enforced, use _validate_fill_value
@@ -764,8 +759,7 @@ def _validate_shift_value(self, fill_value):
764
759
)
765
760
fill_value = new_fill
766
761
767
- fill_value = self ._unbox_scalar (fill_value )
768
- return fill_value
762
+ return self ._unbox (fill_value )
769
763
770
764
def _validate_searchsorted_value (self , value ):
771
765
if isinstance (value , str ):
@@ -797,13 +791,7 @@ def _validate_searchsorted_value(self, value):
797
791
else :
798
792
raise TypeError (f"Unexpected type for 'value': { type (value )} " )
799
793
800
- if isinstance (value , type (self )):
801
- self ._check_compatible_with (value )
802
- value = value .asi8
803
- else :
804
- value = self ._unbox_scalar (value )
805
-
806
- return value
794
+ return self ._unbox (value )
807
795
808
796
def _validate_setitem_value (self , value ):
809
797
@@ -836,19 +824,11 @@ def _validate_setitem_value(self, value):
836
824
raise TypeError (msg )
837
825
838
826
self ._check_compatible_with (value , setitem = True )
839
- if isinstance (value , type (self )):
840
- value = value .asi8
841
- else :
842
- value = self ._unbox_scalar (value )
843
-
844
- return value
827
+ return self ._unbox (value )
845
828
846
829
def _validate_insert_value (self , value ):
847
830
if isinstance (value , self ._recognized_scalars ):
848
831
value = self ._scalar_type (value )
849
- self ._check_compatible_with (value , setitem = True )
850
- # TODO: if we dont have compat, should we raise or astype(object)?
851
- # PeriodIndex does astype(object)
852
832
elif is_valid_nat_for_dtype (value , self .dtype ):
853
833
# GH#18295
854
834
value = NaT
@@ -857,14 +837,16 @@ def _validate_insert_value(self, value):
857
837
f"cannot insert { type (self ).__name__ } with incompatible label"
858
838
)
859
839
840
+ self ._check_compatible_with (value , setitem = True )
841
+ # TODO: if we dont have compat, should we raise or astype(object)?
842
+ # PeriodIndex does astype(object)
860
843
return value
861
844
862
845
def _validate_where_value (self , other ):
863
846
if is_valid_nat_for_dtype (other , self .dtype ):
864
847
other = NaT
865
848
elif isinstance (other , self ._recognized_scalars ):
866
849
other = self ._scalar_type (other )
867
- self ._check_compatible_with (other , setitem = True )
868
850
elif not is_list_like (other ):
869
851
raise TypeError (f"Where requires matching dtype, not { type (other )} " )
870
852
@@ -881,13 +863,20 @@ def _validate_where_value(self, other):
881
863
882
864
if not type (self )._is_recognized_dtype (other .dtype ):
883
865
raise TypeError (f"Where requires matching dtype, not { other .dtype } " )
884
- self ._check_compatible_with (other , setitem = True )
885
866
867
+ self ._check_compatible_with (other , setitem = True )
868
+ return self ._unbox (other )
869
+
870
+ def _unbox (self , other ) -> Union [np .int64 , np .ndarray ]:
871
+ """
872
+ Unbox either a scalar with _unbox_scalar or an instance of our own type.
873
+ """
886
874
if lib .is_scalar (other ):
887
875
other = self ._unbox_scalar (other )
888
876
else :
877
+ # same type as self
878
+ self ._check_compatible_with (other )
889
879
other = other .view ("i8" )
890
-
891
880
return other
892
881
893
882
# ------------------------------------------------------------------
0 commit comments