3939 ABCSeries ,
4040 ABCDataFrame ,
4141 ABCIndex ,
42- ABCPeriodIndex ,
43- ABCSparseSeries )
42+ ABCSparseSeries , ABCSparseArray )
4443
4544
4645def _gen_eval_kwargs (name ):
@@ -445,17 +444,22 @@ def names(x):
445444 return new_methods
446445
447446
448- def add_methods (cls , new_methods , force ):
447+ def add_methods (cls , new_methods ):
449448 for name , method in new_methods .items ():
449+ # For most methods, if we find that the class already has a method
450+ # of the same name, it is OK to over-write it. The exception is
451+ # inplace methods (__iadd__, __isub__, ...) for SparseArray, which
452+ # retain the np.ndarray versions.
453+ force = not (issubclass (cls , ABCSparseArray ) and
454+ name .startswith ('__i' ))
450455 if force or name not in cls .__dict__ :
451456 bind_method (cls , name , method )
452457
453458
454459# ----------------------------------------------------------------------
455460# Arithmetic
456461def add_special_arithmetic_methods (cls , arith_method = None ,
457- comp_method = None , bool_method = None ,
458- force = False ):
462+ comp_method = None , bool_method = None ):
459463 """
460464 Adds the full suite of special arithmetic methods (``__add__``,
461465 ``__sub__``, etc.) to the class.
@@ -469,9 +473,6 @@ def add_special_arithmetic_methods(cls, arith_method=None,
469473 factory for rich comparison - signature: f(op, name, str_rep)
470474 bool_method : function (optional)
471475 factory for boolean methods - signature: f(op, name, str_rep)
472- force : bool, default False
473- if False, checks whether function is defined **on ``cls.__dict__``**
474- before defining if True, always defines functions on class base
475476 """
476477 new_methods = _create_methods (cls , arith_method , comp_method , bool_method ,
477478 special = True )
@@ -512,12 +513,11 @@ def f(self, other):
512513 __ior__ = _wrap_inplace_method (new_methods ["__or__" ]),
513514 __ixor__ = _wrap_inplace_method (new_methods ["__xor__" ])))
514515
515- add_methods (cls , new_methods = new_methods , force = force )
516+ add_methods (cls , new_methods = new_methods )
516517
517518
518519def add_flex_arithmetic_methods (cls , flex_arith_method ,
519- flex_comp_method = None , flex_bool_method = None ,
520- force = False ):
520+ flex_comp_method = None , flex_bool_method = None ):
521521 """
522522 Adds the full suite of flex arithmetic methods (``pow``, ``mul``, ``add``)
523523 to the class.
@@ -529,9 +529,6 @@ def add_flex_arithmetic_methods(cls, flex_arith_method,
529529 f(op, name, str_rep)
530530 flex_comp_method : function, optional,
531531 factory for rich comparison - signature: f(op, name, str_rep)
532- force : bool, default False
533- if False, checks whether function is defined **on ``cls.__dict__``**
534- before defining if True, always defines functions on class base
535532 """
536533 new_methods = _create_methods (cls , flex_arith_method ,
537534 flex_comp_method , flex_bool_method ,
@@ -544,7 +541,7 @@ def add_flex_arithmetic_methods(cls, flex_arith_method,
544541 if k in new_methods :
545542 new_methods .pop (k )
546543
547- add_methods (cls , new_methods = new_methods , force = force )
544+ add_methods (cls , new_methods = new_methods )
548545
549546
550547# -----------------------------------------------------------------------------
@@ -614,14 +611,11 @@ def na_op(x, y):
614611 result = np .empty (x .size , dtype = dtype )
615612 mask = notna (x ) & notna (y )
616613 result [mask ] = op (x [mask ], com ._values_from_object (y [mask ]))
617- elif isinstance (x , np .ndarray ):
614+ else :
615+ assert isinstance (x , np .ndarray )
618616 result = np .empty (len (x ), dtype = x .dtype )
619617 mask = notna (x )
620618 result [mask ] = op (x [mask ], y )
621- else :
622- raise TypeError ("{typ} cannot perform the operation "
623- "{op}" .format (typ = type (x ).__name__ ,
624- op = str_rep ))
625619
626620 result , changed = maybe_upcast_putmask (result , ~ mask , np .nan )
627621
@@ -658,6 +652,10 @@ def wrapper(left, right, name=name, na_op=na_op):
658652 index = left .index , name = res_name ,
659653 dtype = result .dtype )
660654
655+ elif is_categorical_dtype (left ):
656+ raise TypeError ("{typ} cannot perform the operation "
657+ "{op}" .format (typ = type (left ).__name__ , op = str_rep ))
658+
661659 lvalues = left .values
662660 rvalues = right
663661 if isinstance (rvalues , ABCSeries ):
@@ -745,24 +743,19 @@ def na_op(x, y):
745743 elif is_categorical_dtype (y ) and not is_scalar (y ):
746744 return op (y , x )
747745
748- if is_object_dtype (x .dtype ):
746+ elif is_object_dtype (x .dtype ):
749747 result = _comp_method_OBJECT_ARRAY (op , x , y )
748+
749+ elif is_datetimelike_v_numeric (x , y ):
750+ raise TypeError ("invalid type comparison" )
751+
750752 else :
751753
752754 # we want to compare like types
753755 # we only want to convert to integer like if
754756 # we are not NotImplemented, otherwise
755757 # we would allow datetime64 (but viewed as i8) against
756758 # integer comparisons
757- if is_datetimelike_v_numeric (x , y ):
758- raise TypeError ("invalid type comparison" )
759-
760- # numpy does not like comparisons vs None
761- if is_scalar (y ) and isna (y ):
762- if name == '__ne__' :
763- return np .ones (len (x ), dtype = bool )
764- else :
765- return np .zeros (len (x ), dtype = bool )
766759
767760 # we have a datetime/timedelta and may need to convert
768761 mask = None
@@ -795,39 +788,44 @@ def wrapper(self, other, axis=None):
795788 if axis is not None :
796789 self ._get_axis_number (axis )
797790
798- if isinstance (other , ABCSeries ):
791+ if isinstance (other , ABCDataFrame ): # pragma: no cover
792+ # Defer to DataFrame implementation; fail early
793+ return NotImplemented
794+
795+ elif isinstance (other , ABCSeries ):
799796 name = com ._maybe_match_name (self , other )
800797 if not self ._indexed_same (other ):
801798 msg = 'Can only compare identically-labeled Series objects'
802799 raise ValueError (msg )
803- return self ._constructor (na_op (self .values , other .values ),
804- index = self .index , name = name )
805- elif isinstance (other , ABCDataFrame ): # pragma: no cover
806- return NotImplemented
800+ res_values = na_op (self .values , other .values )
801+ return self ._constructor (res_values , index = self .index , name = name )
802+
807803 elif isinstance (other , (np .ndarray , pd .Index )):
808804 # do not check length of zerodim array
809805 # as it will broadcast
810806 if (not is_scalar (lib .item_from_zerodim (other )) and
811807 len (self ) != len (other )):
812808 raise ValueError ('Lengths must match to compare' )
813809
814- if isinstance (other , ABCPeriodIndex ):
815- # temp workaround until fixing GH 13637
816- # tested in test_nat_comparisons
817- # (pandas.tests.series.test_operators.TestSeriesOperators)
818- return self ._constructor (na_op (self .values ,
819- other .astype (object ).values ),
820- index = self .index )
821-
822- return self ._constructor (na_op (self .values , np .asarray (other )),
810+ res_values = na_op (self .values , np .asarray (other ))
811+ return self ._constructor (res_values ,
823812 index = self .index ).__finalize__ (self )
824813
825- elif isinstance (other , pd .Categorical ):
826- if not is_categorical_dtype (self ):
827- msg = ("Cannot compare a Categorical for op {op} with Series "
828- "of dtype {typ}.\n If you want to compare values, use "
829- "'series <op> np.asarray(other)'." )
830- raise TypeError (msg .format (op = op , typ = self .dtype ))
814+ elif (isinstance (other , pd .Categorical ) and
815+ not is_categorical_dtype (self )):
816+ raise TypeError ("Cannot compare a Categorical for op {op} with "
817+ "Series of dtype {typ}.\n If you want to compare "
818+ "values, use 'series <op> np.asarray(other)'."
819+ .format (op = op , typ = self .dtype ))
820+
821+ elif is_scalar (other ) and isna (other ):
822+ # numpy does not like comparisons vs None
823+ if op is operator .ne :
824+ res_values = np .ones (len (self ), dtype = bool )
825+ else :
826+ res_values = np .zeros (len (self ), dtype = bool )
827+ return self ._constructor (res_values , index = self .index ,
828+ name = self .name , dtype = 'bool' )
831829
832830 if is_categorical_dtype (self ):
833831 # cats are a special case as get_values() would return an ndarray,
@@ -877,11 +875,10 @@ def na_op(x, y):
877875 y = _ensure_object (y )
878876 result = lib .vec_binop (x , y , op )
879877 else :
878+ # let null fall thru
879+ if not isna (y ):
880+ y = bool (y )
880881 try :
881-
882- # let null fall thru
883- if not isna (y ):
884- y = bool (y )
885882 result = lib .scalar_binop (x , y , op )
886883 except :
887884 msg = ("cannot compare a dtyped [{dtype}] array "
@@ -899,26 +896,31 @@ def wrapper(self, other):
899896
900897 self , other = _align_method_SERIES (self , other , align_asobject = True )
901898
902- if isinstance (other , ABCSeries ):
899+ if isinstance (other , ABCDataFrame ):
900+ # Defer to DataFrame implementation; fail early
901+ return NotImplemented
902+
903+ elif isinstance (other , ABCSeries ):
903904 name = com ._maybe_match_name (self , other )
904905 is_other_int_dtype = is_integer_dtype (other .dtype )
905906 other = fill_int (other ) if is_other_int_dtype else fill_bool (other )
906907
907908 filler = (fill_int if is_self_int_dtype and is_other_int_dtype
908909 else fill_bool )
909- return filler (self ._constructor (na_op (self .values , other .values ),
910- index = self .index , name = name ))
911910
912- elif isinstance (other , ABCDataFrame ):
913- return NotImplemented
911+ res_values = na_op (self .values , other .values )
912+ unfilled = self ._constructor (res_values ,
913+ index = self .index , name = name )
914+ return filler (unfilled )
914915
915916 else :
916917 # scalars, list, tuple, np.array
917918 filler = (fill_int if is_self_int_dtype and
918919 is_integer_dtype (np .asarray (other )) else fill_bool )
919- return filler (self ._constructor (
920- na_op (self .values , other ),
921- index = self .index )).__finalize__ (self )
920+
921+ res_values = na_op (self .values , other )
922+ unfilled = self ._constructor (res_values , index = self .index )
923+ return filler (unfilled ).__finalize__ (self )
922924
923925 return wrapper
924926
@@ -1023,21 +1025,23 @@ def na_op(x, y):
10231025 mask = notna (xrav ) & notna (yrav )
10241026 xrav = xrav [mask ]
10251027
1026- # we may need to manually
1027- # broadcast a 1 element array
10281028 if yrav .shape != mask .shape :
1029- yrav = np .empty (mask .shape , dtype = yrav .dtype )
1030- yrav .fill (yrav .item ())
1029+ # FIXME: GH#5284, GH#5035, GH#19448
1030+ # Without specifically raising here we get mismatched
1031+ # errors in Py3 (TypeError) vs Py2 (ValueError)
1032+ raise ValueError ('Cannot broadcast operands together.' )
10311033
10321034 yrav = yrav [mask ]
1033- if np . prod ( xrav .shape ) and np . prod ( yrav . shape ) :
1035+ if xrav .size :
10341036 with np .errstate (all = 'ignore' ):
10351037 result [mask ] = op (xrav , yrav )
1036- elif hasattr (x , 'size' ):
1038+
1039+ elif isinstance (x , np .ndarray ):
1040+ # mask is only meaningful for x
10371041 result = np .empty (x .size , dtype = x .dtype )
10381042 mask = notna (xrav )
10391043 xrav = xrav [mask ]
1040- if np . prod ( xrav .shape ) :
1044+ if xrav .size :
10411045 with np .errstate (all = 'ignore' ):
10421046 result [mask ] = op (xrav , y )
10431047 else :
0 commit comments