From 2fa2246bd8fdb83722d66c8c627c81473b0650a2 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Fri, 12 Nov 2021 18:18:25 +0100 Subject: [PATCH 01/24] add warning --- pandas/core/generic.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 23608cf0192df..a4dfa850be4e2 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -3278,6 +3278,15 @@ def to_latex( \bottomrule \end{{tabular}} """ + msg = ( + "In future versions `DataFrame.to_latex` is expected to utilise the base " + "implementation of `Styler.to_latex` for formatting and rendering. " + "The arguments signature may therefore change. It is recommended instead to" + "use `DataFrame.style.to_latex` which also contains additional " + "functionality." + ) + warnings.warn(msg, FutureWarning, stacklevel=2) + # Get defaults from the pandas config if self.ndim == 1: self = self.to_frame() From 89225de96196858a764c05cb0e203d8efe55f39e Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Fri, 12 Nov 2021 18:23:07 +0100 Subject: [PATCH 02/24] add test --- pandas/tests/io/formats/test_to_latex.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pandas/tests/io/formats/test_to_latex.py b/pandas/tests/io/formats/test_to_latex.py index 10c8ccae67fb2..b1cf9cbe8867d 100644 --- a/pandas/tests/io/formats/test_to_latex.py +++ b/pandas/tests/io/formats/test_to_latex.py @@ -1514,3 +1514,15 @@ def test_get_strrow_multindex_multicolumn(self, row_num, expected): ) assert row_string_converter.get_strrow(row_num=row_num) == expected + + def test_future_warning(self): + df = DataFrame([[1]]) + msg = ( + "In future versions `DataFrame.to_latex` is expected to utilise the base " + "implementation of `Styler.to_latex` for formatting and rendering. " + "The arguments signature may therefore change. It is recommended instead to" + "use `DataFrame.style.to_latex` which also contains additional " + "functionality." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + df.to_latex() From 1119a27b6d83279952fbbc98292d2bdabe7482b6 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Fri, 12 Nov 2021 20:28:37 +0100 Subject: [PATCH 03/24] fix doc warnings --- doc/source/whatsnew/v1.2.0.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 36b591c3c3142..3d3ec53948a01 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -150,6 +150,7 @@ and a short caption (:issue:`36267`). The keyword ``position`` has been added to set the position. .. ipython:: python + :okwarning: data = pd.DataFrame({'a': [1, 2], 'b': [3, 4]}) table = data.to_latex(position='ht') @@ -161,6 +162,7 @@ one can optionally provide a tuple ``(full_caption, short_caption)`` to add a short caption macro. .. ipython:: python + :okwarning: data = pd.DataFrame({'a': [1, 2], 'b': [3, 4]}) table = data.to_latex(caption=('the full long caption', 'short caption')) From 93d92887e329e37c69769e375965b53b67bd6ce3 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Fri, 12 Nov 2021 22:47:25 +0100 Subject: [PATCH 04/24] fix test for warning --- pandas/tests/io/formats/test_format.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/tests/io/formats/test_format.py b/pandas/tests/io/formats/test_format.py index d9bd8f6809c73..af62e2872997b 100644 --- a/pandas/tests/io/formats/test_format.py +++ b/pandas/tests/io/formats/test_format.py @@ -3319,7 +3319,8 @@ def test_filepath_or_buffer_arg( ): getattr(df, method)(buf=filepath_or_buffer, encoding=encoding) elif encoding == "foo": - with tm.assert_produces_warning(None): + expected_warning = FutureWarning if method == "to_latex" else None + with tm.assert_produces_warning(expected_warning): with pytest.raises(LookupError, match="unknown encoding"): getattr(df, method)(buf=filepath_or_buffer, encoding=encoding) else: From 2e653fec05c338f359bc1b04751363c34f52575e Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Sat, 13 Nov 2021 08:53:37 +0100 Subject: [PATCH 05/24] filterwarnings --- pandas/tests/io/formats/test_format.py | 2 ++ pandas/tests/io/formats/test_to_latex.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/pandas/tests/io/formats/test_format.py b/pandas/tests/io/formats/test_format.py index af62e2872997b..3d8578833fd7c 100644 --- a/pandas/tests/io/formats/test_format.py +++ b/pandas/tests/io/formats/test_format.py @@ -3298,6 +3298,7 @@ def test_repr_html_ipython_config(ip): assert not result.error_in_exec +@pytest.mark.filterwarnings("ignore::FutureWarning") @pytest.mark.parametrize("method", ["to_string", "to_html", "to_latex"]) @pytest.mark.parametrize( "encoding, data", @@ -3329,6 +3330,7 @@ def test_filepath_or_buffer_arg( assert_filepath_or_buffer_equals(expected) +@pytest.mark.filterwarnings("ignore::FutureWarning") @pytest.mark.parametrize("method", ["to_string", "to_html", "to_latex"]) def test_filepath_or_buffer_bad_arg_raises(float_frame, method): msg = "buf is not a file name and it has no write method" diff --git a/pandas/tests/io/formats/test_to_latex.py b/pandas/tests/io/formats/test_to_latex.py index b1cf9cbe8867d..bc672eeb80d3d 100644 --- a/pandas/tests/io/formats/test_to_latex.py +++ b/pandas/tests/io/formats/test_to_latex.py @@ -19,6 +19,8 @@ RowStringConverter, ) +pytestmark = pytest.mark.filterwarnings("ignore::FutureWarning") + def _dedent(string): """Dedent without new line in the beginning. From 8e10574203af062551298769f2ec761009e6bb28 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Sat, 13 Nov 2021 12:04:31 +0100 Subject: [PATCH 06/24] skip doctest --- pandas/core/generic.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index a4dfa850be4e2..62798a5dc5d31 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -3259,6 +3259,7 @@ def to_latex( {returns} See Also -------- + Styler.to_latex : Render a DataFrame to LaTeX with conditional formatting. DataFrame.to_string : Render a DataFrame to a console-friendly tabular output. DataFrame.to_html : Render a DataFrame as an HTML table. @@ -3268,7 +3269,7 @@ def to_latex( >>> df = pd.DataFrame(dict(name=['Raphael', 'Donatello'], ... mask=['red', 'purple'], ... weapon=['sai', 'bo staff'])) - >>> print(df.to_latex(index=False)) # doctest: +NORMALIZE_WHITESPACE + >>> print(df.to_latex(index=False)) # doctest: +SKIP \begin{{tabular}}{{lll}} \toprule name & mask & weapon \\ From e4fa4ef246f5a53a50ad7fd4ac13a3f93bf85544 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Sat, 13 Nov 2021 19:50:45 +0100 Subject: [PATCH 07/24] test warnings --- pandas/core/generic.py | 2 +- pandas/tests/frame/test_repr_info.py | 1 + pandas/tests/io/test_common.py | 1 + pandas/tests/series/test_repr.py | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 62798a5dc5d31..4ffcd68cd517a 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -3286,7 +3286,7 @@ def to_latex( "use `DataFrame.style.to_latex` which also contains additional " "functionality." ) - warnings.warn(msg, FutureWarning, stacklevel=2) + warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) # Get defaults from the pandas config if self.ndim == 1: diff --git a/pandas/tests/frame/test_repr_info.py b/pandas/tests/frame/test_repr_info.py index b288fafd8f7f6..bb80bd12c1958 100644 --- a/pandas/tests/frame/test_repr_info.py +++ b/pandas/tests/frame/test_repr_info.py @@ -265,6 +265,7 @@ def test_repr_column_name_unicode_truncation_bug(self): with option_context("display.max_columns", 20): assert "StringCol" in repr(df) + @pytest.mark.filterwarnings("ignore::FutureWarning") def test_latex_repr(self): result = r"""\begin{tabular}{llll} \toprule diff --git a/pandas/tests/io/test_common.py b/pandas/tests/io/test_common.py index 699459ab3666d..19735702c2fbe 100644 --- a/pandas/tests/io/test_common.py +++ b/pandas/tests/io/test_common.py @@ -348,6 +348,7 @@ def test_read_fspath_all(self, reader, module, path, datapath): else: tm.assert_frame_equal(result, expected) + @pytest.mark.filterwarnings("ignore:In future versions `DataFrame.to_latex`") @pytest.mark.parametrize( "writer_name, writer_kwargs, module", [ diff --git a/pandas/tests/series/test_repr.py b/pandas/tests/series/test_repr.py index 555342dd39005..73159bda02226 100644 --- a/pandas/tests/series/test_repr.py +++ b/pandas/tests/series/test_repr.py @@ -196,6 +196,7 @@ def test_timeseries_repr_object_dtype(self): ts2 = ts.iloc[np.random.randint(0, len(ts) - 1, 400)] repr(ts2).splitlines()[-1] + @pytest.mark.filterwarnings("ignore::FutureWarning") def test_latex_repr(self): result = r"""\begin{tabular}{ll} \toprule From e20c5d98becda94d02a3ed90bfb28224b2239e1d Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Sat, 13 Nov 2021 19:53:11 +0100 Subject: [PATCH 08/24] test warnings --- pandas/tests/io/formats/test_format.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/io/formats/test_format.py b/pandas/tests/io/formats/test_format.py index 3d8578833fd7c..ab0199dca3f24 100644 --- a/pandas/tests/io/formats/test_format.py +++ b/pandas/tests/io/formats/test_format.py @@ -3298,7 +3298,7 @@ def test_repr_html_ipython_config(ip): assert not result.error_in_exec -@pytest.mark.filterwarnings("ignore::FutureWarning") +@pytest.mark.filterwarnings("ignore:In future versions `DataFrame.to_latex`") @pytest.mark.parametrize("method", ["to_string", "to_html", "to_latex"]) @pytest.mark.parametrize( "encoding, data", From 310bdc2fa099599bbb57e4291847a53a02cbd06a Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Sun, 14 Nov 2021 18:48:15 +0100 Subject: [PATCH 09/24] warn and expand tests --- pandas/core/frame.py | 9 +++++++++ pandas/tests/io/formats/test_format.py | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index b88c97b8e988d..015aafc2766a5 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2855,6 +2855,15 @@ def to_html( -------- to_string : Convert DataFrame to a string. """ + msg = ( + "In future versions `DataFrame.to_html` is expected to utilise the base " + "implementation of `Styler.to_html` for formatting and rendering. " + "The arguments signature may therefore change. It is recommended instead " + "to use `DataFrame.style.to_html` which also contains additional " + "functionality." + ) + warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + if justify is not None and justify not in fmt._VALID_JUSTIFY_PARAMETERS: raise ValueError("Invalid value for justify parameter") diff --git a/pandas/tests/io/formats/test_format.py b/pandas/tests/io/formats/test_format.py index ab0199dca3f24..09135637910c7 100644 --- a/pandas/tests/io/formats/test_format.py +++ b/pandas/tests/io/formats/test_format.py @@ -3299,6 +3299,7 @@ def test_repr_html_ipython_config(ip): @pytest.mark.filterwarnings("ignore:In future versions `DataFrame.to_latex`") +@pytest.mark.filterwarnings("ignore:In future versions `DataFrame.to_html`") @pytest.mark.parametrize("method", ["to_string", "to_html", "to_latex"]) @pytest.mark.parametrize( "encoding, data", @@ -3320,7 +3321,7 @@ def test_filepath_or_buffer_arg( ): getattr(df, method)(buf=filepath_or_buffer, encoding=encoding) elif encoding == "foo": - expected_warning = FutureWarning if method == "to_latex" else None + expected_warning = FutureWarning if method in ["to_latex", "to_html"] else None with tm.assert_produces_warning(expected_warning): with pytest.raises(LookupError, match="unknown encoding"): getattr(df, method)(buf=filepath_or_buffer, encoding=encoding) From 35241165f4a590f270333eae92561d8758a82c31 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Sun, 14 Nov 2021 19:39:37 +0100 Subject: [PATCH 10/24] see also --- pandas/core/frame.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 015aafc2766a5..618e118d8aa40 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2853,6 +2853,7 @@ def to_html( %(returns)s See Also -------- + Styler.to_html : Render a DataFrame to HTML with conditional formatting. to_string : Convert DataFrame to a string. """ msg = ( From f41a4383902aadab5610002b5bd84b04ae851abf Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Wed, 24 Nov 2021 18:56:14 +0100 Subject: [PATCH 11/24] allow warnings in io.rst --- doc/source/user_guide/io.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index 8c8469b93db68..aad3fe4f0443d 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -2631,6 +2631,7 @@ Use some combination of the above: Read in pandas ``to_html`` output (with some loss of floating point precision): .. code-block:: python + :okwarning: df = pd.DataFrame(np.random.randn(2, 2)) s = df.to_html(float_format="{0:.40g}".format) @@ -2677,6 +2678,7 @@ in the method ``to_string`` described above. .. ipython:: python :suppress: + :okwarning: def write_html(df, filename, *args, **kwargs): static = os.path.abspath(os.path.join("source", "_static")) @@ -2684,6 +2686,7 @@ in the method ``to_string`` described above. df.to_html(f, *args, **kwargs) .. ipython:: python + :okwarning: df = pd.DataFrame(np.random.randn(2, 2)) df @@ -2702,6 +2705,7 @@ HTML: The ``columns`` argument will limit the columns shown: .. ipython:: python + :okwarning: print(df.to_html(columns=[0])) @@ -2719,6 +2723,7 @@ HTML: point values: .. ipython:: python + :okwarning: print(df.to_html(float_format="{0:.10f}".format)) @@ -2736,6 +2741,7 @@ HTML: off: .. ipython:: python + :okwarning: print(df.to_html(bold_rows=False)) @@ -2752,6 +2758,7 @@ table CSS classes. Note that these classes are *appended* to the existing ``'dataframe'`` class. .. ipython:: python + :okwarning: print(df.to_html(classes=["awesome_table_class", "even_more_awesome_class"])) @@ -2759,6 +2766,7 @@ The ``render_links`` argument provides the ability to add hyperlinks to cells that contain URLs. .. ipython:: python + :okwarning: url_df = pd.DataFrame( { From ad8cf245edea8abc60d27b244bb5aadbb8e23a13 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Wed, 24 Nov 2021 18:59:23 +0100 Subject: [PATCH 12/24] allow warnings in scale.rst --- doc/source/user_guide/scale.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/source/user_guide/scale.rst b/doc/source/user_guide/scale.rst index 71aef4fdd75f6..edeebe2e8678c 100644 --- a/doc/source/user_guide/scale.rst +++ b/doc/source/user_guide/scale.rst @@ -275,6 +275,7 @@ column names and dtypes. That's because Dask hasn't actually read the data yet. Rather than executing immediately, doing operations build up a **task graph**. .. ipython:: python + :okwarning: ddf ddf["name"] @@ -333,6 +334,7 @@ known automatically. In this case, since we created the parquet files manually, we need to supply the divisions manually. .. ipython:: python + :okwarning: N = 12 starts = [f"20{i:>02d}-01-01" for i in range(N)] From 0d5b4b381cddab705c227b84b5111f82b7f0582a Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Wed, 24 Nov 2021 20:09:03 +0100 Subject: [PATCH 13/24] aedit io.rst --- doc/source/user_guide/io.rst | 159 ++++------------------------------- 1 file changed, 15 insertions(+), 144 deletions(-) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index aad3fe4f0443d..d2d539b216cf8 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -21,7 +21,7 @@ The pandas I/O API is a set of top level ``reader`` functions accessed like text;`CSV `__;:ref:`read_csv`;:ref:`to_csv` text;Fixed-Width Text File;:ref:`read_fwf` text;`JSON `__;:ref:`read_json`;:ref:`to_json` - text;`HTML `__;:ref:`read_html`;:ref:`to_html` + text;`HTML `__;:ref:`read_html`;:ref:`Styler.to_html` text;`LaTeX `__;;:ref:`Styler.to_latex` text;`XML `__;:ref:`read_xml`;:ref:`to_xml` text; Local clipboard;:ref:`read_clipboard`;:ref:`to_clipboard` @@ -2666,163 +2666,34 @@ succeeds, the function will return*. Writing to HTML files '''''''''''''''''''''' -``DataFrame`` objects have an instance method ``to_html`` which renders the -contents of the ``DataFrame`` as an HTML table. The function arguments are as -in the method ``to_string`` described above. - .. note:: - Not all of the possible options for ``DataFrame.to_html`` are shown here for - brevity's sake. See :func:`~pandas.core.frame.DataFrame.to_html` for the - full set of options. + DataFrame *and* Styler objects currently have a ``to_html`` method. We recommend + using the `Styler.to_html() <../reference/api/pandas.io.formats.style.Styler.to_html.rst>`__ method + over `DataFrame.to_html() <../reference/api/pandas.DataFrame.to_html.rst>`__ due to the former's greater flexibility with + conditional styling, and the latter's possible future deprecation. -.. ipython:: python - :suppress: - :okwarning: +Review the documentation for `Styler.to_html <../reference/api/pandas.io.formats.style.Styler.to_html.rst>`__, +which gives examples of conditional styling and explains the operation of its keyword +arguments. The ``to_html`` methods render the contents of the ``DataFrame`` as an HTML table. - def write_html(df, filename, *args, **kwargs): - static = os.path.abspath(os.path.join("source", "_static")) - with open(os.path.join(static, filename + ".html"), "w") as f: - df.to_html(f, *args, **kwargs) +For simple application the following pattern is sufficient: .. ipython:: python - :okwarning: df = pd.DataFrame(np.random.randn(2, 2)) df - print(df.to_html()) # raw html - -.. ipython:: python - :suppress: - - write_html(df, "basic") - -HTML: - -.. raw:: html - :file: ../_static/basic.html - -The ``columns`` argument will limit the columns shown: - -.. ipython:: python - :okwarning: - - print(df.to_html(columns=[0])) - -.. ipython:: python - :suppress: + print(df.style.to_html()) # raw html - write_html(df, "columns", columns=[0]) - -HTML: - -.. raw:: html - :file: ../_static/columns.html - -``float_format`` takes a Python callable to control the precision of floating -point values: - -.. ipython:: python - :okwarning: - - print(df.to_html(float_format="{0:.10f}".format)) - -.. ipython:: python - :suppress: - - write_html(df, "float_format", float_format="{0:.10f}".format) - -HTML: - -.. raw:: html - :file: ../_static/float_format.html - -``bold_rows`` will make the row labels bold by default, but you can turn that -off: - -.. ipython:: python - :okwarning: - - print(df.to_html(bold_rows=False)) - -.. ipython:: python - :suppress: - - write_html(df, "nobold", bold_rows=False) - -.. raw:: html - :file: ../_static/nobold.html - -The ``classes`` argument provides the ability to give the resulting HTML -table CSS classes. Note that these classes are *appended* to the existing -``'dataframe'`` class. - -.. ipython:: python - :okwarning: - - print(df.to_html(classes=["awesome_table_class", "even_more_awesome_class"])) - -The ``render_links`` argument provides the ability to add hyperlinks to cells -that contain URLs. - -.. ipython:: python - :okwarning: - - url_df = pd.DataFrame( - { - "name": ["Python", "pandas"], - "url": ["https://www.python.org/", "https://pandas.pydata.org"], - } - ) - print(url_df.to_html(render_links=True)) - -.. ipython:: python - :suppress: - - write_html(url_df, "render_links", render_links=True) - -HTML: - -.. raw:: html - :file: ../_static/render_links.html - -Finally, the ``escape`` argument allows you to control whether the -"<", ">" and "&" characters escaped in the resulting HTML (by default it is -``True``). So to get the HTML without escaped characters pass ``escape=False`` - -.. ipython:: python - - df = pd.DataFrame({"a": list("&<>"), "b": np.random.randn(3)}) - - -.. ipython:: python - :suppress: - - write_html(df, "escape") - write_html(df, "noescape", escape=False) - -Escaped: - -.. ipython:: python - - print(df.to_html()) - -.. raw:: html - :file: ../_static/escape.html - -Not escaped: +To format values before output, chain the `Styler.format <../reference/api/pandas.io.formats.style.Styler.format.rst>`__ +method. .. ipython:: python - print(df.to_html(escape=False)) - -.. raw:: html - :file: ../_static/noescape.html - -.. note:: + print(df.style.format("€ {}").to_html()) - Some browsers may not show a difference in the rendering of the previous two - HTML tables. +Some browsers or browser applications may process and add css class styling by default to alter the appearance +of HTML tables, such as Jupyter Notebook and Google Colab. .. _io.html.gotchas: From bd5e91c79cb69c4cbb461de43df684d7b6e444d5 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Wed, 24 Nov 2021 20:29:28 +0100 Subject: [PATCH 14/24] aedit io.rst --- doc/source/user_guide/io.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index d2d539b216cf8..83bf2456cafd9 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -2634,8 +2634,8 @@ Read in pandas ``to_html`` output (with some loss of floating point precision): :okwarning: df = pd.DataFrame(np.random.randn(2, 2)) - s = df.to_html(float_format="{0:.40g}".format) - dfin = pd.read_html(s, index_col=0) + s = df.style.format("{0:.40g}").to_html() + dfin = pd.read_html(s, index_col=0)[0] The ``lxml`` backend will raise an error on a failed parse if that is the only parser you provide. If you only have a single parser you can provide just a From 7e3c3dfd99d11ef2fcdb94988568536fa6a7a837 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Thu, 25 Nov 2021 18:19:17 +0100 Subject: [PATCH 15/24] test warnings --- pandas/tests/io/formats/test_to_html.py | 2 ++ pandas/tests/io/test_common.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/pandas/tests/io/formats/test_to_html.py b/pandas/tests/io/formats/test_to_html.py index a61e77bec9828..f7a459bc0f95c 100644 --- a/pandas/tests/io/formats/test_to_html.py +++ b/pandas/tests/io/formats/test_to_html.py @@ -16,6 +16,8 @@ import pandas.io.formats.format as fmt +pytestmark = pytest.mark.filterwarnings("ignore::FutureWarning") + lorem_ipsum = ( "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim " diff --git a/pandas/tests/io/test_common.py b/pandas/tests/io/test_common.py index a782f8dbbc76d..bd20a81924593 100644 --- a/pandas/tests/io/test_common.py +++ b/pandas/tests/io/test_common.py @@ -227,6 +227,7 @@ def test_read_non_existent(self, reader, module, error_class, fn_ext): ): reader(path) + @pytest.mark.filterwarnings("ignore:In future versions `DataFrame.to_html`") @pytest.mark.parametrize( "method, module, error_class, fn_ext", [ @@ -349,6 +350,7 @@ def test_read_fspath_all(self, reader, module, path, datapath): tm.assert_frame_equal(result, expected) @pytest.mark.filterwarnings("ignore:In future versions `DataFrame.to_latex`") + @pytest.mark.filterwarnings("ignore:In future versions `DataFrame.to_html`") @pytest.mark.parametrize( "writer_name, writer_kwargs, module", [ From 7de29d125123abe25047b09e89b0d128ce49a42d Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Thu, 25 Nov 2021 20:26:10 +0100 Subject: [PATCH 16/24] remove okwarning --- doc/source/user_guide/io.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index 83bf2456cafd9..973f077765e81 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -2631,7 +2631,6 @@ Use some combination of the above: Read in pandas ``to_html`` output (with some loss of floating point precision): .. code-block:: python - :okwarning: df = pd.DataFrame(np.random.randn(2, 2)) s = df.style.format("{0:.40g}").to_html() From f2a944aa5244b1164ea865dd0a4dc73440a448ed Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Thu, 25 Nov 2021 20:31:34 +0100 Subject: [PATCH 17/24] pytest filters --- pandas/tests/io/test_html.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pandas/tests/io/test_html.py b/pandas/tests/io/test_html.py index f6ae5ebfdf526..917d689665d03 100644 --- a/pandas/tests/io/test_html.py +++ b/pandas/tests/io/test_html.py @@ -118,6 +118,7 @@ def set_defaults(self, flavor, request): self.read_html = partial(read_html, flavor=flavor) yield + @pytest.mark.filterwarnings("ignore::FutureWarning") def test_to_html_compat(self): df = ( tm.makeCustomDataframe( @@ -877,6 +878,7 @@ def test_header_inferred_from_rows_with_only_th(self): tm.assert_frame_equal(result, expected) + @pytest.mark.filterwarnings("ignore::FutureWarning") def test_parse_dates_list(self): df = DataFrame({"date": date_range("1/1/2001", periods=10)}) expected = df.to_html() @@ -885,6 +887,7 @@ def test_parse_dates_list(self): res = self.read_html(expected, parse_dates=["date"], index_col=0) tm.assert_frame_equal(df, res[0]) + @pytest.mark.filterwarnings("ignore::FutureWarning") def test_parse_dates_combine(self): raw_dates = Series(date_range("1/1/2001", periods=10)) df = DataFrame( @@ -1096,6 +1099,7 @@ def test_ignore_empty_rows_when_inferring_header(self): tm.assert_frame_equal(result, expected) + @pytest.mark.filterwarnings("ignore::FutureWarning") def test_multiple_header_rows(self): # Issue #13434 expected_df = DataFrame( @@ -1120,6 +1124,7 @@ def test_fallback_success(self, datapath): banklist_data = datapath("io", "data", "html", "banklist.html") self.read_html(banklist_data, match=".*Water.*", flavor=["lxml", "html5lib"]) + @pytest.mark.filterwarnings("ignore::FutureWarning") def test_to_html_timestamp(self): rng = date_range("2000-01-01", periods=10) df = DataFrame(np.random.randn(10, 4), index=rng) From 6a4523e73d0a4c76e5451c0b543c555e855cc4f3 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Fri, 26 Nov 2021 08:38:55 +0100 Subject: [PATCH 18/24] whats new --- doc/source/whatsnew/v1.4.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 39e3894f86302..c266b986bdb19 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -469,7 +469,7 @@ Other Deprecations - Deprecated :meth:`PeriodIndex.astype` to ``datetime64[ns]`` or ``DatetimeTZDtype``, use ``obj.to_timestamp(how).tz_localize(dtype.tz)`` instead (:issue:`44398`) - Deprecated passing ``skipna=None`` for :meth:`DataFrame.mad` and :meth:`Series.mad`, pass ``skipna=True`` instead (:issue:`44580`) - Deprecated :meth:`DateOffset.apply`, use ``offset + other`` instead (:issue:`44522`) -- A deprecation warning is now shown for :meth:`DataFrame.to_latex` indicating the arguments signature may change and emulate more the arguments to :meth:`.Styler.to_latex` in future versions (:issue:`44411`) +- A deprecation warning is now shown for both :meth:`DataFrame.to_html` and :meth:`DataFrame.to_latex` indicating the arguments signature may change and emulate more the arguments in :meth:`.Styler.to_html` and :meth:`.Styler.to_latex`, respectively, in future versions (:issue:`44411`, :issue:`44451`) - .. --------------------------------------------------------------------------- From 9e66a72b7639e2453046dfb724fdd7185d732ce0 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Fri, 26 Nov 2021 08:45:15 +0100 Subject: [PATCH 19/24] add explicit test --- pandas/tests/io/formats/test_to_html.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pandas/tests/io/formats/test_to_html.py b/pandas/tests/io/formats/test_to_html.py index f7a459bc0f95c..3c4ddb53ddf69 100644 --- a/pandas/tests/io/formats/test_to_html.py +++ b/pandas/tests/io/formats/test_to_html.py @@ -874,3 +874,16 @@ def test_to_html_float_format_object_col(datapath): result = df.to_html(float_format=lambda x: f"{x:,.0f}") expected = expected_html(datapath, "gh40024_expected_output") assert result == expected + + +def test_future_warning(): + df = DataFrame([[1]]) + msg = ( + "In future versions `DataFrame.to_html` is expected to utilise the base " + "implementation of `Styler.to_html` for formatting and rendering. " + "The arguments signature may therefore change. It is recommended instead " + "to use `DataFrame.style.to_html` which also contains additional " + "functionality." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + df.to_html() From d859877d18fdcb39c1df46bfc7c2d4d1f90de81f Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Tue, 7 Dec 2021 11:35:52 +0100 Subject: [PATCH 20/24] more specific warnings --- pandas/core/frame.py | 47 ++++++++++++++++++++++--- pandas/tests/io/formats/test_format.py | 3 +- pandas/tests/io/formats/test_to_html.py | 42 +++++++++++++++++++--- 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 6f4d12def2257..ff200ebe6c634 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2911,14 +2911,51 @@ def to_html( Styler.to_html : Render a DataFrame to HTML with conditional formatting. to_string : Convert DataFrame to a string. """ - msg = ( + # Warnings are shown in 1.4.0 in preparation for signature changes in 2.0.0 + warnings_default_none = { + "classes": "replaced by `table_attributes`", + "sparsify": "replaced by `sparse_index` and `sparse_columns`", + "max_cols": "replaced by `max_columns` for consistency", + "formatters": "replaced by `formatter` accepted by `Styler.format`", + "float_format": "replaced by `precision`, `decimal`, and `thousands`", + "border": "removed as deprecated HTML, suggested to use CSS", + "col_space": "removed, suggested to use CSS `min-width: 100px;`", + "justify": "removed, suggested to use CSS", + } + + warnings_default_false = { + "render_links": "removed due to limited functionality", + "notebook": "removed as a legacy argument", + "show_dimensions": "removed, suggested to use `caption=f'{df.shape}'`", + } + + warnings_default_true = { + "bold_rows": "replaced by `bold_headers` controlling index and columns", + } + + warning_msg = ( "In future versions `DataFrame.to_html` is expected to utilise the base " "implementation of `Styler.to_html` for formatting and rendering. " - "The arguments signature may therefore change. It is recommended instead " - "to use `DataFrame.style.to_html` which also contains additional " - "functionality." + "The arguments signature may therefore change. You are specifically using " + "the following arguments: " ) - warnings.warn(msg, FutureWarning, stacklevel=find_stack_level()) + warning_flag = False + + for kwarg, msg in warnings_default_none.items(): + if locals()[kwarg] is not None: + warning_flag = True + warning_msg += f"\n `{kwarg}`, which may be {msg}." + for kwarg, msg in warnings_default_false.items(): + if locals()[kwarg] is True: + warning_flag = True + warning_msg += f"\n `{kwarg}`, which may be {msg}." + for kwarg, msg in warnings_default_true.items(): + if locals()[kwarg] is False: + warning_flag = True + warning_msg += f"\n `{kwarg}`, which may be {msg}." + + if warning_flag: + warnings.warn(warning_msg, FutureWarning, stacklevel=find_stack_level()) if justify is not None and justify not in fmt._VALID_JUSTIFY_PARAMETERS: raise ValueError("Invalid value for justify parameter") diff --git a/pandas/tests/io/formats/test_format.py b/pandas/tests/io/formats/test_format.py index 09135637910c7..197d3dff62b30 100644 --- a/pandas/tests/io/formats/test_format.py +++ b/pandas/tests/io/formats/test_format.py @@ -3299,7 +3299,6 @@ def test_repr_html_ipython_config(ip): @pytest.mark.filterwarnings("ignore:In future versions `DataFrame.to_latex`") -@pytest.mark.filterwarnings("ignore:In future versions `DataFrame.to_html`") @pytest.mark.parametrize("method", ["to_string", "to_html", "to_latex"]) @pytest.mark.parametrize( "encoding, data", @@ -3321,7 +3320,7 @@ def test_filepath_or_buffer_arg( ): getattr(df, method)(buf=filepath_or_buffer, encoding=encoding) elif encoding == "foo": - expected_warning = FutureWarning if method in ["to_latex", "to_html"] else None + expected_warning = FutureWarning if method in ["to_latex"] else None with tm.assert_produces_warning(expected_warning): with pytest.raises(LookupError, match="unknown encoding"): getattr(df, method)(buf=filepath_or_buffer, encoding=encoding) diff --git a/pandas/tests/io/formats/test_to_html.py b/pandas/tests/io/formats/test_to_html.py index 3c4ddb53ddf69..52a38238f4c79 100644 --- a/pandas/tests/io/formats/test_to_html.py +++ b/pandas/tests/io/formats/test_to_html.py @@ -876,14 +876,48 @@ def test_to_html_float_format_object_col(datapath): assert result == expected -def test_future_warning(): +@pytest.mark.parametrize( + "kw1, kw1_val, kw1_msg", + [ + ("classes", "text", "replaced by `table_attributes`"), + ("sparsify", True, "replaced by `sparse_index` and `sparse_columns`"), + ("max_cols", 1, "replaced by `max_columns` for consistency"), + ("formatters", [None], "replaced by `formatter` accepted by `Styler.format`"), + ("float_format", "txt", "replaced by `precision`, `decimal`, and `thousands`"), + ("border", 10, "removed as deprecated HTML, suggested to use CSS"), + ("col_space", 1, "removed, suggested to use CSS `min-width: 100px;`"), + ("justify", "right", "removed, suggested to use CSS"), + ], +) +@pytest.mark.parametrize( + "kw2, kw2_val, kw2_msg", + [ + ("render_links", True, "removed due to limited functionality"), + ("notebook", True, "removed as a legacy argument"), + ("show_dimensions", True, "removed, suggested to use `caption=f'{df.shape}'`"), + ( + "bold_rows", + False, + "replaced by `bold_headers` controlling index and columns", + ), + ], +) +def test_future_warning(kw1, kw1_val, kw1_msg, kw2, kw2_val, kw2_msg): df = DataFrame([[1]]) msg = ( "In future versions `DataFrame.to_html` is expected to utilise the base " "implementation of `Styler.to_html` for formatting and rendering. " - "The arguments signature may therefore change. It is recommended instead " - "to use `DataFrame.style.to_html` which also contains additional " - "functionality." + "The arguments signature may therefore change. You are specifically using " + "the following arguments: " ) + msg += f"\\n `{kw1}`, which may be {kw1_msg}." + msg += f"\\n `{kw2}`, which may be {kw2_msg}." + with tm.assert_produces_warning(FutureWarning, match=msg): + df.to_html(**{kw1: kw1_val, kw2: kw2_val}) + + +def test_no_future_warning(): + df = DataFrame([[1]]) + with tm.assert_produces_warning(None): df.to_html() From 02d913ced2b9f52f5eac3113d2aae77ad4ef8f2d Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Tue, 7 Dec 2021 11:39:10 +0100 Subject: [PATCH 21/24] more specific warnings --- pandas/tests/io/test_common.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandas/tests/io/test_common.py b/pandas/tests/io/test_common.py index a3fc82f917c99..94a1d614880e4 100644 --- a/pandas/tests/io/test_common.py +++ b/pandas/tests/io/test_common.py @@ -228,7 +228,6 @@ def test_read_non_existent(self, reader, module, error_class, fn_ext): ): reader(path) - @pytest.mark.filterwarnings("ignore:In future versions `DataFrame.to_html`") @pytest.mark.parametrize( "method, module, error_class, fn_ext", [ @@ -351,7 +350,6 @@ def test_read_fspath_all(self, reader, module, path, datapath): tm.assert_frame_equal(result, expected) @pytest.mark.filterwarnings("ignore:In future versions `DataFrame.to_latex`") - @pytest.mark.filterwarnings("ignore:In future versions `DataFrame.to_html`") @pytest.mark.parametrize( "writer_name, writer_kwargs, module", [ From 7d5ab6c2f4f6d67fac1d948a5490b8323059df29 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Tue, 7 Dec 2021 11:42:37 +0100 Subject: [PATCH 22/24] more specific warnings (filters removed) --- pandas/tests/io/test_html.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pandas/tests/io/test_html.py b/pandas/tests/io/test_html.py index 917d689665d03..74f192a2f6338 100644 --- a/pandas/tests/io/test_html.py +++ b/pandas/tests/io/test_html.py @@ -118,7 +118,6 @@ def set_defaults(self, flavor, request): self.read_html = partial(read_html, flavor=flavor) yield - @pytest.mark.filterwarnings("ignore::FutureWarning") def test_to_html_compat(self): df = ( tm.makeCustomDataframe( @@ -878,7 +877,6 @@ def test_header_inferred_from_rows_with_only_th(self): tm.assert_frame_equal(result, expected) - @pytest.mark.filterwarnings("ignore::FutureWarning") def test_parse_dates_list(self): df = DataFrame({"date": date_range("1/1/2001", periods=10)}) expected = df.to_html() @@ -1099,7 +1097,6 @@ def test_ignore_empty_rows_when_inferring_header(self): tm.assert_frame_equal(result, expected) - @pytest.mark.filterwarnings("ignore::FutureWarning") def test_multiple_header_rows(self): # Issue #13434 expected_df = DataFrame( @@ -1124,7 +1121,6 @@ def test_fallback_success(self, datapath): banklist_data = datapath("io", "data", "html", "banklist.html") self.read_html(banklist_data, match=".*Water.*", flavor=["lxml", "html5lib"]) - @pytest.mark.filterwarnings("ignore::FutureWarning") def test_to_html_timestamp(self): rng = date_range("2000-01-01", periods=10) df = DataFrame(np.random.randn(10, 4), index=rng) From a9e4ac4b8aefec30853316f43f503c531d7f9e22 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Tue, 7 Dec 2021 11:44:38 +0100 Subject: [PATCH 23/24] more specific warnings (filters removed) --- pandas/tests/io/test_html.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/tests/io/test_html.py b/pandas/tests/io/test_html.py index 74f192a2f6338..f6ae5ebfdf526 100644 --- a/pandas/tests/io/test_html.py +++ b/pandas/tests/io/test_html.py @@ -885,7 +885,6 @@ def test_parse_dates_list(self): res = self.read_html(expected, parse_dates=["date"], index_col=0) tm.assert_frame_equal(df, res[0]) - @pytest.mark.filterwarnings("ignore::FutureWarning") def test_parse_dates_combine(self): raw_dates = Series(date_range("1/1/2001", periods=10)) df = DataFrame( From 272670a139a1c4c818d2ed9d0302836803c387f6 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Wed, 22 Dec 2021 18:22:02 +0100 Subject: [PATCH 24/24] doc string addition --- pandas/core/frame.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index d9ef6b710b5fb..d8b81e26a30f8 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2906,6 +2906,27 @@ def to_html( -------- Styler.to_html : Render a DataFrame to HTML with conditional formatting. to_string : Convert DataFrame to a string. + + Notes + ----- + As of version 1.4.0, a warning is shown for the following use of keyword + arguments if they are non-default values, in order to align this function with + the formatting structure akin to ``Styler.to_html``. + + - ``classes``, likely replaced by ``table_attributes``. + - ``sparsify``, likely separated to ``sparse_index``, ``sparse_columns``. + - ``max_cols``, likely replaced with ``max_columns`` consistently. + - ``formatters``, likely replaced with ``formatter``. + - ``float_format``, likely replaced by ``precision``, ``decimal``, + ``thousands``. + - ``border``, likely removed due to deprecated HTML specification. + - ``col_space``, likely removed in favour of CSS solutions. + - ``justify``, likely removed in favour of CSS solutions. + - ``render_links``, likely removed due to limited functionality. + - ``notebook``, likely removed due to legacy impact. + - ``show_dimensions``, likely removed in favour of caption solution. + - ``bold_rows``, likely replaced with ``bold_headers`` with index and column + control. """ # Warnings are shown in 1.4.0 in preparation for signature changes in 2.0.0 warnings_default_none = {