|
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 |
|
@@ -377,7 +377,8 @@ def fillna(self, value, limit=None, inplace=False, downcast=None,
|
377 | 377 |
|
378 | 378 | # fillna, but if we cannot coerce, then try again as an ObjectBlock
|
379 | 379 | try:
|
380 |
| - values, _, value, _ = self._try_coerce_args(self.values, value) |
| 380 | + values, _, _, _ = self._try_coerce_args(self.values, value) |
| 381 | + # value may be converted to internal, thus drop |
381 | 382 | blocks = self.putmask(mask, value, inplace=inplace)
|
382 | 383 | blocks = [b.make_block(values=self._try_coerce_result(b.values))
|
383 | 384 | for b in blocks]
|
@@ -665,8 +666,43 @@ def setitem(self, indexer, value, mgr=None):
|
665 | 666 | if self.is_numeric:
|
666 | 667 | value = np.nan
|
667 | 668 |
|
668 |
| - # coerce args |
669 |
| - values, _, value, _ = self._try_coerce_args(self.values, value) |
| 669 | + # coerce if block dtype can store value |
| 670 | + values = self.values |
| 671 | + try: |
| 672 | + values, _, value, _ = self._try_coerce_args(values, value) |
| 673 | + # can keep its own dtype |
| 674 | + if hasattr(value, 'dtype') and is_dtype_equal(values.dtype, |
| 675 | + value.dtype): |
| 676 | + dtype = self.dtype |
| 677 | + else: |
| 678 | + dtype = 'infer' |
| 679 | + |
| 680 | + except (TypeError, ValueError): |
| 681 | + # current dtype cannot store value, coerce to common dtype |
| 682 | + find_dtype = False |
| 683 | + |
| 684 | + if hasattr(value, 'dtype'): |
| 685 | + dtype = value.dtype |
| 686 | + find_dtype = True |
| 687 | + |
| 688 | + elif is_scalar(value): |
| 689 | + if isnull(value): |
| 690 | + # NaN promotion is handled in latter path |
| 691 | + dtype = False |
| 692 | + else: |
| 693 | + dtype, _ = _infer_dtype_from_scalar(value, |
| 694 | + pandas_dtype=True) |
| 695 | + find_dtype = True |
| 696 | + else: |
| 697 | + dtype = 'infer' |
| 698 | + |
| 699 | + if find_dtype: |
| 700 | + dtype = _find_common_type([values.dtype, dtype]) |
| 701 | + if not is_dtype_equal(self.dtype, dtype): |
| 702 | + b = self.astype(dtype) |
| 703 | + return b.setitem(indexer, value, mgr=mgr) |
| 704 | + |
| 705 | + # value must be storeable at this moment |
670 | 706 | arr_value = np.array(value)
|
671 | 707 |
|
672 | 708 | # cast the values to a type that can hold nan (if necessary)
|
@@ -696,87 +732,52 @@ def setitem(self, indexer, value, mgr=None):
|
696 | 732 | raise ValueError("cannot set using a slice indexer with a "
|
697 | 733 | "different length than the value")
|
698 | 734 |
|
699 |
| - try: |
700 |
| - |
701 |
| - def _is_scalar_indexer(indexer): |
702 |
| - # return True if we are all scalar indexers |
703 |
| - |
704 |
| - if arr_value.ndim == 1: |
705 |
| - if not isinstance(indexer, tuple): |
706 |
| - indexer = tuple([indexer]) |
707 |
| - return all([is_scalar(idx) for idx in indexer]) |
708 |
| - return False |
709 |
| - |
710 |
| - def _is_empty_indexer(indexer): |
711 |
| - # return a boolean if we have an empty indexer |
| 735 | + def _is_scalar_indexer(indexer): |
| 736 | + # return True if we are all scalar indexers |
712 | 737 |
|
713 |
| - if arr_value.ndim == 1: |
714 |
| - if not isinstance(indexer, tuple): |
715 |
| - indexer = tuple([indexer]) |
716 |
| - return any(isinstance(idx, np.ndarray) and len(idx) == 0 |
717 |
| - for idx in indexer) |
718 |
| - return False |
719 |
| - |
720 |
| - # empty indexers |
721 |
| - # 8669 (empty) |
722 |
| - if _is_empty_indexer(indexer): |
723 |
| - pass |
724 |
| - |
725 |
| - # setting a single element for each dim and with a rhs that could |
726 |
| - # be say a list |
727 |
| - # GH 6043 |
728 |
| - elif _is_scalar_indexer(indexer): |
729 |
| - values[indexer] = value |
730 |
| - |
731 |
| - # if we are an exact match (ex-broadcasting), |
732 |
| - # then use the resultant dtype |
733 |
| - elif (len(arr_value.shape) and |
734 |
| - arr_value.shape[0] == values.shape[0] and |
735 |
| - np.prod(arr_value.shape) == np.prod(values.shape)): |
736 |
| - values[indexer] = value |
737 |
| - values = values.astype(arr_value.dtype) |
738 |
| - |
739 |
| - # set |
740 |
| - else: |
741 |
| - values[indexer] = value |
742 |
| - |
743 |
| - # coerce and try to infer the dtypes of the result |
744 |
| - if hasattr(value, 'dtype') and is_dtype_equal(values.dtype, |
745 |
| - value.dtype): |
746 |
| - dtype = value.dtype |
747 |
| - elif is_scalar(value): |
748 |
| - dtype, _ = _infer_dtype_from_scalar(value) |
749 |
| - else: |
750 |
| - dtype = 'infer' |
751 |
| - values = self._try_coerce_and_cast_result(values, dtype) |
752 |
| - block = self.make_block(transf(values), fastpath=True) |
753 |
| - |
754 |
| - # may have to soft convert_objects here |
755 |
| - if block.is_object and not self.is_object: |
756 |
| - block = block.convert(numeric=False) |
757 |
| - |
758 |
| - return block |
759 |
| - except ValueError: |
760 |
| - raise |
761 |
| - except TypeError: |
| 738 | + if arr_value.ndim == 1: |
| 739 | + if not isinstance(indexer, tuple): |
| 740 | + indexer = tuple([indexer]) |
| 741 | + return all([is_scalar(idx) for idx in indexer]) |
| 742 | + return False |
762 | 743 |
|
763 |
| - # cast to the passed dtype if possible |
764 |
| - # otherwise raise the original error |
765 |
| - try: |
766 |
| - # e.g. we are uint32 and our value is uint64 |
767 |
| - # this is for compat with older numpies |
768 |
| - block = self.make_block(transf(values.astype(value.dtype))) |
769 |
| - return block.setitem(indexer=indexer, value=value, mgr=mgr) |
| 744 | + def _is_empty_indexer(indexer): |
| 745 | + # return a boolean if we have an empty indexer |
770 | 746 |
|
771 |
| - except: |
772 |
| - pass |
773 |
| - |
774 |
| - raise |
| 747 | + if arr_value.ndim == 1: |
| 748 | + if not isinstance(indexer, tuple): |
| 749 | + indexer = tuple([indexer]) |
| 750 | + return any(isinstance(idx, np.ndarray) and len(idx) == 0 |
| 751 | + for idx in indexer) |
| 752 | + return False |
775 | 753 |
|
776 |
| - except Exception: |
| 754 | + # empty indexers |
| 755 | + # 8669 (empty) |
| 756 | + if _is_empty_indexer(indexer): |
777 | 757 | pass
|
778 | 758 |
|
779 |
| - return [self] |
| 759 | + # setting a single element for each dim and with a rhs that could |
| 760 | + # be say a list |
| 761 | + # GH 6043 |
| 762 | + elif _is_scalar_indexer(indexer): |
| 763 | + values[indexer] = value |
| 764 | + |
| 765 | + # if we are an exact match (ex-broadcasting), |
| 766 | + # then use the resultant dtype |
| 767 | + elif (len(arr_value.shape) and |
| 768 | + arr_value.shape[0] == values.shape[0] and |
| 769 | + np.prod(arr_value.shape) == np.prod(values.shape)): |
| 770 | + values[indexer] = value |
| 771 | + values = values.astype(arr_value.dtype) |
| 772 | + |
| 773 | + # set |
| 774 | + else: |
| 775 | + values[indexer] = value |
| 776 | + |
| 777 | + # coerce and try to infer the dtypes of the result |
| 778 | + values = self._try_coerce_and_cast_result(values, dtype) |
| 779 | + block = self.make_block(transf(values), fastpath=True) |
| 780 | + return block |
780 | 781 |
|
781 | 782 | def putmask(self, mask, new, align=True, inplace=False, axis=0,
|
782 | 783 | 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))
|
@@ -1519,6 +1521,7 @@ def putmask(self, mask, new, align=True, inplace=False, axis=0,
|
1519 | 1521 | new = new[mask]
|
1520 | 1522 |
|
1521 | 1523 | mask = _safe_reshape(mask, new_values.shape)
|
| 1524 | + |
1522 | 1525 | new_values[mask] = new
|
1523 | 1526 | new_values = self._try_coerce_result(new_values)
|
1524 | 1527 | return [self.make_block(values=new_values)]
|
@@ -1688,7 +1691,7 @@ def fillna(self, value, **kwargs):
|
1688 | 1691 |
|
1689 | 1692 | # allow filling with integers to be
|
1690 | 1693 | # interpreted as seconds
|
1691 |
| - if not isinstance(value, np.timedelta64) and is_integer(value): |
| 1694 | + if not isinstance(value, np.timedelta64): |
1692 | 1695 | value = Timedelta(value, unit='s')
|
1693 | 1696 | return super(TimeDeltaBlock, self).fillna(value, **kwargs)
|
1694 | 1697 |
|
@@ -1920,6 +1923,15 @@ def _maybe_downcast(self, blocks, downcast=None):
|
1920 | 1923 | def _can_hold_element(self, element):
|
1921 | 1924 | return True
|
1922 | 1925 |
|
| 1926 | + def _try_coerce_args(self, values, other): |
| 1927 | + """ provide coercion to our input arguments """ |
| 1928 | + |
| 1929 | + if isinstance(other, ABCDatetimeIndex): |
| 1930 | + # to store DatetimeTZBlock as object |
| 1931 | + other = other.asobject.values |
| 1932 | + |
| 1933 | + return values, False, other, False |
| 1934 | + |
1923 | 1935 | def _try_cast(self, element):
|
1924 | 1936 | return element
|
1925 | 1937 |
|
@@ -2256,8 +2268,6 @@ def _try_coerce_args(self, values, other):
|
2256 | 2268 | "naive Block")
|
2257 | 2269 | other_mask = isnull(other)
|
2258 | 2270 | other = other.asm8.view('i8')
|
2259 |
| - elif hasattr(other, 'dtype') and is_integer_dtype(other): |
2260 |
| - other = other.view('i8') |
2261 | 2271 | else:
|
2262 | 2272 | try:
|
2263 | 2273 | other = np.asarray(other)
|
@@ -2433,6 +2443,8 @@ def _try_coerce_args(self, values, other):
|
2433 | 2443 | raise ValueError("incompatible or non tz-aware value")
|
2434 | 2444 | other_mask = isnull(other)
|
2435 | 2445 | other = other.value
|
| 2446 | + else: |
| 2447 | + raise TypeError |
2436 | 2448 |
|
2437 | 2449 | return values, values_mask, other, other_mask
|
2438 | 2450 |
|
|
0 commit comments