From a3f688af99c61c88ddac19b9e72d0a51ea33e1c9 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Fri, 27 Jul 2018 16:24:50 +0100 Subject: [PATCH 01/20] minor docstring --- pandas/core/internals/blocks.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index ffa2267dd6877..77208e311b3f3 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -777,10 +777,9 @@ def copy(self, deep=True, mgr=None): def replace(self, to_replace, value, inplace=False, filter=None, regex=False, convert=True, mgr=None): - """ replace the to_replace value with value, possible to create new + """replace the to_replace value with value, possible to create new blocks here this is just a call to putmask. regex is not used here. - It is used in ObjectBlocks. It is here for API - compatibility. + It is used in ObjectBlocks. It is here for API compatibility. """ inplace = validate_bool_kwarg(inplace, 'inplace') From c97b2ee954e02077dcb62705cbe3452027067450 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Fri, 27 Jul 2018 16:45:27 +0100 Subject: [PATCH 02/20] prevent infinite recursion error --- pandas/core/generic.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 16105014bf74e..ebd3804c7dfa0 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -6004,7 +6004,7 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None, # {'A': NA} -> 0 elif not is_list_like(value): keys = [(k, src) for k, src in compat.iteritems(to_replace) - if k in self] + if k in self and len(src) > 0] keys_len = len(keys) - 1 for i, (k, src) in enumerate(keys): convert = i == keys_len @@ -6018,7 +6018,8 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None, raise TypeError('value argument must be scalar, dict, or ' 'Series') - elif is_list_like(to_replace): # [NA, ''] -> [0, 'missing'] + # [NA, ''] -> [0, 'missing'] + elif is_list_like(to_replace): if is_list_like(value): if len(to_replace) != len(value): raise ValueError('Replacement lists must match ' @@ -6030,7 +6031,8 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None, inplace=inplace, regex=regex) - else: # [NA, ''] -> 0 + # [NA, ''] -> 0 + elif len(to_replace) > 0: new_data = self._data.replace(to_replace=to_replace, value=value, inplace=inplace, regex=regex) From 941fccb145a6659eccabd645cc23263fe50b14bf Mon Sep 17 00:00:00 2001 From: Ming Li Date: Fri, 27 Jul 2018 17:16:20 +0100 Subject: [PATCH 03/20] negative mask if no match or na --- pandas/core/missing.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pandas/core/missing.py b/pandas/core/missing.py index a46c19e2d399c..39081508c575e 100644 --- a/pandas/core/missing.py +++ b/pandas/core/missing.py @@ -68,6 +68,9 @@ def mask_missing(arr, values_to_mask): else: mask |= isna(arr) + if mask is None: + mask = np.zeros(arr.shape, dtype=bool) + return mask From 389ebcd4205c444ea26a3d3fbb1de30f79bd5913 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Fri, 27 Jul 2018 17:16:32 +0100 Subject: [PATCH 04/20] revert generic --- pandas/core/generic.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index ebd3804c7dfa0..16105014bf74e 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -6004,7 +6004,7 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None, # {'A': NA} -> 0 elif not is_list_like(value): keys = [(k, src) for k, src in compat.iteritems(to_replace) - if k in self and len(src) > 0] + if k in self] keys_len = len(keys) - 1 for i, (k, src) in enumerate(keys): convert = i == keys_len @@ -6018,8 +6018,7 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None, raise TypeError('value argument must be scalar, dict, or ' 'Series') - # [NA, ''] -> [0, 'missing'] - elif is_list_like(to_replace): + elif is_list_like(to_replace): # [NA, ''] -> [0, 'missing'] if is_list_like(value): if len(to_replace) != len(value): raise ValueError('Replacement lists must match ' @@ -6031,8 +6030,7 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None, inplace=inplace, regex=regex) - # [NA, ''] -> 0 - elif len(to_replace) > 0: + else: # [NA, ''] -> 0 new_data = self._data.replace(to_replace=to_replace, value=value, inplace=inplace, regex=regex) From 557365892d5717dda24d35e85c93ac6cdec04f4a Mon Sep 17 00:00:00 2001 From: Ming Li Date: Sat, 28 Jul 2018 15:25:57 +0100 Subject: [PATCH 05/20] revert missing --- pandas/core/missing.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pandas/core/missing.py b/pandas/core/missing.py index 39081508c575e..a46c19e2d399c 100644 --- a/pandas/core/missing.py +++ b/pandas/core/missing.py @@ -68,9 +68,6 @@ def mask_missing(arr, values_to_mask): else: mask |= isna(arr) - if mask is None: - mask = np.zeros(arr.shape, dtype=bool) - return mask From e7dad7e5889373a6eae486ad94e569e0378e7732 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Sat, 28 Jul 2018 17:47:34 +0100 Subject: [PATCH 06/20] add test case for series.replace --- pandas/tests/series/test_replace.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pandas/tests/series/test_replace.py b/pandas/tests/series/test_replace.py index a3b92798879f5..09ba2e8f204c8 100644 --- a/pandas/tests/series/test_replace.py +++ b/pandas/tests/series/test_replace.py @@ -130,6 +130,19 @@ def test_replace_with_single_list(self): s.replace([1, 2, 3], inplace=True, method='crash_cymbal') tm.assert_series_equal(s, ser) + def test_replace_with_empty_list(self): + # GH 21977 + s = pd.Series([[1], [2, 3], [], np.nan, [4]]) + expected = s + result = s.replace([], np.nan) + tm.assert_series_equal(result, expected) + + # GH 19266 + with tm.assert_raises_regex(ValueError, 'mismatch length'): + s.replace({np.nan: []}) + with tm.assert_raises_regex(ValueError, 'mismatch length'): + s.replace({np.nan: ['dummy', 'alt']}) + def test_replace_mixed_types(self): s = pd.Series(np.arange(5), dtype='int64') From 309216c982960015c2642bf510ce2006d5bf640b Mon Sep 17 00:00:00 2001 From: Ming Li Date: Sat, 28 Jul 2018 18:27:38 +0100 Subject: [PATCH 07/20] boolean mask guaranteed if None --- pandas/core/missing.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pandas/core/missing.py b/pandas/core/missing.py index a46c19e2d399c..b2daec327d618 100644 --- a/pandas/core/missing.py +++ b/pandas/core/missing.py @@ -68,6 +68,10 @@ def mask_missing(arr, values_to_mask): else: mask |= isna(arr) + # GH 21977 + if mask is None: + mask = np.zeros(arr.shape, dtype=bool) + return mask From 402d983cb09c8b6af1c0b66dc93c7aa383801fa4 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Sat, 28 Jul 2018 18:31:16 +0100 Subject: [PATCH 08/20] add test case for frame --- pandas/tests/frame/test_replace.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pandas/tests/frame/test_replace.py b/pandas/tests/frame/test_replace.py index dd83a94b7062a..ad472e19cbec8 100644 --- a/pandas/tests/frame/test_replace.py +++ b/pandas/tests/frame/test_replace.py @@ -605,6 +605,20 @@ def test_replace_list(self): assert_frame_equal(res, expec) + def test_replace_with_empty_list(self): + # GH 21977 + s = pd.Series([['a', 'b'], np.nan, [1]]) + df = pd.DataFrame({'col': s}) + + expected = df + result = df.replace([], np.nan) + assert_frame_equal(result, expected) + # GH 19266 + with tm.assert_raises_regex(NotImplementedError, 'Replace with array'): + df.replace({np.nan: []}) + with tm.assert_raises_regex(NotImplementedError, 'Replace with array'): + df.replace({np.nan: ['dummy', 'alt']}) + def test_replace_series_dict(self): # from GH 3064 df = DataFrame({'zero': {'a': 0.0, 'b': 1}, 'one': {'a': 2.0, 'b': 0}}) From 360403113ca27ab685357bd92d5f7edd2067107d Mon Sep 17 00:00:00 2001 From: Ming Li Date: Sat, 28 Jul 2018 18:31:30 +0100 Subject: [PATCH 09/20] update series test --- pandas/tests/series/test_replace.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/series/test_replace.py b/pandas/tests/series/test_replace.py index 09ba2e8f204c8..5cf6f283c0fd0 100644 --- a/pandas/tests/series/test_replace.py +++ b/pandas/tests/series/test_replace.py @@ -138,9 +138,9 @@ def test_replace_with_empty_list(self): tm.assert_series_equal(result, expected) # GH 19266 - with tm.assert_raises_regex(ValueError, 'mismatch length'): + with tm.assert_raises_regex(NotImplementedError, 'Replace with array'): s.replace({np.nan: []}) - with tm.assert_raises_regex(ValueError, 'mismatch length'): + with tm.assert_raises_regex(NotImplementedError, 'Replace with array'): s.replace({np.nan: ['dummy', 'alt']}) def test_replace_mixed_types(self): From 001c3a0d340d61138887af5fb6fc212e3b629611 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Sat, 28 Jul 2018 18:54:35 +0100 Subject: [PATCH 10/20] use different error to avoid recursion --- pandas/core/internals/blocks.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 77208e311b3f3..8505a9caf57cb 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -992,15 +992,15 @@ def putmask(self, mask, new, align=True, inplace=False, axis=0, # # TODO: this prob needs some better checking # for 2D cases - if ((is_list_like(new) and - np.any(mask[mask]) and + if ((is_list_like(new) and np.any(mask[mask]) and getattr(new, 'ndim', 1) == 1)): - + # GH 19266 and GH 21977 if not (mask.shape[-1] == len(new) or mask[mask].shape[-1] == len(new) or len(new) == 1): - raise ValueError("cannot assign mismatch " - "length to masked array") + raise NotImplementedError( + "Replace with array-like of mismatch length to masked " + "array is not supported.") np.putmask(new_values, mask, new) From 91100f7b16e015baf38924e1cfcecc539bb1645d Mon Sep 17 00:00:00 2001 From: Ming Li Date: Sat, 28 Jul 2018 20:41:26 +0100 Subject: [PATCH 11/20] modify tests to expect intended error --- pandas/tests/frame/test_replace.py | 4 ++-- pandas/tests/series/indexing/test_boolean.py | 4 ++-- pandas/tests/series/test_replace.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pandas/tests/frame/test_replace.py b/pandas/tests/frame/test_replace.py index ad472e19cbec8..2050f190d875c 100644 --- a/pandas/tests/frame/test_replace.py +++ b/pandas/tests/frame/test_replace.py @@ -614,9 +614,9 @@ def test_replace_with_empty_list(self): result = df.replace([], np.nan) assert_frame_equal(result, expected) # GH 19266 - with tm.assert_raises_regex(NotImplementedError, 'Replace with array'): + with tm.assert_raises_regex(Exception, "cannot assign mismatch"): df.replace({np.nan: []}) - with tm.assert_raises_regex(NotImplementedError, 'Replace with array'): + with tm.assert_raises_regex(Exception, "cannot assign mismatch"): df.replace({np.nan: ['dummy', 'alt']}) def test_replace_series_dict(self): diff --git a/pandas/tests/series/indexing/test_boolean.py b/pandas/tests/series/indexing/test_boolean.py index e2a9b3586648d..21337b8cfe51b 100644 --- a/pandas/tests/series/indexing/test_boolean.py +++ b/pandas/tests/series/indexing/test_boolean.py @@ -213,12 +213,12 @@ def test_where_unsafe(): def f(): s[mask] = [5, 4, 3, 2, 1] - pytest.raises(ValueError, f) + pytest.raises(Exception, f) def f(): s[mask] = [0] * 5 - pytest.raises(ValueError, f) + pytest.raises(Exception, f) # dtype changes s = Series([1, 2, 3, 4]) diff --git a/pandas/tests/series/test_replace.py b/pandas/tests/series/test_replace.py index 5cf6f283c0fd0..e3a02aac929dc 100644 --- a/pandas/tests/series/test_replace.py +++ b/pandas/tests/series/test_replace.py @@ -138,9 +138,9 @@ def test_replace_with_empty_list(self): tm.assert_series_equal(result, expected) # GH 19266 - with tm.assert_raises_regex(NotImplementedError, 'Replace with array'): + with tm.assert_raises_regex(Exception, "cannot assign mismatch"): s.replace({np.nan: []}) - with tm.assert_raises_regex(NotImplementedError, 'Replace with array'): + with tm.assert_raises_regex(Exception, "cannot assign mismatch"): s.replace({np.nan: ['dummy', 'alt']}) def test_replace_mixed_types(self): From 8271576a283fe4b78f967f472063428a9f0c861d Mon Sep 17 00:00:00 2001 From: Ming Li Date: Sat, 28 Jul 2018 20:42:18 +0100 Subject: [PATCH 12/20] change error type and avoid infinite loop --- pandas/core/internals/blocks.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 8505a9caf57cb..5eb74241c204f 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -994,13 +994,14 @@ def putmask(self, mask, new, align=True, inplace=False, axis=0, # for 2D cases if ((is_list_like(new) and np.any(mask[mask]) and getattr(new, 'ndim', 1) == 1)): - # GH 19266 and GH 21977 if not (mask.shape[-1] == len(new) or mask[mask].shape[-1] == len(new) or len(new) == 1): - raise NotImplementedError( - "Replace with array-like of mismatch length to masked " - "array is not supported.") + # GH 19266 and GH 21977 + # ValueError triggers try except block in Block.replace + # causing RecursionError + raise Exception("cannot assign mismatch length " + "to masked array") np.putmask(new_values, mask, new) From 167a3b7159d272fcff0b7d03d4108e440b502372 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Mon, 6 Aug 2018 11:54:15 +0100 Subject: [PATCH 13/20] revert test_boolean --- pandas/tests/series/indexing/test_boolean.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/series/indexing/test_boolean.py b/pandas/tests/series/indexing/test_boolean.py index 21337b8cfe51b..e2a9b3586648d 100644 --- a/pandas/tests/series/indexing/test_boolean.py +++ b/pandas/tests/series/indexing/test_boolean.py @@ -213,12 +213,12 @@ def test_where_unsafe(): def f(): s[mask] = [5, 4, 3, 2, 1] - pytest.raises(Exception, f) + pytest.raises(ValueError, f) def f(): s[mask] = [0] * 5 - pytest.raises(Exception, f) + pytest.raises(ValueError, f) # dtype changes s = Series([1, 2, 3, 4]) From f657ae30144d1ffbb1f8c8c621bf986f47ffc813 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Mon, 6 Aug 2018 11:56:50 +0100 Subject: [PATCH 14/20] revert type of error --- pandas/tests/frame/test_replace.py | 4 ++-- pandas/tests/series/test_replace.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/tests/frame/test_replace.py b/pandas/tests/frame/test_replace.py index 2050f190d875c..574c0033d0e3b 100644 --- a/pandas/tests/frame/test_replace.py +++ b/pandas/tests/frame/test_replace.py @@ -614,9 +614,9 @@ def test_replace_with_empty_list(self): result = df.replace([], np.nan) assert_frame_equal(result, expected) # GH 19266 - with tm.assert_raises_regex(Exception, "cannot assign mismatch"): + with tm.assert_raises_regex(ValueError, "cannot assign mismatch"): df.replace({np.nan: []}) - with tm.assert_raises_regex(Exception, "cannot assign mismatch"): + with tm.assert_raises_regex(ValueError, "cannot assign mismatch"): df.replace({np.nan: ['dummy', 'alt']}) def test_replace_series_dict(self): diff --git a/pandas/tests/series/test_replace.py b/pandas/tests/series/test_replace.py index e3a02aac929dc..d495fd9c83c24 100644 --- a/pandas/tests/series/test_replace.py +++ b/pandas/tests/series/test_replace.py @@ -138,9 +138,9 @@ def test_replace_with_empty_list(self): tm.assert_series_equal(result, expected) # GH 19266 - with tm.assert_raises_regex(Exception, "cannot assign mismatch"): + with tm.assert_raises_regex(ValueError, "cannot assign mismatch"): s.replace({np.nan: []}) - with tm.assert_raises_regex(Exception, "cannot assign mismatch"): + with tm.assert_raises_regex(ValueError, "cannot assign mismatch"): s.replace({np.nan: ['dummy', 'alt']}) def test_replace_mixed_types(self): From c8f4f72f74684084b6f4e11f3e1cf6407a053784 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Mon, 6 Aug 2018 12:04:24 +0100 Subject: [PATCH 15/20] only retry if the block is not ObjectBlock --- pandas/core/internals/blocks.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 5eb74241c204f..34437760c1ab8 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -801,12 +801,17 @@ def replace(self, to_replace, value, inplace=False, filter=None, copy=not inplace) for b in blocks] return blocks except (TypeError, ValueError): - - # try again with a compatible block - block = self.astype(object) - return block.replace( - to_replace=original_to_replace, value=value, inplace=inplace, - filter=filter, regex=regex, convert=convert) + if self.dtype == 'object': + raise + else: + # try again with a compatible block + block = self.astype(object) + return block.replace(to_replace=original_to_replace, + value=value, + inplace=inplace, + filter=filter, + regex=regex, + convert=convert) def _replace_single(self, *args, **kwargs): """ no-op on a non-ObjectBlock """ @@ -992,16 +997,15 @@ def putmask(self, mask, new, align=True, inplace=False, axis=0, # # TODO: this prob needs some better checking # for 2D cases - if ((is_list_like(new) and np.any(mask[mask]) and + if ((is_list_like(new) and + np.any(mask[mask]) and getattr(new, 'ndim', 1) == 1)): + if not (mask.shape[-1] == len(new) or mask[mask].shape[-1] == len(new) or len(new) == 1): - # GH 19266 and GH 21977 - # ValueError triggers try except block in Block.replace - # causing RecursionError - raise Exception("cannot assign mismatch length " - "to masked array") + raise ValueError("cannot assign mismatch " + "length to masked array") np.putmask(new_values, mask, new) From d3c3236730efc9e6ddf1c34568b76753d24454f2 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Mon, 6 Aug 2018 12:09:37 +0100 Subject: [PATCH 16/20] add comment --- pandas/core/internals/blocks.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 34437760c1ab8..4537428e04f77 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -801,6 +801,8 @@ def replace(self, to_replace, value, inplace=False, filter=None, copy=not inplace) for b in blocks] return blocks except (TypeError, ValueError): + # GH 22083, TypeError or ValueError occurred within error handling + # causes infinite loop. Cast and retry only if not objectblock. if self.dtype == 'object': raise else: From a8020b98dbcafe5cd61ac792cec2fedb00de8c4d Mon Sep 17 00:00:00 2001 From: Ming Li Date: Mon, 6 Aug 2018 14:31:21 +0100 Subject: [PATCH 17/20] add whatsnew --- doc/source/whatsnew/v0.24.0.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index ea0677a0edf28..695a775110c73 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -667,7 +667,8 @@ Reshaping - Bug in :meth:`DataFrame.replace` raises RecursionError when converting OutOfBounds ``datetime64[ns, tz]`` (:issue:`20380`) - :func:`pandas.core.groupby.GroupBy.rank` now raises a ``ValueError`` when an invalid value is passed for argument ``na_option`` (:issue:`22124`) - Bug in :func:`get_dummies` with Unicode attributes in Python 2 (:issue:`22084`) -- +- Bug in :meth:`DataFrame.replace` raises RecursionError when replace empty lists (:issue:`22083`) +- Build Changes ^^^^^^^^^^^^^ From 201adf6c42cab132b989aad0cad461d6fd5db4fb Mon Sep 17 00:00:00 2001 From: Ming Li Date: Mon, 6 Aug 2018 17:37:35 +0100 Subject: [PATCH 18/20] minor change in whatsnew --- doc/source/whatsnew/v0.24.0.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 695a775110c73..7c46a1c7b7f27 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -667,8 +667,8 @@ Reshaping - Bug in :meth:`DataFrame.replace` raises RecursionError when converting OutOfBounds ``datetime64[ns, tz]`` (:issue:`20380`) - :func:`pandas.core.groupby.GroupBy.rank` now raises a ``ValueError`` when an invalid value is passed for argument ``na_option`` (:issue:`22124`) - Bug in :func:`get_dummies` with Unicode attributes in Python 2 (:issue:`22084`) -- Bug in :meth:`DataFrame.replace` raises RecursionError when replace empty lists (:issue:`22083`) -- +- Bug in :meth:`DataFrame.replace` raises ``RecursionError`` when replacing empty lists (:issue:`22083`) +- Build Changes ^^^^^^^^^^^^^ From c4a4a8bf060b6d5d216d7f74c44f58b9314ee23f Mon Sep 17 00:00:00 2001 From: Ming Li Date: Mon, 6 Aug 2018 17:41:05 +0100 Subject: [PATCH 19/20] add empty list --- pandas/tests/frame/test_replace.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/frame/test_replace.py b/pandas/tests/frame/test_replace.py index 6e7e76d15c15e..49dba1c769572 100644 --- a/pandas/tests/frame/test_replace.py +++ b/pandas/tests/frame/test_replace.py @@ -605,12 +605,12 @@ def test_replace_list(self): def test_replace_with_empty_list(self): # GH 21977 - s = pd.Series([['a', 'b'], np.nan, [1]]) + s = pd.Series([['a', 'b'], [], np.nan, [1]]) df = pd.DataFrame({'col': s}) - expected = df result = df.replace([], np.nan) assert_frame_equal(result, expected) + # GH 19266 with tm.assert_raises_regex(ValueError, "cannot assign mismatch"): df.replace({np.nan: []}) From 2bbd097f8a5ed6f1eeb487461a5a6820277a1a4d Mon Sep 17 00:00:00 2001 From: Ming Li Date: Tue, 7 Aug 2018 14:23:19 +0100 Subject: [PATCH 20/20] minor refactor --- pandas/core/internals/blocks.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 46ae439d973d4..be80a605f08fd 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -803,17 +803,17 @@ def replace(self, to_replace, value, inplace=False, filter=None, except (TypeError, ValueError): # GH 22083, TypeError or ValueError occurred within error handling # causes infinite loop. Cast and retry only if not objectblock. - if self.dtype == 'object': + if is_object_dtype(self): raise - else: - # try again with a compatible block - block = self.astype(object) - return block.replace(to_replace=original_to_replace, - value=value, - inplace=inplace, - filter=filter, - regex=regex, - convert=convert) + + # try again with a compatible block + block = self.astype(object) + return block.replace(to_replace=original_to_replace, + value=value, + inplace=inplace, + filter=filter, + regex=regex, + convert=convert) def _replace_single(self, *args, **kwargs): """ no-op on a non-ObjectBlock """