from textwrap import dedent import numpy as np import pytest from pandas import ( DataFrame, MultiIndex, ) jinja2 = pytest.importorskip("jinja2") from pandas.io.formats.style import Styler loader = jinja2.PackageLoader("pandas", "io/formats/templates") env = jinja2.Environment(loader=loader, trim_blocks=True) @pytest.fixture def styler(): return Styler(DataFrame([[2.61], [2.69]], index=["a", "b"], columns=["A"])) @pytest.fixture def styler_mi(): midx = MultiIndex.from_product([["a", "b"], ["c", "d"]]) return Styler(DataFrame(np.arange(16).reshape(4, 4), index=midx, columns=midx)) @pytest.fixture def tpl_style(): return env.get_template("html_style.tpl") @pytest.fixture def tpl_table(): return env.get_template("html_table.tpl") @pytest.mark.xfail(reason="--deb-data-root-dir is expected to break this",strict=False) def test_html_template_extends_options(): # make sure if templates are edited tests are updated as are setup fixtures # to understand the dependency with open("pandas/io/formats/templates/html.tpl") as file: result = file.read() assert "{% include html_style_tpl %}" in result assert "{% include html_table_tpl %}" in result def test_exclude_styles(styler): result = styler.to_html(exclude_styles=True, doctype_html=True) expected = dedent( """\
  A
a 2.610000
b 2.690000
""" ) assert result == expected def test_w3_html_format(styler): styler.set_uuid("").set_table_styles( [{"selector": "th", "props": "att2:v2;"}] ).applymap(lambda x: "att1:v1;").set_table_attributes( 'class="my-cls1" style="attr3:v3;"' ).set_td_classes( DataFrame(["my-cls2"], index=["a"], columns=["A"]) ).format( "{:.1f}" ).set_caption( "A comprehensive test" ) expected = dedent( """\
A comprehensive test
  A
a 2.6
b 2.7
""" ) assert expected == styler.render() def test_colspan_w3(): # GH 36223 df = DataFrame(data=[[1, 2]], columns=[["l0", "l0"], ["l1a", "l1b"]]) styler = Styler(df, uuid="_", cell_ids=False) assert 'l0' in styler.render() def test_rowspan_w3(): # GH 38533 df = DataFrame(data=[[1, 2]], index=[["l0", "l0"], ["l1a", "l1b"]]) styler = Styler(df, uuid="_", cell_ids=False) assert ( 'l0' in styler.render() ) def test_styles(styler): styler.set_uuid("abc_") styler.set_table_styles([{"selector": "td", "props": "color: red;"}]) result = styler.to_html(doctype_html=True) expected = dedent( """\
  A
a 2.610000
b 2.690000
""" ) assert result == expected def test_doctype(styler): result = styler.to_html(doctype_html=False) assert "" not in result assert "" not in result assert "" not in result assert "" not in result def test_block_names(tpl_style, tpl_table): # catch accidental removal of a block expected_style = { "before_style", "style", "table_styles", "before_cellstyle", "cellstyle", } expected_table = { "before_table", "table", "caption", "thead", "tbody", "after_table", "before_head_rows", "head_tr", "after_head_rows", "before_rows", "tr", "after_rows", } result1 = set(tpl_style.blocks) assert result1 == expected_style result2 = set(tpl_table.blocks) assert result2 == expected_table def test_from_custom_template_table(tmpdir): p = tmpdir.mkdir("tpl").join("myhtml_table.tpl") p.write( dedent( """\ {% extends "html_table.tpl" %} {% block table %}

{{custom_title}}

