|
41 | 41 | is_null_datelike_scalar)
|
42 | 42 | import pandas.types.concat as _concat
|
43 | 43 |
|
44 |
| -from pandas.types.generic import ABCSeries |
| 44 | +from pandas.types.generic import ABCSeries, ABCDatetimeIndex |
45 | 45 | from pandas.core.common import is_null_slice
|
46 | 46 | import pandas.core.algorithms as algos
|
47 | 47 |
|
@@ -379,7 +379,8 @@ def fillna(self, value, limit=None, inplace=False, downcast=None,
|
379 | 379 |
|
380 | 380 | # fillna, but if we cannot coerce, then try again as an ObjectBlock
|
381 | 381 | try:
|
382 |
| - values, _, value, _ = self._try_coerce_args(self.values, value) |
| 382 | + values, _, _, _ = self._try_coerce_args(self.values, value) |
| 383 | + # value may be converted to internal, thus drop |
383 | 384 | blocks = self.putmask(mask, value, inplace=inplace)
|
384 | 385 | blocks = [b.make_block(values=self._try_coerce_result(b.values))
|
385 | 386 | for b in blocks]
|
@@ -673,8 +674,43 @@ def setitem(self, indexer, value, mgr=None):
|
673 | 674 | if self.is_numeric:
|
674 | 675 | value = np.nan
|
675 | 676 |
|
676 |
| - # coerce args |
677 |
| - values, _, value, _ = self._try_coerce_args(self.values, value) |
| 677 | + # coerce if block dtype can store value |
| 678 | + values = self.values |
| 679 | + try: |
| 680 | + values, _, value, _ = self._try_coerce_args(values, value) |
| 681 | + # can keep its own dtype |
| 682 | + if hasattr(value, 'dtype') and is_dtype_equal(values.dtype, |
| 683 | + value.dtype): |
| 684 | + dtype = self.dtype |
| 685 | + else: |
| 686 | + dtype = 'infer' |
| 687 | + |
| 688 | + except (TypeError, ValueError): |
| 689 | + # current dtype cannot store value, coerce to common dtype |
| 690 | + find_dtype = False |
| 691 | + |
| 692 | + if hasattr(value, 'dtype'): |
| 693 | + dtype = value.dtype |
| 694 | + find_dtype = True |
| 695 | + |
| 696 | + elif is_scalar(value): |
| 697 | + if isnull(value): |
| 698 | + # NaN promotion is handled in latter path |
| 699 | + dtype = False |
| 700 | + else: |
| 701 | + dtype, _ = _infer_dtype_from_scalar(value, |
| 702 | + pandas_dtype=True) |
| 703 | + find_dtype = True |
| 704 | + else: |
| 705 | + dtype = 'infer' |
| 706 | + |
| 707 | + if find_dtype: |
| 708 | + dtype = _find_common_type([values.dtype, dtype]) |
| 709 | + if not is_dtype_equal(self.dtype, dtype): |
| 710 | + b = self.astype(dtype) |
| 711 | + return b.setitem(indexer, value, mgr=mgr) |
| 712 | + |
| 713 | + # value must be storeable at this moment |
678 | 714 | arr_value = np.array(value)
|
679 | 715 |
|
680 | 716 | # cast the values to a type that can hold nan (if necessary)
|
@@ -704,87 +740,52 @@ def setitem(self, indexer, value, mgr=None):
|
704 | 740 | raise ValueError("cannot set using a slice indexer with a "
|
705 | 741 | "different length than the value")
|
706 | 742 |
|
707 |
| - try: |
708 |
| - |
709 |
| - def _is_scalar_indexer(indexer): |
710 |
| - # return True if we are all scalar indexers |
711 |
| - |
712 |
| - if arr_value.ndim == 1: |
713 |
| - if not isinstance(indexer, tuple): |
714 |
| - indexer = tuple([indexer]) |
715 |
| - return all([is_scalar(idx) for idx in indexer]) |
716 |
| - return False |
717 |
| - |
718 |
| - def _is_empty_indexer(indexer): |
719 |
| - # return a boolean if we have an empty indexer |
| 743 | + def _is_scalar_indexer(indexer): |
| 744 | + # return True if we are all scalar indexers |
720 | 745 |
|
721 |
| - if arr_value.ndim == 1: |
722 |
| - if not isinstance(indexer, tuple): |
723 |
| - indexer = tuple([indexer]) |
724 |
| - return any(isinstance(idx, np.ndarray) and len(idx) == 0 |
725 |
| - for idx in indexer) |
726 |
| - return False |
727 |
| - |
728 |
| - # empty indexers |
729 |
| - # 8669 (empty) |
730 |
| - if _is_empty_indexer(indexer): |
731 |
| - pass |
732 |
| - |
733 |
| - # setting a single element for each dim and with a rhs that could |
734 |
| - # be say a list |
735 |
| - # GH 6043 |
736 |
| - elif _is_scalar_indexer(indexer): |
737 |
| - values[indexer] = value |
738 |
| - |
739 |
| - # if we are an exact match (ex-broadcasting), |
740 |
| - # then use the resultant dtype |
741 |
| - elif (len(arr_value.shape) and |
742 |
| - arr_value.shape[0] == values.shape[0] and |
743 |
| - np.prod(arr_value.shape) == np.prod(values.shape)): |
744 |
| - values[indexer] = value |
745 |
| - values = values.astype(arr_value.dtype) |
746 |
| - |
747 |
| - # set |
748 |
| - else: |
749 |
| - values[indexer] = value |
750 |
| - |
751 |
| - # coerce and try to infer the dtypes of the result |
752 |
| - if hasattr(value, 'dtype') and is_dtype_equal(values.dtype, |
753 |
| - value.dtype): |
754 |
| - dtype = value.dtype |
755 |
| - elif is_scalar(value): |
756 |
| - dtype, _ = _infer_dtype_from_scalar(value) |
757 |
| - else: |
758 |
| - dtype = 'infer' |
759 |
| - values = self._try_coerce_and_cast_result(values, dtype) |
760 |
| - block = self.make_block(transf(values), fastpath=True) |
761 |
| - |
762 |
| - # may have to soft convert_objects here |
763 |
| - if block.is_object and not self.is_object: |
764 |
| - block = block.convert(numeric=False) |
765 |
| - |
766 |
| - return block |
767 |
| - except ValueError: |
768 |
| - raise |
769 |
| - except TypeError: |
| 746 | + if arr_value.ndim == 1: |
| 747 | + if not isinstance(indexer, tuple): |
| 748 | + indexer = tuple([indexer]) |
| 749 | + return all([is_scalar(idx) for idx in indexer]) |
| 750 | + return False |
770 | 751 |
|
771 |
| - # cast to the passed dtype if possible |
772 |
| - # otherwise raise the original error |
773 |
| - try: |
774 |
| - # e.g. we are uint32 and our value is uint64 |
775 |
| - # this is for compat with older numpies |
776 |
| - block = self.make_block(transf(values.astype(value.dtype))) |
777 |
| - return block.setitem(indexer=indexer, value=value, mgr=mgr) |
| 752 | + def _is_empty_indexer(indexer): |
| 753 | + # return a boolean if we have an empty indexer |
778 | 754 |
|
779 |
| - except: |
780 |
| - pass |
781 |
| - |
782 |
| - raise |
| 755 | + if arr_value.ndim == 1: |
| 756 | + if not isinstance(indexer, tuple): |
| 757 | + indexer = tuple([indexer]) |
| 758 | + return any(isinstance(idx, np.ndarray) and len(idx) == 0 |
| 759 | + for idx in indexer) |
| 760 | + return False |
783 | 761 |
|
784 |
| - except Exception: |
| 762 | + # empty indexers |
| 763 | + # 8669 (empty) |
| 764 | + if _is_empty_indexer(indexer): |
785 | 765 | pass
|
786 | 766 |
|
787 |
| - return [self] |
| 767 | + # setting a single element for each dim and with a rhs that could |
| 768 | + # be say a list |
| 769 | + # GH 6043 |
| 770 | + elif _is_scalar_indexer(indexer): |
| 771 | + values[indexer] = value |
| 772 | + |
| 773 | + # if we are an exact match (ex-broadcasting), |
| 774 | + # then use the resultant dtype |
| 775 | + elif (len(arr_value.shape) and |
| 776 | + arr_value.shape[0] == values.shape[0] and |
| 777 | + np.prod(arr_value.shape) == np.prod(values.shape)): |
| 778 | + values[indexer] = value |
| 779 | + values = values.astype(arr_value.dtype) |
| 780 | + |
| 781 | + # set |
| 782 | + else: |
| 783 | + values[indexer] = value |
| 784 | + |
| 785 | + # coerce and try to infer the dtypes of the result |
| 786 | + values = self._try_coerce_and_cast_result(values, dtype) |
| 787 | + block = self.make_block(transf(values), fastpath=True) |
| 788 | + return block |
788 | 789 |
|
789 | 790 | def putmask(self, mask, new, align=True, inplace=False, axis=0,
|
790 | 791 | transpose=False, mgr=None):
|
@@ -1255,6 +1256,7 @@ def func(cond, values, other):
|
1255 | 1256 |
|
1256 | 1257 | values, values_mask, other, other_mask = self._try_coerce_args(
|
1257 | 1258 | values, other)
|
| 1259 | + |
1258 | 1260 | try:
|
1259 | 1261 | return self._try_coerce_result(expressions.where(
|
1260 | 1262 | cond, values, other, raise_on_error=True))
|
@@ -1534,6 +1536,7 @@ def putmask(self, mask, new, align=True, inplace=False, axis=0,
|
1534 | 1536 | new = new[mask]
|
1535 | 1537 |
|
1536 | 1538 | mask = _safe_reshape(mask, new_values.shape)
|
| 1539 | + |
1537 | 1540 | new_values[mask] = new
|
1538 | 1541 | new_values = self._try_coerce_result(new_values)
|
1539 | 1542 | return [self.make_block(values=new_values)]
|
@@ -1703,7 +1706,7 @@ def fillna(self, value, **kwargs):
|
1703 | 1706 |
|
1704 | 1707 | # allow filling with integers to be
|
1705 | 1708 | # interpreted as seconds
|
1706 |
| - if not isinstance(value, np.timedelta64) and is_integer(value): |
| 1709 | + if not isinstance(value, np.timedelta64): |
1707 | 1710 | value = Timedelta(value, unit='s')
|
1708 | 1711 | return super(TimeDeltaBlock, self).fillna(value, **kwargs)
|
1709 | 1712 |
|
@@ -1937,6 +1940,15 @@ def _maybe_downcast(self, blocks, downcast=None):
|
1937 | 1940 | def _can_hold_element(self, element):
|
1938 | 1941 | return True
|
1939 | 1942 |
|
| 1943 | + def _try_coerce_args(self, values, other): |
| 1944 | + """ provide coercion to our input arguments """ |
| 1945 | + |
| 1946 | + if isinstance(other, ABCDatetimeIndex): |
| 1947 | + # to store DatetimeTZBlock as object |
| 1948 | + other = other.asobject.values |
| 1949 | + |
| 1950 | + return values, False, other, False |
| 1951 | + |
1940 | 1952 | def _try_cast(self, element):
|
1941 | 1953 | return element
|
1942 | 1954 |
|
@@ -2276,8 +2288,6 @@ def _try_coerce_args(self, values, other):
|
2276 | 2288 | "naive Block")
|
2277 | 2289 | other_mask = isnull(other)
|
2278 | 2290 | other = other.asm8.view('i8')
|
2279 |
| - elif hasattr(other, 'dtype') and is_integer_dtype(other): |
2280 |
| - other = other.view('i8') |
2281 | 2291 | else:
|
2282 | 2292 | try:
|
2283 | 2293 | other = np.asarray(other)
|
@@ -2453,6 +2463,8 @@ def _try_coerce_args(self, values, other):
|
2453 | 2463 | raise ValueError("incompatible or non tz-aware value")
|
2454 | 2464 | other_mask = isnull(other)
|
2455 | 2465 | other = other.value
|
| 2466 | + else: |
| 2467 | + raise TypeError |
2456 | 2468 |
|
2457 | 2469 | return values, values_mask, other, other_mask
|
2458 | 2470 |
|
|
0 commit comments