Skip to content

Commit 31f68a0

Browse files
authored
BUG: format multiple CSS selectors correctly (#39942)
1 parent 0f9adcd commit 31f68a0

File tree

3 files changed

+43
-16
lines changed

3 files changed

+43
-16
lines changed

doc/source/whatsnew/v1.3.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ Other
561561
- :class:`Styler` rendered HTML output minor alterations to support w3 good code standard (:issue:`39626`)
562562
- Bug in :class:`Styler` where rendered HTML was missing a column class identifier for certain header cells (:issue:`39716`)
563563
- Bug in :meth:`Styler.background_gradient` where text-color was not determined correctly (:issue:`39888`)
564+
- Bug in :class:`Styler` where multiple elements in CSS-selectors were not correctly added to ``table_styles`` (:issue:`39942`)
564565
- Bug in :meth:`DataFrame.equals`, :meth:`Series.equals`, :meth:`Index.equals` with object-dtype containing ``np.datetime64("NaT")`` or ``np.timedelta64("NaT")`` (:issue:`39650`)
565566
- Bug in :func:`pandas.util.show_versions` where console JSON output was not proper JSON (:issue:`39701`)
566567

pandas/io/formats/style.py

+29-16
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
Sequence,
2020
Tuple,
2121
Union,
22+
cast,
2223
)
2324
from uuid import uuid4
2425

@@ -55,7 +56,10 @@
5556
CSSPair = Tuple[str, Union[str, int, float]]
5657
CSSList = List[CSSPair]
5758
CSSProperties = Union[str, CSSList]
58-
CSSStyles = List[Dict[str, CSSProperties]]
59+
CSSStyles = List[Dict[str, CSSProperties]] # = List[CSSDict]
60+
# class CSSDict(TypedDict): # available when TypedDict is valid in pandas
61+
# selector: str
62+
# props: CSSProperties
5963

6064
try:
6165
from matplotlib import colors
@@ -566,7 +570,7 @@ def _translate(self):
566570
"body": body,
567571
"uuid": uuid,
568572
"precision": precision,
569-
"table_styles": table_styles,
573+
"table_styles": _format_table_styles(table_styles),
570574
"caption": caption,
571575
"table_attributes": table_attr,
572576
}
@@ -1904,25 +1908,14 @@ def _pseudo_css(self, uuid: str, name: str, row: int, col: int, text: str):
19041908
-------
19051909
pseudo_css : List
19061910
"""
1911+
selector_id = "#T_" + uuid + "row" + str(row) + "_col" + str(col)
19071912
return [
19081913
{
1909-
"selector": "#T_"
1910-
+ uuid
1911-
+ "row"
1912-
+ str(row)
1913-
+ "_col"
1914-
+ str(col)
1915-
+ f":hover .{name}",
1914+
"selector": selector_id + f":hover .{name}",
19161915
"props": [("visibility", "visible")],
19171916
},
19181917
{
1919-
"selector": "#T_"
1920-
+ uuid
1921-
+ "row"
1922-
+ str(row)
1923-
+ "_col"
1924-
+ str(col)
1925-
+ f" .{name}::after",
1918+
"selector": selector_id + f" .{name}::after",
19261919
"props": [("content", f'"{text}"')],
19271920
},
19281921
]
@@ -2077,6 +2070,26 @@ def _maybe_convert_css_to_tuples(style: CSSProperties) -> CSSList:
20772070
return style
20782071

20792072

2073+
def _format_table_styles(styles: CSSStyles) -> CSSStyles:
2074+
"""
2075+
looks for multiple CSS selectors and separates them:
2076+
[{'selector': 'td, th', 'props': 'a:v;'}]
2077+
---> [{'selector': 'td', 'props': 'a:v;'},
2078+
{'selector': 'th', 'props': 'a:v;'}]
2079+
"""
2080+
return [
2081+
item
2082+
for sublist in [
2083+
[ # this is a CSSDict when TypedDict is available to avoid cast.
2084+
{"selector": x, "props": style["props"]}
2085+
for x in cast(str, style["selector"]).split(",")
2086+
]
2087+
for style in styles
2088+
]
2089+
for item in sublist
2090+
]
2091+
2092+
20802093
def _non_reducing_slice(slice_):
20812094
"""
20822095
Ensure that a slice doesn't reduce to a Series or Scalar.

pandas/tests/io/formats/style/test_style.py

+13
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,19 @@ def test_table_styles(self):
626626
result = " ".join(styler.render().split())
627627
assert "th { foo: bar; }" in result
628628

629+
def test_table_styles_multiple(self):
630+
ctx = self.df.style.set_table_styles(
631+
[
632+
{"selector": "th,td", "props": "color:red;"},
633+
{"selector": "tr", "props": "color:green;"},
634+
]
635+
)._translate()["table_styles"]
636+
assert ctx == [
637+
{"selector": "th", "props": [("color", "red")]},
638+
{"selector": "td", "props": [("color", "red")]},
639+
{"selector": "tr", "props": [("color", "green")]},
640+
]
641+
629642
def test_maybe_convert_css_to_tuples(self):
630643
expected = [("a", "b"), ("c", "d e")]
631644
assert _maybe_convert_css_to_tuples("a:b;c:d e;") == expected

0 commit comments

Comments
 (0)