{{ super() }} {% endblock table %}""" ) ) result = Styler.from_custom_template(str(tmpdir.join("tpl")), "myhtml_table.tpl") assert issubclass(result, Styler) assert result.env is not Styler.env assert result.template_html_table is not Styler.template_html_table styler = result(DataFrame({"A": [1, 2]})) assert "

My Title

\n\n\n {{ super() }} {% endblock style %}""" ) ) result = Styler.from_custom_template( str(tmpdir.join("tpl")), html_style="myhtml_style.tpl" ) assert issubclass(result, Styler) assert result.env is not Styler.env assert result.template_html_style is not Styler.template_html_style styler = result(DataFrame({"A": [1, 2]})) assert '\n\nfull cap" in styler.render() @pytest.mark.parametrize("index", [False, True]) @pytest.mark.parametrize("columns", [False, True]) @pytest.mark.parametrize("index_name", [True, False]) def test_sticky_basic(styler, index, columns, index_name): if index_name: styler.index.name = "some text" if index: styler.set_sticky(axis=0) if columns: styler.set_sticky(axis=1) left_css = ( "#T_ {0} {{\n position: sticky;\n background-color: white;\n" " left: 0px;\n z-index: {1};\n}}" ) top_css = ( "#T_ {0} {{\n position: sticky;\n background-color: white;\n" " top: {1}px;\n z-index: {2};\n{3}}}" ) res = styler.set_uuid("").to_html() # test index stickys over thead and tbody assert (left_css.format("thead tr th:nth-child(1)", "3 !important") in res) is index assert (left_css.format("tbody tr th:nth-child(1)", "1") in res) is index # test column stickys including if name row assert ( top_css.format("thead tr:nth-child(1) th", "0", "2", " height: 25px;\n") in res ) is (columns and index_name) assert ( top_css.format("thead tr:nth-child(2) th", "25", "2", " height: 25px;\n") in res ) is (columns and index_name) assert (top_css.format("thead tr:nth-child(1) th", "0", "2", "") in res) is ( columns and not index_name ) @pytest.mark.parametrize("index", [False, True]) @pytest.mark.parametrize("columns", [False, True]) def test_sticky_mi(styler_mi, index, columns): if index: styler_mi.set_sticky(axis=0) if columns: styler_mi.set_sticky(axis=1) left_css = ( "#T_ {0} {{\n position: sticky;\n background-color: white;\n" " left: {1}px;\n min-width: 75px;\n max-width: 75px;\n z-index: {2};\n}}" ) top_css = ( "#T_ {0} {{\n position: sticky;\n background-color: white;\n" " top: {1}px;\n height: 25px;\n z-index: {2};\n}}" ) res = styler_mi.set_uuid("").to_html() # test the index stickys for thead and tbody over both levels assert ( left_css.format("thead tr th:nth-child(1)", "0", "3 !important") in res ) is index assert (left_css.format("tbody tr th.level0", "0", "1") in res) is index assert ( left_css.format("thead tr th:nth-child(2)", "75", "3 !important") in res ) is index assert (left_css.format("tbody tr th.level1", "75", "1") in res) is index # test the column stickys for each level row assert (top_css.format("thead tr:nth-child(1) th", "0", "2") in res) is columns assert (top_css.format("thead tr:nth-child(2) th", "25", "2") in res) is columns @pytest.mark.parametrize("index", [False, True]) @pytest.mark.parametrize("columns", [False, True]) def test_sticky_levels(styler_mi, index, columns): if index: styler_mi.set_sticky(axis=0, levels=[1]) if columns: styler_mi.set_sticky(axis=1, levels=[1]) left_css = ( "#T_ {0} {{\n position: sticky;\n background-color: white;\n" " left: {1}px;\n min-width: 75px;\n max-width: 75px;\n z-index: {2};\n}}" ) top_css = ( "#T_ {0} {{\n position: sticky;\n background-color: white;\n" " top: {1}px;\n height: 25px;\n z-index: {2};\n}}" ) res = styler_mi.set_uuid("").to_html() # test no sticking of level0 assert "#T_ thead tr th:nth-child(1)" not in res assert "#T_ tbody tr th.level0" not in res assert "#T_ thead tr:nth-child(1) th" not in res # test sticking level1 assert ( left_css.format("thead tr th:nth-child(2)", "0", "3 !important") in res ) is index assert (left_css.format("tbody tr th.level1", "0", "1") in res) is index assert (top_css.format("thead tr:nth-child(2) th", "0", "2") in res) is columns def test_sticky_raises(styler): with pytest.raises(ValueError, match="`axis` must be"): styler.set_sticky(axis="bad")