import numpy as np import pytest from pandas._libs import index as libindex from pandas.errors import SettingWithCopyError import pandas.util._test_decorators as td from pandas import ( DataFrame, MultiIndex, Series, ) import pandas._testing as tm def test_detect_chained_assignment(using_copy_on_write, warn_copy_on_write): # Inplace ops, originally from: # https://stackoverflow.com/questions/20508968/series-fillna-in-a-multiindex-dataframe-does-not-fill-is-this-a-bug a = [12, 23] b = [123, None] c = [1234, 2345] d = [12345, 23456] tuples = [("eyes", "left"), ("eyes", "right"), ("ears", "left"), ("ears", "right")] events = { ("eyes", "left"): a, ("eyes", "right"): b, ("ears", "left"): c, ("ears", "right"): d, } multiind = MultiIndex.from_tuples(tuples, names=["part", "side"]) zed = DataFrame(events, index=["a", "b"], columns=multiind) if using_copy_on_write: with tm.raises_chained_assignment_error(): zed["eyes"]["right"].fillna(value=555, inplace=True) elif warn_copy_on_write: with tm.assert_produces_warning(None): zed["eyes"]["right"].fillna(value=555, inplace=True) else: msg = "A value is trying to be set on a copy of a slice from a DataFrame" with pytest.raises(SettingWithCopyError, match=msg): with tm.assert_produces_warning(None): zed["eyes"]["right"].fillna(value=555, inplace=True) @td.skip_array_manager_invalid_test # with ArrayManager df.loc[0] is not a view def test_cache_updating(using_copy_on_write, warn_copy_on_write): # 5216 # make sure that we don't try to set a dead cache a = np.random.default_rng(2).random((10, 3)) df = DataFrame(a, columns=["x", "y", "z"]) df_original = df.copy() tuples = [(i, j) for i in range(5) for j in range(2)] index = MultiIndex.from_tuples(tuples) df.index = index # setting via chained assignment # but actually works, since everything is a view with tm.raises_chained_assignment_error(): df.loc[0]["z"].iloc[0] = 1.0 if using_copy_on_write: assert df.loc[(0, 0), "z"] == df_original.loc[0, "z"] else: result = df.loc[(0, 0), "z"] assert result == 1 # correct setting df.loc[(0, 0), "z"] = 2 result = df.loc[(0, 0), "z"] assert result == 2 def test_indexer_caching(monkeypatch): # GH5727 # make sure that indexers are in the _internal_names_set size_cutoff = 20 with monkeypatch.context(): monkeypatch.setattr(libindex, "_SIZE_CUTOFF", size_cutoff) index = MultiIndex.from_arrays([np.arange(size_cutoff), np.arange(size_cutoff)]) s = Series(np.zeros(size_cutoff), index=index) # setitem s[s == 0] = 1 expected = Series(np.ones(size_cutoff), index=index) tm.assert_series_equal(s, expected)