|
42 | 42 | is_null_datelike_scalar)
|
43 | 43 | import pandas.types.concat as _concat
|
44 | 44 |
|
45 |
| -from pandas.types.generic import ABCSeries |
| 45 | +from pandas.types.generic import ABCSeries, ABCDatetimeIndex |
46 | 46 | from pandas.core.common import is_null_slice
|
47 | 47 | import pandas.core.algorithms as algos
|
48 | 48 |
|
@@ -378,7 +378,8 @@ def fillna(self, value, limit=None, inplace=False, downcast=None,
|
378 | 378 |
|
379 | 379 | # fillna, but if we cannot coerce, then try again as an ObjectBlock
|
380 | 380 | try:
|
381 |
| - values, _, value, _ = self._try_coerce_args(self.values, value) |
| 381 | + values, _, _, _ = self._try_coerce_args(self.values, value) |
| 382 | + # value may be converted to internal, thus drop |
382 | 383 | blocks = self.putmask(mask, value, inplace=inplace)
|
383 | 384 | blocks = [b.make_block(values=self._try_coerce_result(b.values))
|
384 | 385 | for b in blocks]
|
@@ -666,8 +667,43 @@ def setitem(self, indexer, value, mgr=None):
|
666 | 667 | if self.is_numeric:
|
667 | 668 | value = np.nan
|
668 | 669 |
|
669 |
| - # coerce args |
670 |
| - values, _, value, _ = self._try_coerce_args(self.values, value) |
| 670 | + # coerce if block dtype can store value |
| 671 | + values = self.values |
| 672 | + try: |
| 673 | + values, _, value, _ = self._try_coerce_args(values, value) |
| 674 | + # can keep its own dtype |
| 675 | + if hasattr(value, 'dtype') and is_dtype_equal(values.dtype, |
| 676 | + value.dtype): |
| 677 | + dtype = self.dtype |
| 678 | + else: |
| 679 | + dtype = 'infer' |
| 680 | + |
| 681 | + except (TypeError, ValueError): |
| 682 | + # current dtype cannot store value, coerce to common dtype |
| 683 | + find_dtype = False |
| 684 | + |
| 685 | + if hasattr(value, 'dtype'): |
| 686 | + dtype = value.dtype |
| 687 | + find_dtype = True |
| 688 | + |
| 689 | + elif is_scalar(value): |
| 690 | + if isnull(value): |
| 691 | + # NaN promotion is handled in latter path |
| 692 | + dtype = False |
| 693 | + else: |
| 694 | + dtype, _ = _infer_dtype_from_scalar(value, |
| 695 | + pandas_dtype=True) |
| 696 | + find_dtype = True |
| 697 | + else: |
| 698 | + dtype = 'infer' |
| 699 | + |
| 700 | + if find_dtype: |
| 701 | + dtype = _find_common_type([values.dtype, dtype]) |
| 702 | + if not is_dtype_equal(self.dtype, dtype): |
| 703 | + b = self.astype(dtype) |
| 704 | + return b.setitem(indexer, value, mgr=mgr) |
| 705 | + |
| 706 | + # value must be storeable at this moment |
671 | 707 | arr_value = np.array(value)
|
672 | 708 |
|
673 | 709 | # cast the values to a type that can hold nan (if necessary)
|
@@ -697,87 +733,52 @@ def setitem(self, indexer, value, mgr=None):
|
697 | 733 | raise ValueError("cannot set using a slice indexer with a "
|
698 | 734 | "different length than the value")
|
699 | 735 |
|
700 |
| - try: |
701 |
| - |
702 |
| - def _is_scalar_indexer(indexer): |
703 |
| - # return True if we are all scalar indexers |
704 |
| - |
705 |
| - if arr_value.ndim == 1: |
706 |
| - if not isinstance(indexer, tuple): |
707 |
| - indexer = tuple([indexer]) |
708 |
| - return all([is_scalar(idx) for idx in indexer]) |
709 |
| - return False |
710 |
| - |
711 |
| - def _is_empty_indexer(indexer): |
712 |
| - # return a boolean if we have an empty indexer |
| 736 | + def _is_scalar_indexer(indexer): |
| 737 | + # return True if we are all scalar indexers |
713 | 738 |
|
714 |
| - if arr_value.ndim == 1: |
715 |
| - if not isinstance(indexer, tuple): |
716 |
| - indexer = tuple([indexer]) |
717 |
| - return any(isinstance(idx, np.ndarray) and len(idx) == 0 |
718 |
| - for idx in indexer) |
719 |
| - return False |
720 |
| - |
721 |
| - # empty indexers |
722 |
| - # 8669 (empty) |
723 |
| - if _is_empty_indexer(indexer): |
724 |
| - pass |
725 |
| - |
726 |
| - # setting a single element for each dim and with a rhs that could |
727 |
| - # be say a list |
728 |
| - # GH 6043 |
729 |
| - elif _is_scalar_indexer(indexer): |
730 |
| - values[indexer] = value |
731 |
| - |
732 |
| - # if we are an exact match (ex-broadcasting), |
733 |
| - # then use the resultant dtype |
734 |
| - elif (len(arr_value.shape) and |
735 |
| - arr_value.shape[0] == values.shape[0] and |
736 |
| - np.prod(arr_value.shape) == np.prod(values.shape)): |
737 |
| - values[indexer] = value |
738 |
| - values = values.astype(arr_value.dtype) |
739 |
| - |
740 |
| - # set |
741 |
| - else: |
742 |
| - values[indexer] = value |
743 |
| - |
744 |
| - # coerce and try to infer the dtypes of the result |
745 |
| - if hasattr(value, 'dtype') and is_dtype_equal(values.dtype, |
746 |
| - value.dtype): |
747 |
| - dtype = value.dtype |
748 |
| - elif is_scalar(value): |
749 |
| - dtype, _ = _infer_dtype_from_scalar(value) |
750 |
| - else: |
751 |
| - dtype = 'infer' |
752 |
| - values = self._try_coerce_and_cast_result(values, dtype) |
753 |
| - block = self.make_block(transf(values), fastpath=True) |
754 |
| - |
755 |
| - # may have to soft convert_objects here |
756 |
| - if block.is_object and not self.is_object: |
757 |
| - block = block.convert(numeric=False) |
758 |
| - |
759 |
| - return block |
760 |
| - except ValueError: |
761 |
| - raise |
762 |
| - except TypeError: |
| 739 | + if arr_value.ndim == 1: |
| 740 | + if not isinstance(indexer, tuple): |
| 741 | + indexer = tuple([indexer]) |
| 742 | + return all([is_scalar(idx) for idx in indexer]) |
| 743 | + return False |
763 | 744 |
|
764 |
| - # cast to the passed dtype if possible |
765 |
| - # otherwise raise the original error |
766 |
| - try: |
767 |
| - # e.g. we are uint32 and our value is uint64 |
768 |
| - # this is for compat with older numpies |
769 |
| - block = self.make_block(transf(values.astype(value.dtype))) |
770 |
| - return block.setitem(indexer=indexer, value=value, mgr=mgr) |
| 745 | + def _is_empty_indexer(indexer): |
| 746 | + # return a boolean if we have an empty indexer |
771 | 747 |
|
772 |
| - except: |
773 |
| - pass |
774 |
| - |
775 |
| - raise |
| 748 | + if arr_value.ndim == 1: |
| 749 | + if not isinstance(indexer, tuple): |
| 750 | + indexer = tuple([indexer]) |
| 751 | + return any(isinstance(idx, np.ndarray) and len(idx) == 0 |
| 752 | + for idx in indexer) |
| 753 | + return False |
776 | 754 |
|
777 |
| - except Exception: |
| 755 | + # empty indexers |
| 756 | + # 8669 (empty) |
| 757 | + if _is_empty_indexer(indexer): |
778 | 758 | pass
|
779 | 759 |
|
780 |
| - return [self] |
| 760 | + # setting a single element for each dim and with a rhs that could |
| 761 | + # be say a list |
| 762 | + # GH 6043 |
| 763 | + elif _is_scalar_indexer(indexer): |
| 764 | + values[indexer] = value |
| 765 | + |
| 766 | + # if we are an exact match (ex-broadcasting), |
| 767 | + # then use the resultant dtype |
| 768 | + elif (len(arr_value.shape) and |
| 769 | + arr_value.shape[0] == values.shape[0] and |
| 770 | + np.prod(arr_value.shape) == np.prod(values.shape)): |
| 771 | + values[indexer] = value |
| 772 | + values = values.astype(arr_value.dtype) |
| 773 | + |
| 774 | + # set |
| 775 | + else: |
| 776 | + values[indexer] = value |
| 777 | + |
| 778 | + # coerce and try to infer the dtypes of the result |
| 779 | + values = self._try_coerce_and_cast_result(values, dtype) |
| 780 | + block = self.make_block(transf(values), fastpath=True) |
| 781 | + return block |
781 | 782 |
|
782 | 783 | def putmask(self, mask, new, align=True, inplace=False, axis=0,
|
783 | 784 | transpose=False, mgr=None):
|
@@ -1241,6 +1242,7 @@ def func(cond, values, other):
|
1241 | 1242 |
|
1242 | 1243 | values, values_mask, other, other_mask = self._try_coerce_args(
|
1243 | 1244 | values, other)
|
| 1245 | + |
1244 | 1246 | try:
|
1245 | 1247 | return self._try_coerce_result(expressions.where(
|
1246 | 1248 | cond, values, other, raise_on_error=True))
|
@@ -1497,6 +1499,7 @@ def putmask(self, mask, new, align=True, inplace=False, axis=0,
|
1497 | 1499 | new = new[mask]
|
1498 | 1500 |
|
1499 | 1501 | mask = _safe_reshape(mask, new_values.shape)
|
| 1502 | + |
1500 | 1503 | new_values[mask] = new
|
1501 | 1504 | new_values = self._try_coerce_result(new_values)
|
1502 | 1505 | return [self.make_block(values=new_values)]
|
@@ -1666,7 +1669,7 @@ def fillna(self, value, **kwargs):
|
1666 | 1669 |
|
1667 | 1670 | # allow filling with integers to be
|
1668 | 1671 | # interpreted as seconds
|
1669 |
| - if not isinstance(value, np.timedelta64) and is_integer(value): |
| 1672 | + if not isinstance(value, np.timedelta64): |
1670 | 1673 | value = Timedelta(value, unit='s')
|
1671 | 1674 | return super(TimeDeltaBlock, self).fillna(value, **kwargs)
|
1672 | 1675 |
|
@@ -1898,6 +1901,15 @@ def _maybe_downcast(self, blocks, downcast=None):
|
1898 | 1901 | def _can_hold_element(self, element):
|
1899 | 1902 | return True
|
1900 | 1903 |
|
| 1904 | + def _try_coerce_args(self, values, other): |
| 1905 | + """ provide coercion to our input arguments """ |
| 1906 | + |
| 1907 | + if isinstance(other, ABCDatetimeIndex): |
| 1908 | + # to store DatetimeTZBlock as object |
| 1909 | + other = other.asobject.values |
| 1910 | + |
| 1911 | + return values, False, other, False |
| 1912 | + |
1901 | 1913 | def _try_cast(self, element):
|
1902 | 1914 | return element
|
1903 | 1915 |
|
@@ -2234,8 +2246,6 @@ def _try_coerce_args(self, values, other):
|
2234 | 2246 | "naive Block")
|
2235 | 2247 | other_mask = isnull(other)
|
2236 | 2248 | other = other.asm8.view('i8')
|
2237 |
| - elif hasattr(other, 'dtype') and is_integer_dtype(other): |
2238 |
| - other = other.view('i8') |
2239 | 2249 | else:
|
2240 | 2250 | try:
|
2241 | 2251 | other = np.asarray(other)
|
@@ -2411,6 +2421,8 @@ def _try_coerce_args(self, values, other):
|
2411 | 2421 | raise ValueError("incompatible or non tz-aware value")
|
2412 | 2422 | other_mask = isnull(other)
|
2413 | 2423 | other = other.value
|
| 2424 | + else: |
| 2425 | + raise TypeError |
2414 | 2426 |
|
2415 | 2427 | return values, values_mask, other, other_mask
|
2416 | 2428 |
|
|
0 commit comments