@@ -741,6 +741,7 @@ def na_op(x, y):
741741 if is_categorical_dtype (x ):
742742 return op (x , y )
743743 elif is_categorical_dtype (y ) and not is_scalar (y ):
744+ # the `not is_scalar(y)` check avoids catching string "category"
744745 return op (y , x )
745746
746747 elif is_object_dtype (x .dtype ):
@@ -750,7 +751,6 @@ def na_op(x, y):
750751 raise TypeError ("invalid type comparison" )
751752
752753 else :
753-
754754 # we want to compare like types
755755 # we only want to convert to integer like if
756756 # we are not NotImplemented, otherwise
@@ -759,23 +759,18 @@ def na_op(x, y):
759759
760760 # we have a datetime/timedelta and may need to convert
761761 mask = None
762- if (needs_i8_conversion (x ) or
763- (not is_scalar (y ) and needs_i8_conversion (y ))):
764-
765- if is_scalar (y ):
766- mask = isna (x )
767- y = libindex .convert_scalar (x , com ._values_from_object (y ))
768- else :
769- mask = isna (x ) | isna (y )
770- y = y .view ('i8' )
762+ if not is_scalar (y ) and needs_i8_conversion (y ):
763+ mask = isna (x ) | isna (y )
764+ y = y .view ('i8' )
771765 x = x .view ('i8' )
772766
773- try :
767+ method = getattr (x , name , None )
768+ if method is not None :
774769 with np .errstate (all = 'ignore' ):
775770 result = getattr (x , name )(y )
776771 if result is NotImplemented :
777772 raise TypeError ("invalid type comparison" )
778- except AttributeError :
773+ else :
779774 result = op (x , y )
780775
781776 if mask is not None and mask .any ():
@@ -788,17 +783,36 @@ def wrapper(self, other, axis=None):
788783 if axis is not None :
789784 self ._get_axis_number (axis )
790785
786+ res_name = _get_series_op_result_name (self , other )
787+
791788 if isinstance (other , ABCDataFrame ): # pragma: no cover
792789 # Defer to DataFrame implementation; fail early
793790 return NotImplemented
794791
792+ elif isinstance (other , ABCSeries ) and not self ._indexed_same (other ):
793+ raise ValueError ('Can only compare identically-labeled Series '
794+ 'objects' )
795+
796+ elif is_datetime64_dtype (self ) or is_datetime64tz_dtype (self ):
797+ res_values = dispatch_to_index_op (op , self , other ,
798+ pd .DatetimeIndex )
799+ return _construct_result (self , res_values ,
800+ index = self .index , name = res_name ,
801+ dtype = res_values .dtype )
802+
803+ elif is_timedelta64_dtype (self ):
804+ res_values = dispatch_to_index_op (op , self , other ,
805+ pd .TimedeltaIndex )
806+ return _construct_result (self , res_values ,
807+ index = self .index , name = res_name ,
808+ dtype = res_values .dtype )
809+
795810 elif isinstance (other , ABCSeries ):
811+ # By this point we know that self._indexed_same(other)
796812 name = com ._maybe_match_name (self , other )
797- if not self ._indexed_same (other ):
798- msg = 'Can only compare identically-labeled Series objects'
799- raise ValueError (msg )
800813 res_values = na_op (self .values , other .values )
801- return self ._constructor (res_values , index = self .index , name = name )
814+ return self ._constructor (res_values , index = self .index ,
815+ name = res_name )
802816
803817 elif isinstance (other , (np .ndarray , pd .Index )):
804818 # do not check length of zerodim array
@@ -836,7 +850,7 @@ def wrapper(self, other, axis=None):
836850 res = op (self .values , other )
837851 else :
838852 values = self .get_values ()
839- if isinstance (other , ( list , np . ndarray ) ):
853+ if isinstance (other , list ):
840854 other = np .asarray (other )
841855
842856 with np .errstate (all = 'ignore' ):
0 commit comments