Skip to content

BUG: maximum recursion error when replacing empty lists #22083

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Aug 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.24.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ 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 replacing empty lists (:issue:`22083`)
-

Build Changes
Expand Down
10 changes: 7 additions & 3 deletions pandas/core/internals/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -802,6 +801,11 @@ 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 is_object_dtype(self):
raise

# try again with a compatible block
block = self.astype(object)
return block.replace(to_replace=original_to_replace,
Expand Down
4 changes: 4 additions & 0 deletions pandas/core/missing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
14 changes: 14 additions & 0 deletions pandas/tests/frame/test_replace.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,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(ValueError, "cannot assign mismatch"):
df.replace({np.nan: []})
with tm.assert_raises_regex(ValueError, "cannot assign mismatch"):
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}})
Expand Down
13 changes: 13 additions & 0 deletions pandas/tests/series/test_replace.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, "cannot assign mismatch"):
s.replace({np.nan: []})
with tm.assert_raises_regex(ValueError, "cannot assign mismatch"):
s.replace({np.nan: ['dummy', 'alt']})

def test_replace_mixed_types(self):
s = pd.Series(np.arange(5), dtype='int64')

Expand Down