Skip to content

Commit ce3e57b

Browse files
authored
BUG: re-render CSS with styler.apply and applymap non-cleared _todo (#39396)
1 parent 421fb8d commit ce3e57b

File tree

3 files changed

+30
-5
lines changed

3 files changed

+30
-5
lines changed

doc/source/whatsnew/v1.3.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ Other
385385
^^^^^
386386
- Bug in :class:`Index` constructor sometimes silently ignorning a specified ``dtype`` (:issue:`38879`)
387387
- Bug in constructing a :class:`Series` from a list and a :class:`PandasDtype` (:issue:`39357`)
388+
- Bug in :class:`Styler` which caused CSS to duplicate on multiple renders. (:issue:`39395`)
388389
-
389390

390391
.. ---------------------------------------------------------------------------

pandas/io/formats/style.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ def _compute(self):
830830
r = self
831831
for func, args, kwargs in self._todo:
832832
r = func(self)(*args, **kwargs)
833+
self._todo = []
833834
return r
834835

835836
def _apply(
@@ -1454,9 +1455,8 @@ def set_properties(self, subset=None, **kwargs) -> Styler:
14541455
>>> df.style.set_properties(color="white", align="right")
14551456
>>> df.style.set_properties(**{'background-color': 'yellow'})
14561457
"""
1457-
values = ";".join(f"{p}: {v}" for p, v in kwargs.items())
1458-
f = lambda x: values
1459-
return self.applymap(f, subset=subset)
1458+
values = "".join(f"{p}: {v};" for p, v in kwargs.items())
1459+
return self.applymap(lambda x: values, subset=subset)
14601460

14611461
@staticmethod
14621462
def _bar(

pandas/tests/io/formats/test_style.py

+26-2
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,27 @@ def test_deepcopy(self):
102102
assert self.styler._todo != s2._todo
103103

104104
def test_clear(self):
105-
s = self.df.style.highlight_max()._compute()
106-
assert len(s.ctx) > 0
105+
# updated in GH 39396
106+
tt = DataFrame({"A": [None, "tt"]})
107+
css = DataFrame({"A": [None, "cls-a"]})
108+
s = self.df.style.highlight_max().set_tooltips(tt).set_td_classes(css)
109+
# _todo, tooltips and cell_context items added to..
107110
assert len(s._todo) > 0
111+
assert s.tooltips
112+
assert len(s.cell_context) > 0
113+
114+
s = s._compute()
115+
# ctx and _todo items affected when a render takes place
116+
assert len(s.ctx) > 0
117+
assert len(s._todo) == 0 # _todo is emptied after compute.
118+
119+
s._todo = [1]
108120
s.clear()
121+
# ctx, _todo, tooltips and cell_context items all revert to null state.
109122
assert len(s.ctx) == 0
110123
assert len(s._todo) == 0
124+
assert not s.tooltips
125+
assert len(s.cell_context) == 0
111126

112127
def test_render(self):
113128
df = DataFrame({"A": [0, 1]})
@@ -116,6 +131,15 @@ def test_render(self):
116131
s.render()
117132
# it worked?
118133

134+
def test_multiple_render(self):
135+
# GH 39396
136+
s = Styler(self.df, uuid_len=0).applymap(lambda x: "color: red;", subset=["A"])
137+
s.render() # do 2 renders to ensure css styles not duplicated
138+
assert (
139+
'<style type="text/css" >\n#T__row0_col0,#T__row1_col0{\n '
140+
"color: red;\n }</style>" in s.render()
141+
)
142+
119143
def test_render_empty_dfs(self):
120144
empty_df = DataFrame()
121145
es = Styler(empty_df)

0 commit comments

Comments
 (0)