@@ -388,7 +388,8 @@ def fillna(self, value, limit=None, inplace=False, downcast=None,
388388
389389 # fillna, but if we cannot coerce, then try again as an ObjectBlock
390390 try :
391- values , _ , value , _ = self ._try_coerce_args (self .values , value )
391+ values , _ , _ , _ = self ._try_coerce_args (self .values , value )
392+ # value may be converted to internal, thus drop
392393 blocks = self .putmask (mask , value , inplace = inplace )
393394 blocks = [b .make_block (values = self ._try_coerce_result (b .values ))
394395 for b in blocks ]
@@ -682,8 +683,43 @@ def setitem(self, indexer, value, mgr=None):
682683 if self .is_numeric :
683684 value = np .nan
684685
685- # coerce args
686- values , _ , value , _ = self ._try_coerce_args (self .values , value )
686+ # coerce if block dtype can store value
687+ values = self .values
688+ try :
689+ values , _ , value , _ = self ._try_coerce_args (values , value )
690+ # can keep its own dtype
691+ if hasattr (value , 'dtype' ) and is_dtype_equal (values .dtype ,
692+ value .dtype ):
693+ dtype = self .dtype
694+ else :
695+ dtype = 'infer'
696+
697+ except (TypeError , ValueError ):
698+ # current dtype cannot store value, coerce to common dtype
699+ find_dtype = False
700+
701+ if hasattr (value , 'dtype' ):
702+ dtype = value .dtype
703+ find_dtype = True
704+
705+ elif is_scalar (value ):
706+ if isnull (value ):
707+ # NaN promotion is handled in latter path
708+ dtype = False
709+ else :
710+ dtype , _ = _infer_dtype_from_scalar (value ,
711+ pandas_dtype = True )
712+ find_dtype = True
713+ else :
714+ dtype = 'infer'
715+
716+ if find_dtype :
717+ dtype = _find_common_type ([values .dtype , dtype ])
718+ if not is_dtype_equal (self .dtype , dtype ):
719+ b = self .astype (dtype )
720+ return b .setitem (indexer , value , mgr = mgr )
721+
722+ # value must be storeable at this moment
687723 arr_value = np .array (value )
688724
689725 # cast the values to a type that can hold nan (if necessary)
@@ -713,19 +749,8 @@ def setitem(self, indexer, value, mgr=None):
713749 raise ValueError ("cannot set using a slice indexer with a "
714750 "different length than the value" )
715751
716- try :
717-
718- def _is_scalar_indexer (indexer ):
719- # return True if we are all scalar indexers
720-
721- if arr_value .ndim == 1 :
722- if not isinstance (indexer , tuple ):
723- indexer = tuple ([indexer ])
724- return all ([is_scalar (idx ) for idx in indexer ])
725- return False
726-
727- def _is_empty_indexer (indexer ):
728- # return a boolean if we have an empty indexer
752+ def _is_scalar_indexer (indexer ):
753+ # return True if we are all scalar indexers
729754
730755 if arr_value .ndim == 1 :
731756 if not isinstance (indexer , tuple ):
@@ -777,23 +802,43 @@ def _is_empty_indexer(indexer):
777802 raise
778803 except TypeError :
779804
780- # cast to the passed dtype if possible
781- # otherwise raise the original error
782- try :
783- # e.g. we are uint32 and our value is uint64
784- # this is for compat with older numpies
785- block = self .make_block (transf (values .astype (value .dtype )))
786- return block .setitem (indexer = indexer , value = value , mgr = mgr )
805+ def _is_empty_indexer (indexer ):
806+ # return a boolean if we have an empty indexer
787807
788- except :
789- pass
790-
791- raise
808+ if arr_value .ndim == 1 :
809+ if not isinstance (indexer , tuple ):
810+ indexer = tuple ([indexer ])
811+ return any (isinstance (idx , np .ndarray ) and len (idx ) == 0
812+ for idx in indexer )
813+ return False
792814
793- except Exception :
815+ # empty indexers
816+ # 8669 (empty)
817+ if _is_empty_indexer (indexer ):
794818 pass
795819
796- return [self ]
820+ # setting a single element for each dim and with a rhs that could
821+ # be say a list
822+ # GH 6043
823+ elif _is_scalar_indexer (indexer ):
824+ values [indexer ] = value
825+
826+ # if we are an exact match (ex-broadcasting),
827+ # then use the resultant dtype
828+ elif (len (arr_value .shape ) and
829+ arr_value .shape [0 ] == values .shape [0 ] and
830+ np .prod (arr_value .shape ) == np .prod (values .shape )):
831+ values [indexer ] = value
832+ values = values .astype (arr_value .dtype )
833+
834+ # set
835+ else :
836+ values [indexer ] = value
837+
838+ # coerce and try to infer the dtypes of the result
839+ values = self ._try_coerce_and_cast_result (values , dtype )
840+ block = self .make_block (transf (values ), fastpath = True )
841+ return block
797842
798843 def putmask (self , mask , new , align = True , inplace = False , axis = 0 ,
799844 transpose = False , mgr = None ):
@@ -1264,6 +1309,7 @@ def func(cond, values, other):
12641309
12651310 values , values_mask , other , other_mask = self ._try_coerce_args (
12661311 values , other )
1312+
12671313 try :
12681314 return self ._try_coerce_result (expressions .where (
12691315 cond , values , other , raise_on_error = True ))
@@ -1543,6 +1589,7 @@ def putmask(self, mask, new, align=True, inplace=False, axis=0,
15431589 new = new [mask ]
15441590
15451591 mask = _safe_reshape (mask , new_values .shape )
1592+
15461593 new_values [mask ] = new
15471594 new_values = self ._try_coerce_result (new_values )
15481595 return [self .make_block (values = new_values )]
@@ -1712,7 +1759,7 @@ def fillna(self, value, **kwargs):
17121759
17131760 # allow filling with integers to be
17141761 # interpreted as seconds
1715- if not isinstance (value , np .timedelta64 ) and is_integer ( value ) :
1762+ if not isinstance (value , np .timedelta64 ):
17161763 value = Timedelta (value , unit = 's' )
17171764 return super (TimeDeltaBlock , self ).fillna (value , ** kwargs )
17181765
@@ -1949,6 +1996,15 @@ def _maybe_downcast(self, blocks, downcast=None):
19491996 def _can_hold_element (self , element ):
19501997 return True
19511998
1999+ def _try_coerce_args (self , values , other ):
2000+ """ provide coercion to our input arguments """
2001+
2002+ if isinstance (other , ABCDatetimeIndex ):
2003+ # to store DatetimeTZBlock as object
2004+ other = other .asobject .values
2005+
2006+ return values , False , other , False
2007+
19522008 def _try_cast (self , element ):
19532009 return element
19542010
@@ -2288,8 +2344,6 @@ def _try_coerce_args(self, values, other):
22882344 "naive Block" )
22892345 other_mask = isnull (other )
22902346 other = other .asm8 .view ('i8' )
2291- elif hasattr (other , 'dtype' ) and is_integer_dtype (other ):
2292- other = other .view ('i8' )
22932347 else :
22942348 try :
22952349 other = np .asarray (other )
@@ -2466,6 +2520,8 @@ def _try_coerce_args(self, values, other):
24662520 raise ValueError ("incompatible or non tz-aware value" )
24672521 other_mask = isnull (other )
24682522 other = other .value
2523+ else :
2524+ raise TypeError
24692525
24702526 return values , values_mask , other , other_mask
24712527
0 commit comments