From af84c6976115f85a9291ac2070679556e93237f6 Mon Sep 17 00:00:00 2001 From: Roland Lukesch Date: Mon, 22 Feb 2021 21:23:17 +0100 Subject: [PATCH 1/8] BUG: Incomplete Styler copy methods fix (#39708) --- doc/source/whatsnew/v1.3.0.rst | 1 + pandas/io/formats/style.py | 16 +++- pandas/tests/io/formats/test_style.py | 111 +++++++++++++++++++++++++- 3 files changed, 123 insertions(+), 5 deletions(-) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index d5177075afda5..bc83062bb0185 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -482,6 +482,7 @@ Other - Bug in :class:`Styler` where rendered HTML was missing a column class identifier for certain header cells (:issue:`39716`) - Bug in :meth:`Styler.background_gradient` where text-color was not determined correctly (:issue:`39888`) - Bug in :meth:`DataFrame.equals`, :meth:`Series.equals`, :meth:`Index.equals` with object-dtype containing ``np.datetime64("NaT")`` or ``np.timedelta64("NaT")`` (:issue:`39650`) +- Bug in :class:`Styler` copy methods which were not updated for recently introduced attributes (:issue:`39708`) .. --------------------------------------------------------------------------- diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 3b0d857217d43..806b20373eb68 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -783,15 +783,29 @@ def _copy(self, deepcopy: bool = False) -> Styler: precision=self.precision, caption=self.caption, uuid=self.uuid, - table_styles=self.table_styles, + table_attributes=self.table_attributes, + cell_ids=self.cell_ids, na_rep=self.na_rep, + uuid_len=self.uuid_len, ) + + styler.hidden_index = self.hidden_index + if deepcopy: styler.ctx = copy.deepcopy(self.ctx) styler._todo = copy.deepcopy(self._todo) + styler.table_styles = copy.deepcopy(self.table_styles) + styler.hidden_columns = copy.deepcopy(self.hidden_columns) + styler.cell_context = copy.deepcopy(self.cell_context) + styler.tooltips = copy.deepcopy(self.tooltips) else: styler.ctx = self.ctx styler._todo = self._todo + styler.table_styles = self.table_styles + styler.hidden_columns = self.hidden_columns + styler.cell_context = self.cell_context + styler.tooltips = self.tooltips + return styler def __copy__(self) -> Styler: diff --git a/pandas/tests/io/formats/test_style.py b/pandas/tests/io/formats/test_style.py index 66dc1cd4adddd..eedc559e538a3 100644 --- a/pandas/tests/io/formats/test_style.py +++ b/pandas/tests/io/formats/test_style.py @@ -87,28 +87,131 @@ def test_update_ctx_flatten_multi_and_trailing_semi(self): } assert self.styler.ctx == expected - def test_copy(self): + @pytest.mark.parametrize("do_changes", [True, False]) + @pytest.mark.parametrize("do_render", [True, False]) + def test_copy(self, do_changes, do_render): + # Updated in GH39708 + # Change some defaults (to check later if they are copied) + if do_changes: + style = [{"selector": "th", "props": [("foo", "bar")]}] + self.styler.set_table_styles(style) + attributes = 'class="foo" data-bar' + self.styler.set_table_attributes(attributes) + self.styler.uuid_len += 1 + self.styler.hidden_index = not self.styler.hidden_index + self.styler.hide_columns("A") + classes = pd.DataFrame( + [["favorite-val red", ""], [None, "blue my-val"]], + index=self.df.index, + columns=self.df.columns, + ) + self.styler.set_td_classes(classes) + ttips = pd.DataFrame( + data=[["Favorite", ""], [np.nan, "my"]], + columns=self.df.columns, + index=self.df.index, + ) + self.styler.set_tooltips(ttips) + self.styler.cell_ids = not self.styler.cell_ids + self.styler.format("{:.2%}") + + if do_render: + self.styler.render() + s2 = copy.copy(self.styler) + + # Check for identity assert self.styler is not s2 assert self.styler.ctx is s2.ctx # shallow assert self.styler._todo is s2._todo - + assert self.styler.table_styles is s2.table_styles + assert self.styler.hidden_columns is s2.hidden_columns + assert self.styler.cell_context is s2.cell_context + assert self.styler.tooltips is s2.tooltips + if do_changes: # self.styler.tooltips is not None + assert self.styler.tooltips.tt_data is s2.tooltips.tt_data + + # Check for equality (and changes in referenced objects) self.styler._update_ctx(self.attrs) self.styler.highlight_max() assert self.styler.ctx == s2.ctx assert self.styler._todo == s2._todo + assert self.styler.table_styles == s2.table_styles + assert self.styler.table_attributes == s2.table_attributes + assert self.styler.cell_ids == s2.cell_ids + assert self.styler.uuid_len == s2.uuid_len + assert self.styler.hidden_index == s2.hidden_index + assert self.styler.hidden_columns == s2.hidden_columns + assert self.styler.cell_context == s2.cell_context + if do_changes: # self.styler.table_style is not None + self.styler.table_styles[0]["selector"] = "ti" + assert self.styler.table_styles == s2.table_styles + if do_changes: # self.styler.tooltips is not None + tm.assert_frame_equal(self.styler.tooltips.tt_data, s2.tooltips.tt_data) + + @pytest.mark.parametrize("do_changes", [True, False]) + @pytest.mark.parametrize("do_render", [True, False]) + def test_deepcopy(self, do_changes, do_render): + # Updated in GH39708 + # Change some defaults (to check later if they are copied) + if do_changes: + style = [{"selector": "th", "props": [("foo", "bar")]}] + self.styler.set_table_styles(style) + attributes = 'class="foo" data-bar' + self.styler.set_table_attributes(attributes) + self.styler.uuid_len += 1 + self.styler.hidden_index = not self.styler.hidden_index + self.styler.hide_columns("A") + classes = pd.DataFrame( + [["favorite-val red", ""], [None, "blue my-val"]], + index=self.df.index, + columns=self.df.columns, + ) + self.styler.set_td_classes(classes) + ttips = pd.DataFrame( + data=[["Favorite", ""], [np.nan, "my"]], + columns=self.df.columns, + index=self.df.index, + ) + self.styler.set_tooltips(ttips) + self.styler.cell_ids = not self.styler.cell_ids + self.styler.format("{:.2%}") + + if do_render: + self.styler.render() - def test_deepcopy(self): s2 = copy.deepcopy(self.styler) + + # Check for non-identity assert self.styler is not s2 assert self.styler.ctx is not s2.ctx assert self.styler._todo is not s2._todo - + assert self.styler.hidden_columns is not s2.hidden_columns + assert self.styler.cell_context is not s2.cell_context + if do_changes: # self.styler.table_style is not None + assert self.styler.table_styles is not s2.table_styles + if do_changes: # self.styler.tooltips is not None + assert self.styler.tooltips is not s2.tooltips + assert self.styler.tooltips.tt_data is not s2.tooltips.tt_data + + # Check for equality (and changes in original objects) self.styler._update_ctx(self.attrs) self.styler.highlight_max() assert self.styler.ctx != s2.ctx assert s2._todo == [] assert self.styler._todo != s2._todo + assert self.styler.table_styles == s2.table_styles + assert self.styler.table_attributes == s2.table_attributes + assert self.styler.cell_ids == s2.cell_ids + assert self.styler.uuid_len == s2.uuid_len + assert self.styler.hidden_index == s2.hidden_index + assert self.styler.hidden_columns == s2.hidden_columns + assert self.styler.cell_context == s2.cell_context + if do_changes: # self.styler.table_style is not None + self.styler.table_styles[0]["selector"] = "ti" + assert self.styler.table_styles != s2.table_styles + if do_changes: # self.styler.tooltips is not None + tm.assert_frame_equal(self.styler.tooltips.tt_data, s2.tooltips.tt_data) def test_clear(self): # updated in GH 39396 From 6e4927fe8313dee3762ec14d3b9bf3d5e6b1f068 Mon Sep 17 00:00:00 2001 From: Roland Lukesch Date: Tue, 23 Feb 2021 22:23:59 +0100 Subject: [PATCH 2/8] Mention issue number in enhancements section --- doc/source/whatsnew/v1.3.0.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index bc83062bb0185..07b4af594a119 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -63,7 +63,7 @@ Other enhancements - :meth:`DataFrame.apply` can now accept non-callable DataFrame properties as strings, e.g. ``df.apply("size")``, which was already the case for :meth:`Series.apply` (:issue:`39116`) - :meth:`Series.apply` can now accept list-like or dictionary-like arguments that aren't lists or dictionaries, e.g. ``ser.apply(np.array(["sum", "mean"]))``, which was already the case for :meth:`DataFrame.apply` (:issue:`39140`) - :meth:`DataFrame.plot.scatter` can now accept a categorical column as the argument to ``c`` (:issue:`12380`, :issue:`31357`) -- :meth:`.Styler.set_tooltips` allows on hover tooltips to be added to styled HTML dataframes (:issue:`35643`, :issue:`21266`, :issue:`39317`) +- :meth:`.Styler.set_tooltips` allows on hover tooltips to be added to styled HTML dataframes (:issue:`35643`, :issue:`21266`, :issue:`39317`, :issue:`39708`) - :meth:`.Styler.set_tooltips_class` and :meth:`.Styler.set_table_styles` amended to optionally allow certain css-string input arguments (:issue:`39564`) - :meth:`.Styler.apply` now more consistently accepts ndarray function returns, i.e. in all cases for ``axis`` is ``0, 1 or None`` (:issue:`39359`) - :meth:`.Styler.apply` and :meth:`.Styler.applymap` now raise errors if wrong format CSS is passed on render (:issue:`39660`) @@ -482,7 +482,6 @@ Other - Bug in :class:`Styler` where rendered HTML was missing a column class identifier for certain header cells (:issue:`39716`) - Bug in :meth:`Styler.background_gradient` where text-color was not determined correctly (:issue:`39888`) - Bug in :meth:`DataFrame.equals`, :meth:`Series.equals`, :meth:`Index.equals` with object-dtype containing ``np.datetime64("NaT")`` or ``np.timedelta64("NaT")`` (:issue:`39650`) -- Bug in :class:`Styler` copy methods which were not updated for recently introduced attributes (:issue:`39708`) .. --------------------------------------------------------------------------- From d916e6647113db1198d0618b81c747b7c6dd4176 Mon Sep 17 00:00:00 2001 From: Roland Lukesch Date: Tue, 23 Feb 2021 22:28:18 +0100 Subject: [PATCH 3/8] Improve copy mechanism for uuid and uuid_len --- pandas/io/formats/style.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 806b20373eb68..046779073cd3a 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -782,13 +782,12 @@ def _copy(self, deepcopy: bool = False) -> Styler: self.data, precision=self.precision, caption=self.caption, - uuid=self.uuid, table_attributes=self.table_attributes, cell_ids=self.cell_ids, na_rep=self.na_rep, - uuid_len=self.uuid_len, ) + styler.uuid = self.uuid styler.hidden_index = self.hidden_index if deepcopy: From beae31983235d13b376a60f9acdcc344b017f48e Mon Sep 17 00:00:00 2001 From: Roland Lukesch Date: Tue, 23 Feb 2021 22:31:26 +0100 Subject: [PATCH 4/8] Wrap test_copy and test_deepcopy --- pandas/tests/io/formats/test_style.py | 145 ++++++++++++-------------- 1 file changed, 67 insertions(+), 78 deletions(-) diff --git a/pandas/tests/io/formats/test_style.py b/pandas/tests/io/formats/test_style.py index eedc559e538a3..02a4c7490b8d0 100644 --- a/pandas/tests/io/formats/test_style.py +++ b/pandas/tests/io/formats/test_style.py @@ -89,7 +89,7 @@ def test_update_ctx_flatten_multi_and_trailing_semi(self): @pytest.mark.parametrize("do_changes", [True, False]) @pytest.mark.parametrize("do_render", [True, False]) - def test_copy(self, do_changes, do_render): + def test_copy_wrapped(self, do_changes, do_render): # Updated in GH39708 # Change some defaults (to check later if they are copied) if do_changes: @@ -97,7 +97,6 @@ def test_copy(self, do_changes, do_render): self.styler.set_table_styles(style) attributes = 'class="foo" data-bar' self.styler.set_table_attributes(attributes) - self.styler.uuid_len += 1 self.styler.hidden_index = not self.styler.hidden_index self.styler.hide_columns("A") classes = pd.DataFrame( @@ -118,100 +117,90 @@ def test_copy(self, do_changes, do_render): if do_render: self.styler.render() - s2 = copy.copy(self.styler) + s_copy = copy.copy(self.styler) + s_deepcopy = copy.deepcopy(self.styler) # Check for identity - assert self.styler is not s2 - assert self.styler.ctx is s2.ctx # shallow - assert self.styler._todo is s2._todo - assert self.styler.table_styles is s2.table_styles - assert self.styler.hidden_columns is s2.hidden_columns - assert self.styler.cell_context is s2.cell_context - assert self.styler.tooltips is s2.tooltips + assert self.styler is not s_copy + assert self.styler.ctx is s_copy.ctx # shallow + assert self.styler._todo is s_copy._todo + assert self.styler.table_styles is s_copy.table_styles + assert self.styler.hidden_columns is s_copy.hidden_columns + assert self.styler.cell_context is s_copy.cell_context + assert self.styler.tooltips is s_copy.tooltips if do_changes: # self.styler.tooltips is not None - assert self.styler.tooltips.tt_data is s2.tooltips.tt_data + assert self.styler.tooltips.tt_data is s_copy.tooltips.tt_data + assert ( + self.styler.tooltips.class_properties + is s_copy.tooltips.class_properties + ) + assert self.styler.tooltips.table_styles is s_copy.tooltips.table_styles - # Check for equality (and changes in referenced objects) - self.styler._update_ctx(self.attrs) - self.styler.highlight_max() - assert self.styler.ctx == s2.ctx - assert self.styler._todo == s2._todo - assert self.styler.table_styles == s2.table_styles - assert self.styler.table_attributes == s2.table_attributes - assert self.styler.cell_ids == s2.cell_ids - assert self.styler.uuid_len == s2.uuid_len - assert self.styler.hidden_index == s2.hidden_index - assert self.styler.hidden_columns == s2.hidden_columns - assert self.styler.cell_context == s2.cell_context + # Check for non-identity + assert self.styler is not s_deepcopy + assert self.styler.ctx is not s_deepcopy.ctx + assert self.styler._todo is not s_deepcopy._todo + assert self.styler.hidden_columns is not s_deepcopy.hidden_columns + assert self.styler.cell_context is not s_deepcopy.cell_context if do_changes: # self.styler.table_style is not None - self.styler.table_styles[0]["selector"] = "ti" - assert self.styler.table_styles == s2.table_styles + assert self.styler.table_styles is not s_deepcopy.table_styles if do_changes: # self.styler.tooltips is not None - tm.assert_frame_equal(self.styler.tooltips.tt_data, s2.tooltips.tt_data) - - @pytest.mark.parametrize("do_changes", [True, False]) - @pytest.mark.parametrize("do_render", [True, False]) - def test_deepcopy(self, do_changes, do_render): - # Updated in GH39708 - # Change some defaults (to check later if they are copied) - if do_changes: - style = [{"selector": "th", "props": [("foo", "bar")]}] - self.styler.set_table_styles(style) - attributes = 'class="foo" data-bar' - self.styler.set_table_attributes(attributes) - self.styler.uuid_len += 1 - self.styler.hidden_index = not self.styler.hidden_index - self.styler.hide_columns("A") - classes = pd.DataFrame( - [["favorite-val red", ""], [None, "blue my-val"]], - index=self.df.index, - columns=self.df.columns, + assert self.styler.tooltips is not s_deepcopy.tooltips + assert self.styler.tooltips.tt_data is not s_deepcopy.tooltips.tt_data + assert ( + self.styler.tooltips.class_properties + is not s_deepcopy.tooltips.class_properties ) - self.styler.set_td_classes(classes) - ttips = pd.DataFrame( - data=[["Favorite", ""], [np.nan, "my"]], - columns=self.df.columns, - index=self.df.index, + assert ( + self.styler.tooltips.table_styles + is not s_deepcopy.tooltips.table_styles ) - self.styler.set_tooltips(ttips) - self.styler.cell_ids = not self.styler.cell_ids - self.styler.format("{:.2%}") - - if do_render: - self.styler.render() - - s2 = copy.deepcopy(self.styler) - # Check for non-identity - assert self.styler is not s2 - assert self.styler.ctx is not s2.ctx - assert self.styler._todo is not s2._todo - assert self.styler.hidden_columns is not s2.hidden_columns - assert self.styler.cell_context is not s2.cell_context + # Check for equality (and changes in referenced objects) + self.styler._update_ctx(self.attrs) + self.styler.highlight_max() + assert self.styler.ctx == s_copy.ctx + assert self.styler._todo == s_copy._todo + assert self.styler.table_styles == s_copy.table_styles + assert self.styler.table_attributes == s_copy.table_attributes + assert self.styler.cell_ids == s_copy.cell_ids + assert self.styler.hidden_index == s_copy.hidden_index + assert self.styler.hidden_columns == s_copy.hidden_columns + assert self.styler.cell_context == s_copy.cell_context if do_changes: # self.styler.table_style is not None - assert self.styler.table_styles is not s2.table_styles + assert self.styler.table_styles == s_copy.table_styles if do_changes: # self.styler.tooltips is not None - assert self.styler.tooltips is not s2.tooltips - assert self.styler.tooltips.tt_data is not s2.tooltips.tt_data + tm.assert_frame_equal(self.styler.tooltips.tt_data, s_copy.tooltips.tt_data) + assert ( + self.styler.tooltips.class_properties + == s_copy.tooltips.class_properties + ) + assert self.styler.tooltips.table_styles == s_copy.tooltips.table_styles # Check for equality (and changes in original objects) self.styler._update_ctx(self.attrs) self.styler.highlight_max() - assert self.styler.ctx != s2.ctx - assert s2._todo == [] - assert self.styler._todo != s2._todo - assert self.styler.table_styles == s2.table_styles - assert self.styler.table_attributes == s2.table_attributes - assert self.styler.cell_ids == s2.cell_ids - assert self.styler.uuid_len == s2.uuid_len - assert self.styler.hidden_index == s2.hidden_index - assert self.styler.hidden_columns == s2.hidden_columns - assert self.styler.cell_context == s2.cell_context + assert self.styler.ctx != s_deepcopy.ctx + assert s_deepcopy._todo == [] + assert self.styler._todo != s_deepcopy._todo + assert self.styler.table_styles == s_deepcopy.table_styles + assert self.styler.table_attributes == s_deepcopy.table_attributes + assert self.styler.cell_ids == s_deepcopy.cell_ids + assert self.styler.hidden_index == s_deepcopy.hidden_index + assert self.styler.hidden_columns == s_deepcopy.hidden_columns + assert self.styler.cell_context == s_deepcopy.cell_context if do_changes: # self.styler.table_style is not None self.styler.table_styles[0]["selector"] = "ti" - assert self.styler.table_styles != s2.table_styles + assert self.styler.table_styles != s_deepcopy.table_styles if do_changes: # self.styler.tooltips is not None - tm.assert_frame_equal(self.styler.tooltips.tt_data, s2.tooltips.tt_data) + tm.assert_frame_equal( + self.styler.tooltips.tt_data, s_deepcopy.tooltips.tt_data + ) + assert ( + self.styler.tooltips.class_properties + == s_deepcopy.tooltips.class_properties + ) + assert self.styler.tooltips.table_styles == s_deepcopy.tooltips.table_styles def test_clear(self): # updated in GH 39396 From 88ebd707e3f10a15d0fa352f2be23e77626bcb1f Mon Sep 17 00:00:00 2001 From: Roland Lukesch Date: Tue, 23 Feb 2021 22:34:09 +0100 Subject: [PATCH 5/8] Copy hidden_columns, not deepcopy --- pandas/io/formats/style.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 046779073cd3a..cc5003c2cf112 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -794,7 +794,7 @@ def _copy(self, deepcopy: bool = False) -> Styler: styler.ctx = copy.deepcopy(self.ctx) styler._todo = copy.deepcopy(self._todo) styler.table_styles = copy.deepcopy(self.table_styles) - styler.hidden_columns = copy.deepcopy(self.hidden_columns) + styler.hidden_columns = copy.copy(self.hidden_columns) styler.cell_context = copy.deepcopy(self.cell_context) styler.tooltips = copy.deepcopy(self.tooltips) else: From be9676aaa6be289cf5b0d8e30114e1a2a8e5e799 Mon Sep 17 00:00:00 2001 From: Roland Lukesch Date: Tue, 23 Feb 2021 23:12:32 +0100 Subject: [PATCH 6/8] Remove .format call --- pandas/tests/io/formats/test_style.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/tests/io/formats/test_style.py b/pandas/tests/io/formats/test_style.py index 02a4c7490b8d0..264b2f711f143 100644 --- a/pandas/tests/io/formats/test_style.py +++ b/pandas/tests/io/formats/test_style.py @@ -112,7 +112,6 @@ def test_copy_wrapped(self, do_changes, do_render): ) self.styler.set_tooltips(ttips) self.styler.cell_ids = not self.styler.cell_ids - self.styler.format("{:.2%}") if do_render: self.styler.render() From 68a19ece398ca058f2f2dea371bde5d819f34208 Mon Sep 17 00:00:00 2001 From: Roland Lukesch Date: Wed, 24 Feb 2021 00:12:48 +0100 Subject: [PATCH 7/8] Simplify test_copy_wrapped --- pandas/tests/io/formats/test_style.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pandas/tests/io/formats/test_style.py b/pandas/tests/io/formats/test_style.py index 264b2f711f143..9f6ff901fbe0f 100644 --- a/pandas/tests/io/formats/test_style.py +++ b/pandas/tests/io/formats/test_style.py @@ -119,6 +119,9 @@ def test_copy_wrapped(self, do_changes, do_render): s_copy = copy.copy(self.styler) s_deepcopy = copy.deepcopy(self.styler) + self.styler._update_ctx(self.attrs) + self.styler.highlight_max() + # Check for identity assert self.styler is not s_copy assert self.styler.ctx is s_copy.ctx # shallow @@ -156,8 +159,6 @@ def test_copy_wrapped(self, do_changes, do_render): ) # Check for equality (and changes in referenced objects) - self.styler._update_ctx(self.attrs) - self.styler.highlight_max() assert self.styler.ctx == s_copy.ctx assert self.styler._todo == s_copy._todo assert self.styler.table_styles == s_copy.table_styles @@ -177,8 +178,6 @@ def test_copy_wrapped(self, do_changes, do_render): assert self.styler.tooltips.table_styles == s_copy.tooltips.table_styles # Check for equality (and changes in original objects) - self.styler._update_ctx(self.attrs) - self.styler.highlight_max() assert self.styler.ctx != s_deepcopy.ctx assert s_deepcopy._todo == [] assert self.styler._todo != s_deepcopy._todo From dc338d5d28286fa81e61931f4024fac05e4031f4 Mon Sep 17 00:00:00 2001 From: Roland Lukesch Date: Thu, 25 Feb 2021 21:25:50 +0100 Subject: [PATCH 8/8] Remove duplicate code in test_copy --- pandas/tests/io/formats/test_style.py | 81 +++++++++++---------------- 1 file changed, 32 insertions(+), 49 deletions(-) diff --git a/pandas/tests/io/formats/test_style.py b/pandas/tests/io/formats/test_style.py index 9f6ff901fbe0f..9349b5f760dc4 100644 --- a/pandas/tests/io/formats/test_style.py +++ b/pandas/tests/io/formats/test_style.py @@ -89,14 +89,14 @@ def test_update_ctx_flatten_multi_and_trailing_semi(self): @pytest.mark.parametrize("do_changes", [True, False]) @pytest.mark.parametrize("do_render", [True, False]) - def test_copy_wrapped(self, do_changes, do_render): + def test_copy(self, do_changes, do_render): # Updated in GH39708 - # Change some defaults (to check later if they are copied) + # Change some defaults (to check later if the new values are copied) if do_changes: - style = [{"selector": "th", "props": [("foo", "bar")]}] - self.styler.set_table_styles(style) - attributes = 'class="foo" data-bar' - self.styler.set_table_attributes(attributes) + self.styler.set_table_styles( + [{"selector": "th", "props": [("foo", "bar")]}] + ) + self.styler.set_table_attributes('class="foo" data-bar') self.styler.hidden_index = not self.styler.hidden_index self.styler.hide_columns("A") classes = pd.DataFrame( @@ -119,12 +119,11 @@ def test_copy_wrapped(self, do_changes, do_render): s_copy = copy.copy(self.styler) s_deepcopy = copy.deepcopy(self.styler) - self.styler._update_ctx(self.attrs) - self.styler.highlight_max() + assert self.styler is not s_copy + assert self.styler is not s_deepcopy # Check for identity - assert self.styler is not s_copy - assert self.styler.ctx is s_copy.ctx # shallow + assert self.styler.ctx is s_copy.ctx assert self.styler._todo is s_copy._todo assert self.styler.table_styles is s_copy.table_styles assert self.styler.hidden_columns is s_copy.hidden_columns @@ -139,7 +138,6 @@ def test_copy_wrapped(self, do_changes, do_render): assert self.styler.tooltips.table_styles is s_copy.tooltips.table_styles # Check for non-identity - assert self.styler is not s_deepcopy assert self.styler.ctx is not s_deepcopy.ctx assert self.styler._todo is not s_deepcopy._todo assert self.styler.hidden_columns is not s_deepcopy.hidden_columns @@ -158,47 +156,32 @@ def test_copy_wrapped(self, do_changes, do_render): is not s_deepcopy.tooltips.table_styles ) - # Check for equality (and changes in referenced objects) + self.styler._update_ctx(self.attrs) + self.styler.highlight_max() assert self.styler.ctx == s_copy.ctx - assert self.styler._todo == s_copy._todo - assert self.styler.table_styles == s_copy.table_styles - assert self.styler.table_attributes == s_copy.table_attributes - assert self.styler.cell_ids == s_copy.cell_ids - assert self.styler.hidden_index == s_copy.hidden_index - assert self.styler.hidden_columns == s_copy.hidden_columns - assert self.styler.cell_context == s_copy.cell_context - if do_changes: # self.styler.table_style is not None - assert self.styler.table_styles == s_copy.table_styles - if do_changes: # self.styler.tooltips is not None - tm.assert_frame_equal(self.styler.tooltips.tt_data, s_copy.tooltips.tt_data) - assert ( - self.styler.tooltips.class_properties - == s_copy.tooltips.class_properties - ) - assert self.styler.tooltips.table_styles == s_copy.tooltips.table_styles - - # Check for equality (and changes in original objects) assert self.styler.ctx != s_deepcopy.ctx - assert s_deepcopy._todo == [] + assert self.styler._todo == s_copy._todo assert self.styler._todo != s_deepcopy._todo - assert self.styler.table_styles == s_deepcopy.table_styles - assert self.styler.table_attributes == s_deepcopy.table_attributes - assert self.styler.cell_ids == s_deepcopy.cell_ids - assert self.styler.hidden_index == s_deepcopy.hidden_index - assert self.styler.hidden_columns == s_deepcopy.hidden_columns - assert self.styler.cell_context == s_deepcopy.cell_context - if do_changes: # self.styler.table_style is not None - self.styler.table_styles[0]["selector"] = "ti" - assert self.styler.table_styles != s_deepcopy.table_styles - if do_changes: # self.styler.tooltips is not None - tm.assert_frame_equal( - self.styler.tooltips.tt_data, s_deepcopy.tooltips.tt_data - ) - assert ( - self.styler.tooltips.class_properties - == s_deepcopy.tooltips.class_properties - ) - assert self.styler.tooltips.table_styles == s_deepcopy.tooltips.table_styles + assert s_deepcopy._todo == [] + + equal_attributes = [ + "table_styles", + "table_attributes", + "cell_ids", + "hidden_index", + "hidden_columns", + "cell_context", + ] + for s2 in [s_copy, s_deepcopy]: + for att in equal_attributes: + assert self.styler.__dict__[att] == s2.__dict__[att] + if do_changes: # self.styler.tooltips is not None + tm.assert_frame_equal(self.styler.tooltips.tt_data, s2.tooltips.tt_data) + assert ( + self.styler.tooltips.class_properties + == s2.tooltips.class_properties + ) + assert self.styler.tooltips.table_styles == s2.tooltips.table_styles def test_clear(self): # updated in GH 39396