Repository: pandas-dev/pandas

Issue:
DataFrame.where does not work as expected with inplace=True
related #4667, #7647

According to the documentation, `inplace` should replace values appropriately with `other`, but this does not seem to work as expected.  This worked in 0.12.

```
In [6]: df = pandas.DataFrame([{'A': 1, 'B': np.nan, 'C': 'Test'}, {'A': np.nan, 'B': 'Test', 'C': np.nan}])

In [7]: df
Out[7]: 
    A     B     C
0   1   NaN  Test
1 NaN  Test   NaN

In [8]: df1 = df.where(~pandas.isnull(df), None)

In [9]: df1
Out[9]: 
      A     B     C
0     1  None  Test
1  None  Test  None

In [10]: df.where(~pandas.isnull(df), None, inplace=True)

In [11]: df
Out[11]: 
    A     B     C
0   1   NaN  Test
1 NaN  Test   NaN
```



Discussion:

Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -679,8 +679,8 @@ def to_gbq(self, destination_table, project_id=None, chunksize=10000,
         the defined table schema and column types. For simplicity, this method
         uses the Google BigQuery streaming API. The to_gbq method chunks data
         into a default chunk size of 10,000. Failures return the complete error
-        response which can be quite long depending on the size of the insert. 
-        There are several important limitations of the Google streaming API 
+        response which can be quite long depending on the size of the insert.
+        There are several important limitations of the Google streaming API
         which are detailed at:
         https://developers.google.com/bigquery/streaming-data-into-bigquery.
 
@@ -1925,11 +1925,7 @@ def _setitem_frame(self, key, value):
         if key.values.dtype != np.bool_:
             raise TypeError('Must pass DataFrame with boolean values only')
 
-        if self._is_mixed_type:
-            if not self._is_numeric_mixed_type:
-                raise TypeError(
-                    'Cannot do boolean setting on mixed-type frame')
-
+        self._check_inplace_setting(value)
         self._check_setitem_copy()
         self.where(-key, value, inplace=True)
 
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -1910,6 +1910,24 @@ def _is_datelike_mixed_type(self):
         f = lambda: self._data.is_datelike_mixed_type
         return self._protect_consolidate(f)
 
+    def _check_inplace_setting(self, value):
+        """ check whether we allow in-place setting with this type of value """
+
+        if self._is_mixed_type:
+            if not self._is_numeric_mixed_type:
+
+                # allow an actual np.nan thru
+                try:
+                    if np.isnan(value):
+                        return True
+                except:
+                    pass
+
+                raise TypeError(
+                    'Cannot do inplace boolean setting on mixed-types with a non np.nan value')
+
+        return True
+
     def _protect_consolidate(self, f):
         blocks_before = len(self._data.blocks)
         result = f()
@@ -3214,6 +3232,8 @@ def where(self, cond, other=np.nan, inplace=False, axis=None, level=None,
         if inplace:
             # we may have different type blocks come out of putmask, so
             # reconstruct the block manager
+
+            self._check_inplace_setting(other)
             new_data = self._data.putmask(mask=cond, new=other, align=axis is None,
                                           inplace=True)
             self._update_inplace(new_data)


Test patch:
diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py
--- a/pandas/tests/test_frame.py
+++ b/pandas/tests/test_frame.py
@@ -9242,6 +9242,12 @@ def test_where_none(self):
         expected = DataFrame({'series': Series([0,1,2,3,4,5,6,7,np.nan,np.nan]) })
         assert_frame_equal(df, expected)
 
+        # GH 7656
+        df = DataFrame([{'A': 1, 'B': np.nan, 'C': 'Test'}, {'A': np.nan, 'B': 'Test', 'C': np.nan}])
+        expected = df.where(~isnull(df), None)
+        with tm.assertRaisesRegexp(TypeError, 'boolean setting on mixed-type'):
+            df.where(~isnull(df), None, inplace=True)
+
     def test_where_align(self):
 
         def create():