@@ -388,7 +388,8 @@ def fillna(self, value, limit=None, inplace=False, downcast=None,
388
388
389
389
# fillna, but if we cannot coerce, then try again as an ObjectBlock
390
390
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
392
393
blocks = self .putmask (mask , value , inplace = inplace )
393
394
blocks = [b .make_block (values = self ._try_coerce_result (b .values ))
394
395
for b in blocks ]
@@ -682,8 +683,43 @@ def setitem(self, indexer, value, mgr=None):
682
683
if self .is_numeric :
683
684
value = np .nan
684
685
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
687
723
arr_value = np .array (value )
688
724
689
725
# cast the values to a type that can hold nan (if necessary)
@@ -713,19 +749,8 @@ def setitem(self, indexer, value, mgr=None):
713
749
raise ValueError ("cannot set using a slice indexer with a "
714
750
"different length than the value" )
715
751
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
729
754
730
755
if arr_value .ndim == 1 :
731
756
if not isinstance (indexer , tuple ):
@@ -777,23 +802,43 @@ def _is_empty_indexer(indexer):
777
802
raise
778
803
except TypeError :
779
804
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
787
807
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
792
814
793
- except Exception :
815
+ # empty indexers
816
+ # 8669 (empty)
817
+ if _is_empty_indexer (indexer ):
794
818
pass
795
819
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
797
842
798
843
def putmask (self , mask , new , align = True , inplace = False , axis = 0 ,
799
844
transpose = False , mgr = None ):
@@ -1264,6 +1309,7 @@ def func(cond, values, other):
1264
1309
1265
1310
values , values_mask , other , other_mask = self ._try_coerce_args (
1266
1311
values , other )
1312
+
1267
1313
try :
1268
1314
return self ._try_coerce_result (expressions .where (
1269
1315
cond , values , other , raise_on_error = True ))
@@ -1543,6 +1589,7 @@ def putmask(self, mask, new, align=True, inplace=False, axis=0,
1543
1589
new = new [mask ]
1544
1590
1545
1591
mask = _safe_reshape (mask , new_values .shape )
1592
+
1546
1593
new_values [mask ] = new
1547
1594
new_values = self ._try_coerce_result (new_values )
1548
1595
return [self .make_block (values = new_values )]
@@ -1712,7 +1759,7 @@ def fillna(self, value, **kwargs):
1712
1759
1713
1760
# allow filling with integers to be
1714
1761
# interpreted as seconds
1715
- if not isinstance (value , np .timedelta64 ) and is_integer ( value ) :
1762
+ if not isinstance (value , np .timedelta64 ):
1716
1763
value = Timedelta (value , unit = 's' )
1717
1764
return super (TimeDeltaBlock , self ).fillna (value , ** kwargs )
1718
1765
@@ -1949,6 +1996,15 @@ def _maybe_downcast(self, blocks, downcast=None):
1949
1996
def _can_hold_element (self , element ):
1950
1997
return True
1951
1998
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
+
1952
2008
def _try_cast (self , element ):
1953
2009
return element
1954
2010
@@ -2288,8 +2344,6 @@ def _try_coerce_args(self, values, other):
2288
2344
"naive Block" )
2289
2345
other_mask = isnull (other )
2290
2346
other = other .asm8 .view ('i8' )
2291
- elif hasattr (other , 'dtype' ) and is_integer_dtype (other ):
2292
- other = other .view ('i8' )
2293
2347
else :
2294
2348
try :
2295
2349
other = np .asarray (other )
@@ -2466,6 +2520,8 @@ def _try_coerce_args(self, values, other):
2466
2520
raise ValueError ("incompatible or non tz-aware value" )
2467
2521
other_mask = isnull (other )
2468
2522
other = other .value
2523
+ else :
2524
+ raise TypeError
2469
2525
2470
2526
return values , values_mask , other , other_mask
2471
2527
0 commit comments