From 072ed398a19069dcfd169a0151ccad40bce8a654 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Tue, 16 Feb 2021 12:58:33 +0100 Subject: [PATCH 1/8] [ArrayManager] ENH: implement concat with axis=1 (merge/join) --- .github/workflows/ci.yml | 1 + pandas/core/internals/array_manager.py | 7 ++- pandas/core/internals/concat.py | 55 +++++++++++++++++----- pandas/tests/frame/methods/test_drop.py | 2 +- pandas/tests/frame/methods/test_explode.py | 5 -- pandas/tests/frame/methods/test_join.py | 10 ++-- pandas/tests/io/formats/test_printing.py | 2 +- pandas/tests/io/test_fsspec.py | 2 +- pandas/tests/reshape/merge/test_join.py | 3 ++ pandas/tests/reshape/merge/test_merge.py | 29 +++++++++--- 10 files changed, 79 insertions(+), 37 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aec19e27a33e2..7bf6320b6653c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -153,6 +153,7 @@ jobs: run: | source activate pandas-dev pytest pandas/tests/frame/methods --array-manager + pytest pandas/tests/reshape/merge --array-manager # indexing iset related (temporary since other tests don't pass yet) pytest pandas/tests/frame/indexing/test_indexing.py::TestDataFrameIndexing::test_setitem_multi_index --array-manager diff --git a/pandas/core/internals/array_manager.py b/pandas/core/internals/array_manager.py index 083f32488acd4..a8254f870cbd5 100644 --- a/pandas/core/internals/array_manager.py +++ b/pandas/core/internals/array_manager.py @@ -754,10 +754,12 @@ def reindex_indexer( # ignored keywords consolidate: bool = True, only_slice: bool = False, + # ArrayManager specific keywords + do_integrity_check: bool = True, ) -> T: axis = self._normalize_axis(axis) return self._reindex_indexer( - new_axis, indexer, axis, fill_value, allow_dups, copy + new_axis, indexer, axis, fill_value, allow_dups, copy, do_integrity_check ) def _reindex_indexer( @@ -768,6 +770,7 @@ def _reindex_indexer( fill_value=None, allow_dups: bool = False, copy: bool = True, + do_integrity_check: bool = True, ) -> T: """ Parameters @@ -822,7 +825,7 @@ def _reindex_indexer( new_axes = list(self._axes) new_axes[axis] = new_axis - return type(self)(new_arrays, new_axes) + return type(self)(new_arrays, new_axes, do_integrity_check=do_integrity_check) def take(self, indexer, axis: int = 1, verify: bool = True, convert: bool = True): """ diff --git a/pandas/core/internals/concat.py b/pandas/core/internals/concat.py index 01d8cde3e9af2..aa3987999b3b8 100644 --- a/pandas/core/internals/concat.py +++ b/pandas/core/internals/concat.py @@ -31,6 +31,47 @@ from pandas import Index +def concatenate_array_managers( + mgrs_indexers, axes: List[Index], concat_axis: int, copy: bool +) -> Manager: + """ + Concatenate array managers into one. + + Parameters + ---------- + mgrs_indexers : list of (ArrayManager, {axis: indexer,...}) tuples + axes : list of Index + concat_axis : int + copy : bool + + Returns + ------- + ArrayManager + """ + # reindex all arrays + mgrs = [] + for mgr, indexers in mgrs_indexers: + for ax, indexer in indexers.items(): + mgr = mgr.reindex_indexer( + axes[ax], indexer, axis=ax, allow_dups=True, do_integrity_check=False + ) + mgrs.append(mgr) + + # concatting along the rows -> concat the reindexed arrays + # TODO(ArrayManager) doesn't yet preserve the correct dtype + if concat_axis == 1: + arrays = [ + concat_compat([mgrs[i].arrays[j] for i in range(len(mgrs))]) + for j in range(len(mgrs[0].arrays)) + ] + return ArrayManager(arrays, [axes[1], axes[0]], do_integrity_check=False) + # concatting along the columns -> combine reindexed arrays in a single manager + else: + assert concat_axis == 0 + arrays = list(itertools.chain.from_iterable([mgr.arrays for mgr in mgrs])) + return ArrayManager(arrays, [axes[1], axes[0]], do_integrity_check=False) + + def concatenate_block_managers( mgrs_indexers, axes: List[Index], concat_axis: int, copy: bool ) -> Manager: @@ -49,19 +90,7 @@ def concatenate_block_managers( BlockManager """ if isinstance(mgrs_indexers[0][0], ArrayManager): - - if concat_axis == 1: - # TODO for now only fastpath without indexers - mgrs = [t[0] for t in mgrs_indexers] - arrays = [ - concat_compat([mgrs[i].arrays[j] for i in range(len(mgrs))], axis=0) - for j in range(len(mgrs[0].arrays)) - ] - return ArrayManager(arrays, [axes[1], axes[0]]) - elif concat_axis == 0: - mgrs = [t[0] for t in mgrs_indexers] - arrays = list(itertools.chain.from_iterable([mgr.arrays for mgr in mgrs])) - return ArrayManager(arrays, [axes[1], axes[0]]) + return concatenate_array_managers(mgrs_indexers, axes, concat_axis, copy) concat_plans = [ _get_mgr_concatenation_plan(mgr, indexers) for mgr, indexers in mgrs_indexers diff --git a/pandas/tests/frame/methods/test_drop.py b/pandas/tests/frame/methods/test_drop.py index 4568cda24d5cf..2af5c8dd29842 100644 --- a/pandas/tests/frame/methods/test_drop.py +++ b/pandas/tests/frame/methods/test_drop.py @@ -155,7 +155,7 @@ def test_drop(self): assert return_value is None tm.assert_frame_equal(df, expected) - @td.skip_array_manager_not_yet_implemented + @td.skip_array_manager_not_yet_implemented # TODO(ArrayManager) groupby def test_drop_multiindex_not_lexsorted(self): # GH#11640 diff --git a/pandas/tests/frame/methods/test_explode.py b/pandas/tests/frame/methods/test_explode.py index be80dd49ff1fb..bd0901387eeed 100644 --- a/pandas/tests/frame/methods/test_explode.py +++ b/pandas/tests/frame/methods/test_explode.py @@ -1,14 +1,9 @@ import numpy as np import pytest -import pandas.util._test_decorators as td - import pandas as pd import pandas._testing as tm -# TODO(ArrayManager) concat with reindexing -pytestmark = td.skip_array_manager_not_yet_implemented - def test_error(): df = pd.DataFrame( diff --git a/pandas/tests/frame/methods/test_join.py b/pandas/tests/frame/methods/test_join.py index 42694dc3ff37c..2bbc73da24033 100644 --- a/pandas/tests/frame/methods/test_join.py +++ b/pandas/tests/frame/methods/test_join.py @@ -3,15 +3,10 @@ import numpy as np import pytest -import pandas.util._test_decorators as td - import pandas as pd from pandas import DataFrame, Index, MultiIndex, date_range, period_range import pandas._testing as tm -# TODO(ArrayManager) concat with reindexing -pytestmark = td.skip_array_manager_not_yet_implemented - @pytest.fixture def frame_with_period_index(): @@ -234,8 +229,9 @@ def test_join(self, multiindex_dataframe_random_data): b = frame.loc[frame.index[2:], ["B", "C"]] joined = a.join(b, how="outer").reindex(frame.index) - expected = frame.copy() - expected.values[np.isnan(joined.values)] = np.nan + expected = frame.copy().values + expected[np.isnan(joined.values)] = np.nan + expected = DataFrame(expected, index=frame.index, columns=frame.columns) assert not np.isnan(joined.values).all() diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py index 2339e21288bb5..24d1973eeda6d 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -121,7 +121,7 @@ def test_ambiguous_width(self): assert adjoined == expected -@td.skip_array_manager_not_yet_implemented +@td.skip_array_manager_not_yet_implemented # TODO(ArrayManager) JSON class TestTableSchemaRepr: @classmethod def setup_class(cls): diff --git a/pandas/tests/io/test_fsspec.py b/pandas/tests/io/test_fsspec.py index d9575a6ad81e5..3131131682ccd 100644 --- a/pandas/tests/io/test_fsspec.py +++ b/pandas/tests/io/test_fsspec.py @@ -247,7 +247,7 @@ def test_pickle_options(fsspectest): tm.assert_frame_equal(df, out) -@td.skip_array_manager_not_yet_implemented +@td.skip_array_manager_not_yet_implemented # TODO(ArrayManager) JSON def test_json_options(fsspectest): df = DataFrame({"a": [0]}) df.to_json("testmem://afile", storage_options={"test": "json_write"}) diff --git a/pandas/tests/reshape/merge/test_join.py b/pandas/tests/reshape/merge/test_join.py index 500d7000817af..242fc8cade9e6 100644 --- a/pandas/tests/reshape/merge/test_join.py +++ b/pandas/tests/reshape/merge/test_join.py @@ -1,6 +1,8 @@ import numpy as np import pytest +import pandas.util._test_decorators as td + import pandas as pd from pandas import ( Categorical, @@ -547,6 +549,7 @@ def test_join_non_unique_period_index(self): ) tm.assert_frame_equal(result, expected) + @td.skip_array_manager_not_yet_implemented # TODO(ArrayManager) groupby def test_mixed_type_join_with_suffix(self): # GH #916 df = DataFrame(np.random.randn(20, 6), columns=["a", "b", "c", "d", "e", "f"]) diff --git a/pandas/tests/reshape/merge/test_merge.py b/pandas/tests/reshape/merge/test_merge.py index da3ac81c4aa17..e9591cc46dd26 100644 --- a/pandas/tests/reshape/merge/test_merge.py +++ b/pandas/tests/reshape/merge/test_merge.py @@ -277,17 +277,27 @@ def test_merge_copy(self): merged["d"] = "peekaboo" assert (right["d"] == "bar").all() - def test_merge_nocopy(self): + def test_merge_nocopy(self, using_array_manager): left = DataFrame({"a": 0, "b": 1}, index=range(10)) right = DataFrame({"c": "foo", "d": "bar"}, index=range(10)) merged = merge(left, right, left_index=True, right_index=True, copy=False) - merged["a"] = 6 - assert (left["a"] == 6).all() + if using_array_manager: + # With ArrayManager, setting a column doesn't change the values inplace + # and thus does not propagate the changes to the original left/right + # dataframes -> need to check that no copy was made in a different way + # TODO(ArrayManager) we should be able to simplify this with a .loc + # setitem test: merged.loc[0, "a"] = 10; assert left.loc[0, "a"] == 10 + # but this currently replaces the array (_setitem_with_indexer_split_path) + assert merged._mgr.arrays[0] is left._mgr.arrays[0] + assert merged._mgr.arrays[2] is right._mgr.arrays[0] + else: + merged["a"] = 6 + assert (left["a"] == 6).all() - merged["d"] = "peekaboo" - assert (right["d"] == "peekaboo").all() + merged["d"] = "peekaboo" + assert (right["d"] == "peekaboo").all() def test_intelligently_handle_join_key(self): # #733, be a bit more 1337 about not returning unconsolidated DataFrame @@ -1362,7 +1372,7 @@ def test_merge_take_missing_values_from_index_of_other_dtype(self): expected = expected.reindex(columns=["a", "key", "b"]) tm.assert_frame_equal(result, expected) - def test_merge_readonly(self): + def test_merge_readonly(self, using_array_manager): # https://github.com/pandas-dev/pandas/issues/27943 data1 = DataFrame( np.arange(20).reshape((4, 5)) + 1, columns=["a", "b", "c", "d", "e"] @@ -1371,7 +1381,12 @@ def test_merge_readonly(self): np.arange(20).reshape((5, 4)) + 1, columns=["a", "b", "x", "y"] ) - data1._mgr.blocks[0].values.flags.writeable = False + if using_array_manager: + for arr in data1._mgr.arrays: + arr.flags.writeable = False + else: + data1._mgr.blocks[0].values.flags.writeable = False + data1.merge(data2) # no error From 31cfb0d5d0ebe303c820b6684f64c824e8c5a565 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Wed, 17 Feb 2021 11:00:35 +0100 Subject: [PATCH 2/8] address feedback --- pandas/core/internals/array_manager.py | 1 + pandas/core/internals/concat.py | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pandas/core/internals/array_manager.py b/pandas/core/internals/array_manager.py index ddac75ce81071..28e9ce6885e21 100644 --- a/pandas/core/internals/array_manager.py +++ b/pandas/core/internals/array_manager.py @@ -756,6 +756,7 @@ def reindex_indexer( self: T, new_axis, indexer, + *, axis: int, fill_value=None, allow_dups: bool = False, diff --git a/pandas/core/internals/concat.py b/pandas/core/internals/concat.py index 141e9f42a350a..99bc9ac337728 100644 --- a/pandas/core/internals/concat.py +++ b/pandas/core/internals/concat.py @@ -75,16 +75,16 @@ def concatenate_array_managers( ) mgrs.append(mgr) - # concatting along the rows -> concat the reindexed arrays - # TODO(ArrayManager) doesn't yet preserve the correct dtype if concat_axis == 1: + # concatting along the rows -> concat the reindexed arrays + # TODO(ArrayManager) doesn't yet preserve the correct dtype arrays = [ concat_compat([mgrs[i].arrays[j] for i in range(len(mgrs))]) for j in range(len(mgrs[0].arrays)) ] return ArrayManager(arrays, [axes[1], axes[0]], do_integrity_check=False) - # concatting along the columns -> combine reindexed arrays in a single manager else: + # concatting along the columns -> combine reindexed arrays in a single manager assert concat_axis == 0 arrays = list(itertools.chain.from_iterable([mgr.arrays for mgr in mgrs])) return ArrayManager(arrays, [axes[1], axes[0]], do_integrity_check=False) @@ -107,6 +107,7 @@ def concatenate_block_managers( ------- BlockManager """ + # TODO(ArrayManager) this assumes that all managers are of the same type if isinstance(mgrs_indexers[0][0], ArrayManager): return concatenate_array_managers(mgrs_indexers, axes, concat_axis, copy) From 3488d63d6bba41663a39ca097e7f2a22663c4c54 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Thu, 18 Feb 2021 14:31:06 +0100 Subject: [PATCH 3/8] add array property --- pandas/core/internals/managers.py | 12 ++++++++++++ pandas/tests/reshape/merge/test_merge.py | 7 ++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py index b3f0466f236b6..29dc5b14fdd35 100644 --- a/pandas/core/internals/managers.py +++ b/pandas/core/internals/managers.py @@ -282,6 +282,18 @@ def get_dtypes(self): dtypes = np.array([blk.dtype for blk in self.blocks]) return algos.take_nd(dtypes, self.blknos, allow_fill=False) + @property + def arrays(self): + """ + Quick access to the backing arrays of the Blocks. + + Only for compatibility with ArrayManager for testing convenience. + Not to be used in actual code, and return value is not the same as the + ArrayManager method (list of 1D arrays vs iterator of 2D ndarrays / 1D EAs). + """ + for blk in self.blocks: + yield blk.values + def __getstate__(self): block_values = [b.values for b in self.blocks] block_items = [self.items[b.mgr_locs.indexer] for b in self.blocks] diff --git a/pandas/tests/reshape/merge/test_merge.py b/pandas/tests/reshape/merge/test_merge.py index 72afea7ba3e8d..483a9488be70d 100644 --- a/pandas/tests/reshape/merge/test_merge.py +++ b/pandas/tests/reshape/merge/test_merge.py @@ -1391,11 +1391,8 @@ def test_merge_readonly(self, using_array_manager): np.arange(20).reshape((5, 4)) + 1, columns=["a", "b", "x", "y"] ) - if using_array_manager: - for arr in data1._mgr.arrays: - arr.flags.writeable = False - else: - data1._mgr.blocks[0].values.flags.writeable = False + for arr in data1._mgr.arrays: + arr.flags.writeable = False data1.merge(data2) # no error From 437c1d24bae42e9903fa46ea60140b434fd2f852 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Thu, 18 Feb 2021 14:40:47 +0100 Subject: [PATCH 4/8] simplify do_integrity_check --- pandas/core/internals/array_manager.py | 7 ++----- pandas/core/internals/concat.py | 4 +--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/pandas/core/internals/array_manager.py b/pandas/core/internals/array_manager.py index 28e9ce6885e21..1655d7bd28f08 100644 --- a/pandas/core/internals/array_manager.py +++ b/pandas/core/internals/array_manager.py @@ -764,12 +764,10 @@ def reindex_indexer( # ignored keywords consolidate: bool = True, only_slice: bool = False, - # ArrayManager specific keywords - do_integrity_check: bool = True, ) -> T: axis = self._normalize_axis(axis) return self._reindex_indexer( - new_axis, indexer, axis, fill_value, allow_dups, copy, do_integrity_check + new_axis, indexer, axis, fill_value, allow_dups, copy ) def _reindex_indexer( @@ -780,7 +778,6 @@ def _reindex_indexer( fill_value=None, allow_dups: bool = False, copy: bool = True, - do_integrity_check: bool = True, ) -> T: """ Parameters @@ -835,7 +832,7 @@ def _reindex_indexer( new_axes = list(self._axes) new_axes[axis] = new_axis - return type(self)(new_arrays, new_axes, do_integrity_check=do_integrity_check) + return type(self)(new_arrays, new_axes, do_integrity_check=False) def take(self, indexer, axis: int = 1, verify: bool = True, convert: bool = True): """ diff --git a/pandas/core/internals/concat.py b/pandas/core/internals/concat.py index 99bc9ac337728..a294677cf4e05 100644 --- a/pandas/core/internals/concat.py +++ b/pandas/core/internals/concat.py @@ -70,9 +70,7 @@ def concatenate_array_managers( mgrs = [] for mgr, indexers in mgrs_indexers: for ax, indexer in indexers.items(): - mgr = mgr.reindex_indexer( - axes[ax], indexer, axis=ax, allow_dups=True, do_integrity_check=False - ) + mgr = mgr.reindex_indexer(axes[ax], indexer, axis=ax, allow_dups=True) mgrs.append(mgr) if concat_axis == 1: From 2597cd5461c5c0dd43c116f30e8fe87b1cbc2b26 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Thu, 18 Feb 2021 14:42:12 +0100 Subject: [PATCH 5/8] clean-up unused using_array_manager --- pandas/tests/reshape/merge/test_merge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/reshape/merge/test_merge.py b/pandas/tests/reshape/merge/test_merge.py index 483a9488be70d..eef8e75b8e111 100644 --- a/pandas/tests/reshape/merge/test_merge.py +++ b/pandas/tests/reshape/merge/test_merge.py @@ -1382,7 +1382,7 @@ def test_merge_take_missing_values_from_index_of_other_dtype(self): expected = expected.reindex(columns=["a", "key", "b"]) tm.assert_frame_equal(result, expected) - def test_merge_readonly(self, using_array_manager): + def test_merge_readonly(self): # https://github.com/pandas-dev/pandas/issues/27943 data1 = DataFrame( np.arange(20).reshape((4, 5)) + 1, columns=["a", "b", "c", "d", "e"] From 31d1305fc24cc32c97cb3ca028615a2822f202b8 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Thu, 18 Feb 2021 15:39:04 +0100 Subject: [PATCH 6/8] remove keyword-only indicator --- pandas/core/internals/array_manager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/core/internals/array_manager.py b/pandas/core/internals/array_manager.py index 1655d7bd28f08..e1bde790e16e4 100644 --- a/pandas/core/internals/array_manager.py +++ b/pandas/core/internals/array_manager.py @@ -756,7 +756,6 @@ def reindex_indexer( self: T, new_axis, indexer, - *, axis: int, fill_value=None, allow_dups: bool = False, From 3f5fc380f4ca8d856a7bb089fe16f4941856403e Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Tue, 23 Feb 2021 09:53:18 +0100 Subject: [PATCH 7/8] concatenate_block_managers -> concatenate_managers --- pandas/core/internals/__init__.py | 4 ++-- pandas/core/internals/concat.py | 2 +- pandas/core/reshape/concat.py | 4 ++-- pandas/core/reshape/merge.py | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pandas/core/internals/__init__.py b/pandas/core/internals/__init__.py index 132598e03d6c0..054ce8a40288b 100644 --- a/pandas/core/internals/__init__.py +++ b/pandas/core/internals/__init__.py @@ -12,7 +12,7 @@ TimeDeltaBlock, make_block, ) -from pandas.core.internals.concat import concatenate_block_managers +from pandas.core.internals.concat import concatenate_managers from pandas.core.internals.managers import ( BlockManager, SingleBlockManager, @@ -35,7 +35,7 @@ "ArrayManager", "BlockManager", "SingleBlockManager", - "concatenate_block_managers", + "concatenate_managers", # those two are preserved here for downstream compatibility (GH-33892) "create_block_manager_from_arrays", "create_block_manager_from_blocks", diff --git a/pandas/core/internals/concat.py b/pandas/core/internals/concat.py index 44284023745cd..362f2fde47e0b 100644 --- a/pandas/core/internals/concat.py +++ b/pandas/core/internals/concat.py @@ -88,7 +88,7 @@ def concatenate_array_managers( return ArrayManager(arrays, [axes[1], axes[0]], do_integrity_check=False) -def concatenate_block_managers( +def concatenate_managers( mgrs_indexers, axes: List[Index], concat_axis: int, copy: bool ) -> Manager: """ diff --git a/pandas/core/reshape/concat.py b/pandas/core/reshape/concat.py index 92fc4a2e85163..a8c6913cd5d6c 100644 --- a/pandas/core/reshape/concat.py +++ b/pandas/core/reshape/concat.py @@ -43,7 +43,7 @@ get_unanimous_names, ) import pandas.core.indexes.base as ibase -from pandas.core.internals import concatenate_block_managers +from pandas.core.internals import concatenate_managers if TYPE_CHECKING: from pandas import ( @@ -524,7 +524,7 @@ def get_result(self): mgrs_indexers.append((obj._mgr, indexers)) - new_data = concatenate_block_managers( + new_data = concatenate_managers( mgrs_indexers, self.new_axes, concat_axis=self.bm_axis, copy=self.copy ) if not self.copy: diff --git a/pandas/core/reshape/merge.py b/pandas/core/reshape/merge.py index 79d018427aa33..217d9915f834c 100644 --- a/pandas/core/reshape/merge.py +++ b/pandas/core/reshape/merge.py @@ -76,7 +76,7 @@ import pandas.core.common as com from pandas.core.construction import extract_array from pandas.core.frame import _merge_doc -from pandas.core.internals import concatenate_block_managers +from pandas.core.internals import concatenate_managers from pandas.core.sorting import is_int64_overflow_possible if TYPE_CHECKING: @@ -720,7 +720,7 @@ def get_result(self): lindexers = {1: left_indexer} if left_indexer is not None else {} rindexers = {1: right_indexer} if right_indexer is not None else {} - result_data = concatenate_block_managers( + result_data = concatenate_managers( [(self.left._mgr, lindexers), (self.right._mgr, rindexers)], axes=[llabels.append(rlabels), join_index], concat_axis=0, @@ -1616,7 +1616,7 @@ def get_result(self): lindexers = {1: left_join_indexer} if left_join_indexer is not None else {} rindexers = {1: right_join_indexer} if right_join_indexer is not None else {} - result_data = concatenate_block_managers( + result_data = concatenate_managers( [(self.left._mgr, lindexers), (self.right._mgr, rindexers)], axes=[llabels.append(rlabels), join_index], concat_axis=0, From 54692cadd39d22f98c230c01da85181c9ffb7937 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Tue, 23 Feb 2021 09:55:02 +0100 Subject: [PATCH 8/8] add comment --- pandas/tests/reshape/merge/test_merge.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tests/reshape/merge/test_merge.py b/pandas/tests/reshape/merge/test_merge.py index eef8e75b8e111..e1b1e80a29a43 100644 --- a/pandas/tests/reshape/merge/test_merge.py +++ b/pandas/tests/reshape/merge/test_merge.py @@ -1391,6 +1391,7 @@ def test_merge_readonly(self): np.arange(20).reshape((5, 4)) + 1, columns=["a", "b", "x", "y"] ) + # make each underlying block array / column array read-only for arr in data1._mgr.arrays: arr.flags.writeable = False