From ed7c1f6d9fc198d555c1389f0f1608396631f565 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Sat, 20 Feb 2021 21:47:51 +0100 Subject: [PATCH 1/5] format multiple selectors --- pandas/io/formats/style.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 877e146fd8681..62811e5ef9a13 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -566,7 +566,7 @@ def _translate(self): "body": body, "uuid": uuid, "precision": precision, - "table_styles": table_styles, + "table_styles": _format_table_styles(table_styles), "caption": caption, "table_attributes": table_attr, } @@ -2077,6 +2077,26 @@ def _maybe_convert_css_to_tuples(style: CSSProperties) -> CSSList: return style +def _format_table_styles(styles: CSSStyles) -> CSSStyles: + """ + looks for multiple CSS selectors and separates them: + [{'selector': 'td, th', 'props': 'a:v;'}] + ---> [{'selector': 'td', 'props': 'a:v;'}, + {'selector': 'th', 'props': 'a:v;'}] + """ + return [ + item + for sublist in [ + [ + {"selector": x, "props": style["props"]} + for x in style["selector"].split(",") + ] + for style in styles + ] + for item in sublist + ] + + def _non_reducing_slice(slice_): """ Ensure that a slice doesn't reduce to a Series or Scalar. From 0db44b89d50899d691e4c07a508aac9d06f2bff3 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Fri, 26 Feb 2021 08:39:44 +0100 Subject: [PATCH 2/5] mypy fix --- pandas/io/formats/style.py | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 62811e5ef9a13..445583266b6b0 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -19,6 +19,7 @@ Sequence, Tuple, Union, + cast, ) from uuid import uuid4 @@ -1904,25 +1905,14 @@ def _pseudo_css(self, uuid: str, name: str, row: int, col: int, text: str): ------- pseudo_css : List """ + selector_id = "#T_" + uuid + "row" + str(row) + "_col" + str(col) return [ { - "selector": "#T_" - + uuid - + "row" - + str(row) - + "_col" - + str(col) - + f":hover .{name}", + "selector": selector_id + f":hover .{name}", "props": [("visibility", "visible")], }, { - "selector": "#T_" - + uuid - + "row" - + str(row) - + "_col" - + str(col) - + f" .{name}::after", + "selector": selector_id + f" .{name}::after", "props": [("content", f'"{text}"')], }, ] @@ -2089,7 +2079,7 @@ def _format_table_styles(styles: CSSStyles) -> CSSStyles: for sublist in [ [ {"selector": x, "props": style["props"]} - for x in style["selector"].split(",") + for x in cast(str, style["selector"]).split(",") ] for style in styles ] From acca24ba944f673c8785dc963f2b7bd2a427b3de Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Fri, 26 Feb 2021 08:50:17 +0100 Subject: [PATCH 3/5] add tests --- pandas/tests/io/formats/style/test_style.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pandas/tests/io/formats/style/test_style.py b/pandas/tests/io/formats/style/test_style.py index 01ed234f6e248..f0d1090899043 100644 --- a/pandas/tests/io/formats/style/test_style.py +++ b/pandas/tests/io/formats/style/test_style.py @@ -626,6 +626,19 @@ def test_table_styles(self): result = " ".join(styler.render().split()) assert "th { foo: bar; }" in result + def test_table_styles_multiple(self): + ctx = self.df.style.set_table_styles( + [ + {"selector": "th,td", "props": "color:red;"}, + {"selector": "tr", "props": "color:green;"}, + ] + )._translate()["table_styles"] + assert ctx == [ + {"selector": "th", "props": [("color", "red")]}, + {"selector": "td", "props": [("color", "red")]}, + {"selector": "tr", "props": [("color", "green")]}, + ] + def test_maybe_convert_css_to_tuples(self): expected = [("a", "b"), ("c", "d e")] assert _maybe_convert_css_to_tuples("a:b;c:d e;") == expected From c3642947f91e6589830b4d9c0432dede284317c7 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Fri, 26 Feb 2021 08:54:11 +0100 Subject: [PATCH 4/5] whats new --- doc/source/whatsnew/v1.3.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 8deeb3cfae1d3..78caa3d0c15de 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -492,6 +492,7 @@ Other - :class:`Styler` rendered HTML output minor alterations to support w3 good code standard (:issue:`39626`) - 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 :class:`Styler` where multiple elements in CSS-selectors were not correctly added to ``table_styles`` (:issue:`39942`) - 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 :func:`pandas.util.show_versions` where console JSON output was not proper JSON (:issue:`39701`) From 2ce85c98e2fe2f9086f4b2c6333b521418b433ed Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (MBP)" Date: Sat, 27 Feb 2021 18:44:20 +0100 Subject: [PATCH 5/5] whats new --- pandas/io/formats/style.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 563e5cf029be0..e50f5986098d3 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -56,7 +56,10 @@ CSSPair = Tuple[str, Union[str, int, float]] CSSList = List[CSSPair] CSSProperties = Union[str, CSSList] -CSSStyles = List[Dict[str, CSSProperties]] +CSSStyles = List[Dict[str, CSSProperties]] # = List[CSSDict] +# class CSSDict(TypedDict): # available when TypedDict is valid in pandas +# selector: str +# props: CSSProperties try: from matplotlib import colors @@ -2077,7 +2080,7 @@ def _format_table_styles(styles: CSSStyles) -> CSSStyles: return [ item for sublist in [ - [ + [ # this is a CSSDict when TypedDict is available to avoid cast. {"selector": x, "props": style["props"]} for x in cast(str, style["selector"]).split(",") ]