@@ -38,6 +38,35 @@ def mi_styler(mi_df):
3838 return Styler (mi_df , uuid_len = 0 )
3939
4040
41+ @pytest .fixture
42+ def mi_styler_comp (mi_styler ):
43+ # comprehensively add features to mi_styler
44+ mi_styler .uuid_len = 5
45+ mi_styler .uuid = "abcde_"
46+ mi_styler .set_caption ("capt" )
47+ mi_styler .set_table_styles ([{"selector" : "a" , "props" : "a:v;" }])
48+ mi_styler .hide_columns ()
49+ mi_styler .hide_columns ([("c0" , "c1_a" )])
50+ mi_styler .hide_index ()
51+ mi_styler .hide_index ([("i0" , "i1_a" )])
52+ mi_styler .set_table_attributes ('class="box"' )
53+ mi_styler .format (na_rep = "MISSING" , precision = 3 )
54+ mi_styler .highlight_max (axis = None )
55+ mi_styler .set_td_classes (
56+ DataFrame (
57+ [["a" , "b" ], ["a" , "c" ]], index = mi_styler .index , columns = mi_styler .columns
58+ )
59+ )
60+ mi_styler .set_tooltips (
61+ DataFrame (
62+ [["a2" , "b2" ], ["a2" , "c2" ]],
63+ index = mi_styler .index ,
64+ columns = mi_styler .columns ,
65+ )
66+ )
67+ return mi_styler
68+
69+
4170@pytest .mark .parametrize (
4271 "sparse_columns, exp_cols" ,
4372 [
@@ -156,6 +185,49 @@ def test_render_trimming_mi():
156185 assert {"attributes" : 'colspan="2"' }.items () <= ctx ["head" ][0 ][2 ].items ()
157186
158187
188+ @pytest .mark .parametrize ("comprehensive" , [True , False ])
189+ @pytest .mark .parametrize ("render" , [True , False ])
190+ @pytest .mark .parametrize ("deepcopy" , [True , False ])
191+ def test_copy (comprehensive , render , deepcopy , mi_styler , mi_styler_comp ):
192+ styler = mi_styler_comp if comprehensive else mi_styler
193+ styler .uuid_len = 5
194+
195+ s2 = copy .deepcopy (styler ) if deepcopy else copy .copy (styler ) # make copy and check
196+ assert s2 is not styler
197+
198+ if render :
199+ styler .to_html ()
200+
201+ excl = ["na_rep" , "precision" , "uuid" , "cellstyle_map" ] # deprecated or special var
202+ if not deepcopy : # check memory locations are equal for all included attributes
203+ for attr in [a for a in styler .__dict__ if (not callable (a ) and a not in excl )]:
204+ assert id (getattr (s2 , attr )) == id (getattr (styler , attr ))
205+ else : # check memory locations are different for nested or mutable vars
206+ shallow = [
207+ "data" ,
208+ "columns" ,
209+ "index" ,
210+ "uuid_len" ,
211+ "caption" ,
212+ "cell_ids" ,
213+ "hide_index_" ,
214+ "hide_columns_" ,
215+ "table_attributes" ,
216+ ]
217+ for attr in shallow :
218+ assert id (getattr (s2 , attr )) == id (getattr (styler , attr ))
219+
220+ for attr in [
221+ a
222+ for a in styler .__dict__
223+ if (not callable (a ) and a not in excl and a not in shallow )
224+ ]:
225+ if getattr (s2 , attr ) is None :
226+ assert id (getattr (s2 , attr )) == id (getattr (styler , attr ))
227+ else :
228+ assert id (getattr (s2 , attr )) != id (getattr (styler , attr ))
229+
230+
159231class TestStyler :
160232 def setup_method (self , method ):
161233 np .random .seed (24 )
@@ -211,102 +283,6 @@ def test_update_ctx_flatten_multi_and_trailing_semi(self):
211283 }
212284 assert self .styler .ctx == expected
213285
214- @pytest .mark .parametrize ("do_changes" , [True , False ])
215- @pytest .mark .parametrize ("do_render" , [True , False ])
216- def test_copy (self , do_changes , do_render ):
217- # Updated in GH39708
218- # Change some defaults (to check later if the new values are copied)
219- if do_changes :
220- self .styler .set_table_styles (
221- [{"selector" : "th" , "props" : [("foo" , "bar" )]}]
222- )
223- self .styler .set_table_attributes ('class="foo" data-bar' )
224- self .styler .hide_index_ = not self .styler .hide_index_
225- self .styler .hide_columns ("A" )
226- classes = DataFrame (
227- [["favorite-val red" , "" ], [None , "blue my-val" ]],
228- index = self .df .index ,
229- columns = self .df .columns ,
230- )
231- self .styler .set_td_classes (classes )
232- ttips = DataFrame (
233- data = [["Favorite" , "" ], [np .nan , "my" ]],
234- columns = self .df .columns ,
235- index = self .df .index ,
236- )
237- self .styler .set_tooltips (ttips )
238- self .styler .cell_ids = not self .styler .cell_ids
239-
240- if do_render :
241- self .styler .render ()
242-
243- s_copy = copy .copy (self .styler )
244- s_deepcopy = copy .deepcopy (self .styler )
245-
246- assert self .styler is not s_copy
247- assert self .styler is not s_deepcopy
248-
249- # Check for identity
250- assert self .styler .ctx is s_copy .ctx
251- assert self .styler ._todo is s_copy ._todo
252- assert self .styler .table_styles is s_copy .table_styles
253- assert self .styler .hidden_columns is s_copy .hidden_columns
254- assert self .styler .cell_context is s_copy .cell_context
255- assert self .styler .tooltips is s_copy .tooltips
256- if do_changes : # self.styler.tooltips is not None
257- assert self .styler .tooltips .tt_data is s_copy .tooltips .tt_data
258- assert (
259- self .styler .tooltips .class_properties
260- is s_copy .tooltips .class_properties
261- )
262- assert self .styler .tooltips .table_styles is s_copy .tooltips .table_styles
263-
264- # Check for non-identity
265- assert self .styler .ctx is not s_deepcopy .ctx
266- assert self .styler ._todo is not s_deepcopy ._todo
267- assert self .styler .hidden_columns is not s_deepcopy .hidden_columns
268- assert self .styler .cell_context is not s_deepcopy .cell_context
269- if do_changes : # self.styler.table_style is not None
270- assert self .styler .table_styles is not s_deepcopy .table_styles
271- if do_changes : # self.styler.tooltips is not None
272- assert self .styler .tooltips is not s_deepcopy .tooltips
273- assert self .styler .tooltips .tt_data is not s_deepcopy .tooltips .tt_data
274- assert (
275- self .styler .tooltips .class_properties
276- is not s_deepcopy .tooltips .class_properties
277- )
278- assert (
279- self .styler .tooltips .table_styles
280- is not s_deepcopy .tooltips .table_styles
281- )
282-
283- self .styler ._update_ctx (self .attrs )
284- self .styler .highlight_max ()
285- assert self .styler .ctx == s_copy .ctx
286- assert self .styler .ctx != s_deepcopy .ctx
287- assert self .styler ._todo == s_copy ._todo
288- assert self .styler ._todo != s_deepcopy ._todo
289- assert s_deepcopy ._todo == []
290-
291- equal_attributes = [
292- "table_styles" ,
293- "table_attributes" ,
294- "cell_ids" ,
295- "hide_index_" ,
296- "hidden_columns" ,
297- "cell_context" ,
298- ]
299- for s2 in [s_copy , s_deepcopy ]:
300- for att in equal_attributes :
301- assert self .styler .__dict__ [att ] == s2 .__dict__ [att ]
302- if do_changes : # self.styler.tooltips is not None
303- tm .assert_frame_equal (self .styler .tooltips .tt_data , s2 .tooltips .tt_data )
304- assert (
305- self .styler .tooltips .class_properties
306- == s2 .tooltips .class_properties
307- )
308- assert self .styler .tooltips .table_styles == s2 .tooltips .table_styles
309-
310286 def test_clear (self ):
311287 # updated in GH 39396
312288 tt = DataFrame ({"A" : [None , "tt" ]})
0 commit comments