From d7fe32a8505540ea441486673b2cd24ee8e62f41 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Fri, 1 Nov 2024 12:20:27 +0100 Subject: [PATCH 01/20] feat(python): Add show methods to DataFrame and LazyFrame --- py-polars/polars/dataframe/frame.py | 57 +++++++++++++++++++++++++++++ py-polars/polars/lazyframe/frame.py | 52 ++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index 3403f8c12dac..e1c0335fbf75 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -55,6 +55,7 @@ from polars._utils.serde import serialize_polars_object from polars._utils.unstable import issue_unstable_warning, unstable from polars._utils.various import ( + _in_notebook, is_bool_sequence, no_default, normalize_filepath, @@ -11263,6 +11264,62 @@ def melt( value_name=value_name, ) + def show(self, n: int = 5) -> None: + """ + Show the first `n` rows. + + Parameters + ---------- + n + Numbers of rows to show. If a negative value is passed, return all rows + except the last `abs(n)`. + + See Also + -------- + head + + Examples + -------- + >>> df = pl.DataFrame( + ... { + ... "foo": [1, 2, 3, 4, 5], + ... "bar": [6, 7, 8, 9, 10], + ... "ham": ["a", "b", "c", "d", "e"], + ... } + ... ) + >>> df.show(3) + shape: (3, 3) + ┌─────┬─────┬─────┐ + │ foo ┆ bar ┆ ham │ + │ --- ┆ --- ┆ --- │ + │ i64 ┆ i64 ┆ str │ + ╞═════╪═════╪═════╡ + │ 1 ┆ 6 ┆ a │ + │ 2 ┆ 7 ┆ b │ + │ 3 ┆ 8 ┆ c │ + └─────┴─────┴─────┘ + + Pass a negative value to get all rows `except` the last `abs(n)`. + + >>> df.show(-3) + shape: (2, 3) + ┌─────┬─────┬─────┐ + │ foo ┆ bar ┆ ham │ + │ --- ┆ --- ┆ --- │ + │ i64 ┆ i64 ┆ str │ + ╞═════╪═════╪═════╡ + │ 1 ┆ 6 ┆ a │ + │ 2 ┆ 7 ┆ b │ + └─────┴─────┴─────┘ + """ + show_result = self.head(n) + if _in_notebook(): + from IPython.display import display_html + + display_html(show_result) + else: + print(show_result) + def _to_metadata( self, columns: None | str | list[str] = None, diff --git a/py-polars/polars/lazyframe/frame.py b/py-polars/polars/lazyframe/frame.py index 9b438ae8dbfa..50b319c44484 100644 --- a/py-polars/polars/lazyframe/frame.py +++ b/py-polars/polars/lazyframe/frame.py @@ -6907,6 +6907,58 @@ def melt( streamable=streamable, ) + def show(self, n: int = 5) -> None: + """ + Show the first `n` rows. + + Parameters + ---------- + n + Number of rows to return. + + Warnings + -------- + * This method does *not* maintain the laziness of the frame, and will `collect` + the final result. This could potentially be an expensive operation. + + Examples + -------- + >>> lf = pl.LazyFrame( + ... { + ... "a": [1, 2, 3, 4, 5, 6], + ... "b": [7, 8, 9, 10, 11, 12], + ... } + ... ) + >>> lf.show() + ┌─────┬─────┐ + │ a ┆ b │ + │ --- ┆ --- │ + │ i64 ┆ i64 │ + ╞═════╪═════╡ + │ 1 ┆ 7 │ + │ 2 ┆ 8 │ + │ 3 ┆ 9 │ + │ 4 ┆ 10 │ + │ 5 ┆ 11 │ + └─────┴─────┘ + >>> lf.show(2) + ┌─────┬─────┐ + │ a ┆ b │ + │ --- ┆ --- │ + │ i64 ┆ i64 │ + ╞═════╪═════╡ + │ 1 ┆ 7 │ + │ 2 ┆ 8 │ + └─────┴─────┘ + """ + show_result = self.head(n).collect() + if _in_notebook(): + from IPython.display import display_html + + display_html(show_result) + else: + print(show_result) + def _to_metadata( self, columns: None | str | list[str] = None, From ae7502d575f595219777f08e145821d7e2694153 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Mon, 4 Nov 2024 19:07:22 +0100 Subject: [PATCH 02/20] refine implementation and add tests --- py-polars/polars/dataframe/frame.py | 45 +++- py-polars/polars/lazyframe/frame.py | 42 +++- py-polars/tests/unit/dataframe/test_show.py | 225 ++++++++++++++++++++ py-polars/tests/unit/lazyframe/test_show.py | 27 +++ 4 files changed, 321 insertions(+), 18 deletions(-) create mode 100644 py-polars/tests/unit/dataframe/test_show.py create mode 100644 py-polars/tests/unit/lazyframe/test_show.py diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index e1c0335fbf75..95f5903f41a4 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -64,6 +64,7 @@ warn_null_comparison, ) from polars._utils.wrap import wrap_expr, wrap_ldf, wrap_s +from polars.config import Config from polars.dataframe._html import NotebookFormatter from polars.dataframe.group_by import DynamicGroupBy, GroupBy, RollingGroupBy from polars.dataframe.plotting import DataFramePlot @@ -11264,15 +11265,35 @@ def melt( value_name=value_name, ) - def show(self, n: int = 5) -> None: + def show( + self, + n: int = 5, + *, + float_precision: int | None = None, + fmt_str_lengths: int | None = None, + fmt_table_cell_list_len: int | None = None, + tbl_cols: int | None = None, + ) -> None: """ Show the first `n` rows. Parameters ---------- - n + n : int Numbers of rows to show. If a negative value is passed, return all rows except the last `abs(n)`. + float_precision : int + Number of decimal places to display for floating point values. See + :func:`Config.set_float_precision` for more information. + fmt_str_lengths : int + Number of characters to display for string values. See + :func:`Config.set_fmt_str_lengths` for more information. + fmt_table_cell_list_len : int + Number of elements to display for List values. See + :func:`Config.set_fmt_table_cell_list_len` for more information. + tbl_cols : int + Number of columns to display. See :func:`Config.set_tbl_cols` for more + information. See Also -------- @@ -11312,13 +11333,21 @@ def show(self, n: int = 5) -> None: │ 2 ┆ 7 ┆ b │ └─────┴─────┴─────┘ """ - show_result = self.head(n) - if _in_notebook(): - from IPython.display import display_html + df = self.head(n) + with Config( + float_precision=float_precision, + fmt_str_lengths=fmt_str_lengths, + fmt_table_cell_list_len=fmt_table_cell_list_len, + tbl_cols=tbl_cols, + tbl_rows=n, + ): + if _in_notebook(): + print("In notebook") + from IPython.display import display_html - display_html(show_result) - else: - print(show_result) + display_html(df) + else: + print(df) def _to_metadata( self, diff --git a/py-polars/polars/lazyframe/frame.py b/py-polars/polars/lazyframe/frame.py index 50b319c44484..41ad125730d8 100644 --- a/py-polars/polars/lazyframe/frame.py +++ b/py-polars/polars/lazyframe/frame.py @@ -6907,14 +6907,34 @@ def melt( streamable=streamable, ) - def show(self, n: int = 5) -> None: + def show( + self, + n: int = 5, + *, + float_precision: int | None = None, + fmt_str_lengths: int | None = None, + fmt_table_cell_list_len: int | None = None, + tbl_cols: int | None = None, + ) -> None: """ Show the first `n` rows. Parameters ---------- - n - Number of rows to return. + n : int + Number of rows to show. + float_precision : int + Number of decimal places to display for floating point values. See + :func:`Config.set_float_precision` for more information. + fmt_str_lengths : int + Number of characters to display for string values. See + :func:`Config.set_fmt_str_lengths` for more information. + fmt_table_cell_list_len : int + Number of elements to display for List values. See + :func:`Config.set_fmt_table_cell_list_len` for more information. + tbl_cols : int + Number of columns to display. See :func:`Config.set_tbl_cols` for more + information. Warnings -------- @@ -6930,6 +6950,7 @@ def show(self, n: int = 5) -> None: ... } ... ) >>> lf.show() + shape: (5, 2) ┌─────┬─────┐ │ a ┆ b │ │ --- ┆ --- │ @@ -6942,6 +6963,7 @@ def show(self, n: int = 5) -> None: │ 5 ┆ 11 │ └─────┴─────┘ >>> lf.show(2) + shape: (2, 2) ┌─────┬─────┐ │ a ┆ b │ │ --- ┆ --- │ @@ -6951,13 +6973,13 @@ def show(self, n: int = 5) -> None: │ 2 ┆ 8 │ └─────┴─────┘ """ - show_result = self.head(n).collect() - if _in_notebook(): - from IPython.display import display_html - - display_html(show_result) - else: - print(show_result) + self.head(n).collect().show( + n, + float_precision=float_precision, + fmt_str_lengths=fmt_str_lengths, + fmt_table_cell_list_len=fmt_table_cell_list_len, + tbl_cols=tbl_cols, + ) def _to_metadata( self, diff --git a/py-polars/tests/unit/dataframe/test_show.py b/py-polars/tests/unit/dataframe/test_show.py new file mode 100644 index 000000000000..54e29facc04c --- /dev/null +++ b/py-polars/tests/unit/dataframe/test_show.py @@ -0,0 +1,225 @@ +from unittest.mock import patch + +import pytest + +import polars as pl +from polars.testing.asserts import assert_frame_equal + + +@pytest.fixture(name="in_notebook") +def _in_notebook(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr("polars.dataframe.frame._in_notebook", lambda: True) + + +def test_df_show_default(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame( + { + "foo": [1, 2, 3, 4, 5, 6, 7], + "bar": ["a", "b", "c", "d", "e", "f", "g"], + } + ) + df.show() + out, _ = capsys.readouterr() + assert ( + out + == """shape: (5, 2) +┌─────┬─────┐ +│ foo ┆ bar │ +│ --- ┆ --- │ +│ i64 ┆ str │ +╞═════╪═════╡ +│ 1 ┆ a │ +│ 2 ┆ b │ +│ 3 ┆ c │ +│ 4 ┆ d │ +│ 5 ┆ e │ +└─────┴─────┘ +""" + ) + + +def test_df_show_n_rows(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame( + { + "foo": [1, 2, 3, 4, 5, 6, 7], + "bar": ["a", "b", "c", "d", "e", "f", "g"], + } + ) + df.show(3) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 2) +┌─────┬─────┐ +│ foo ┆ bar │ +│ --- ┆ --- │ +│ i64 ┆ str │ +╞═════╪═════╡ +│ 1 ┆ a │ +│ 2 ┆ b │ +│ 3 ┆ c │ +└─────┴─────┘ +""" + ) + + +def test_df_show_float_precision(capsys: pytest.CaptureFixture[str]) -> None: + from math import e, pi + + df = pl.DataFrame({"const": ["pi", "e"], "value": [pi, e]}) + df.show(float_precision=15) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (2, 2) +┌───────┬───────────────────┐ +│ const ┆ value │ +│ --- ┆ --- │ +│ str ┆ f64 │ +╞═══════╪═══════════════════╡ +│ pi ┆ 3.141592653589793 │ +│ e ┆ 2.718281828459045 │ +└───────┴───────────────────┘ +""" + ) + + df.show(float_precision=3) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (2, 2) +┌───────┬───────┐ +│ const ┆ value │ +│ --- ┆ --- │ +│ str ┆ f64 │ +╞═══════╪═══════╡ +│ pi ┆ 3.142 │ +│ e ┆ 2.718 │ +└───────┴───────┘ +""" + ) + + +def test_df_show_fmt_str_lengths(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame( + { + "txt": [ + "Play it, Sam. Play 'As Time Goes By'.", + "This is the beginning of a beautiful friendship.", + ] + } + ) + df.show(fmt_str_lengths=10) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (2, 1) +┌─────────────┐ +│ txt │ +│ --- │ +│ str │ +╞═════════════╡ +│ Play it, S… │ +│ This is th… │ +└─────────────┘ +""" + ) + df.show(fmt_str_lengths=50) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (2, 1) +┌──────────────────────────────────────────────────┐ +│ txt │ +│ --- │ +│ str │ +╞══════════════════════════════════════════════════╡ +│ Play it, Sam. Play 'As Time Goes By'. │ +│ This is the beginning of a beautiful friendship. │ +└──────────────────────────────────────────────────┘ +""" + ) + + +def test_df_show_fmt_table_cell_list_len(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({"nums": [list(range(10))]}) + + df.show(fmt_table_cell_list_len=2) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (1, 1) +┌───────────┐ +│ nums │ +│ --- │ +│ list[i64] │ +╞═══════════╡ +│ [0, … 9] │ +└───────────┘ +""" + ) + + df.show(fmt_table_cell_list_len=8) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (1, 1) +┌────────────────────────────┐ +│ nums │ +│ --- │ +│ list[i64] │ +╞════════════════════════════╡ +│ [0, 1, 2, 3, 4, 5, 6, … 9] │ +└────────────────────────────┘ +""" + ) + + +def test_df_show_tbl_cols(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({str(i): [i] for i in range(10)}) + + df.show(tbl_cols=3) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (1, 10) +┌─────┬─────┬───┬─────┐ +│ 0 ┆ 1 ┆ … ┆ 9 │ +│ --- ┆ --- ┆ ┆ --- │ +│ i64 ┆ i64 ┆ ┆ i64 │ +╞═════╪═════╪═══╪═════╡ +│ 0 ┆ 1 ┆ … ┆ 9 │ +└─────┴─────┴───┴─────┘ +""" + ) + + df.show(tbl_cols=7) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (1, 10) +┌─────┬─────┬─────┬─────┬───┬─────┬─────┬─────┐ +│ 0 ┆ 1 ┆ 2 ┆ 3 ┆ … ┆ 7 ┆ 8 ┆ 9 │ +│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- │ +│ i64 ┆ i64 ┆ i64 ┆ i64 ┆ ┆ i64 ┆ i64 ┆ i64 │ +╞═════╪═════╪═════╪═════╪═══╪═════╪═════╪═════╡ +│ 0 ┆ 1 ┆ 2 ┆ 3 ┆ … ┆ 7 ┆ 8 ┆ 9 │ +└─────┴─────┴─────┴─────┴───┴─────┴─────┴─────┘ +""" + ) + + +@pytest.mark.usefixtures("in_notebook") +def test_df_show_in_notebook(monkeypatch: pytest.MonkeyPatch) -> None: + with patch("IPython.display.display_html") as display_html: + df = pl.DataFrame( + { + "foo": [1, 2, 3, 4, 5, 6, 7], + "bar": ["a", "b", "c", "d", "e", "f", "g"], + } + ) + df.show(7) + display_html.assert_called_once() + args, _ = display_html.call_args + assert len(args) == 1 + assert_frame_equal(args[0], df) diff --git a/py-polars/tests/unit/lazyframe/test_show.py b/py-polars/tests/unit/lazyframe/test_show.py new file mode 100644 index 000000000000..9363390f10b1 --- /dev/null +++ b/py-polars/tests/unit/lazyframe/test_show.py @@ -0,0 +1,27 @@ +from inspect import signature +from unittest.mock import patch + +import polars as pl + + +def test_show_signature_match() -> None: + assert signature(pl.LazyFrame.show) == signature(pl.DataFrame.show) + + +def test_lf_show_calls_df_show() -> None: + lf = pl.LazyFrame( + { + "foo": ["a", "b", "c", "d", "e", "f", "g"], + "bar": [1, 2, 3, 4, 5, 6, 7], + } + ) + with patch.object(pl.DataFrame, "show") as df_show: + lf.show(5) + + df_show.assert_called_once_with( + 5, + float_precision=None, + fmt_str_lengths=None, + fmt_table_cell_list_len=None, + tbl_cols=None, + ) From c76a0a5ccfa7c5db3974979d9c43604169a3070d Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Tue, 5 Nov 2024 12:43:01 +0100 Subject: [PATCH 03/20] remove show_in_notebook test --- py-polars/tests/unit/dataframe/test_show.py | 24 --------------------- 1 file changed, 24 deletions(-) diff --git a/py-polars/tests/unit/dataframe/test_show.py b/py-polars/tests/unit/dataframe/test_show.py index 54e29facc04c..0c6dba346e5e 100644 --- a/py-polars/tests/unit/dataframe/test_show.py +++ b/py-polars/tests/unit/dataframe/test_show.py @@ -1,14 +1,6 @@ -from unittest.mock import patch - import pytest import polars as pl -from polars.testing.asserts import assert_frame_equal - - -@pytest.fixture(name="in_notebook") -def _in_notebook(monkeypatch: pytest.MonkeyPatch) -> None: - monkeypatch.setattr("polars.dataframe.frame._in_notebook", lambda: True) def test_df_show_default(capsys: pytest.CaptureFixture[str]) -> None: @@ -207,19 +199,3 @@ def test_df_show_tbl_cols(capsys: pytest.CaptureFixture[str]) -> None: └─────┴─────┴─────┴─────┴───┴─────┴─────┴─────┘ """ ) - - -@pytest.mark.usefixtures("in_notebook") -def test_df_show_in_notebook(monkeypatch: pytest.MonkeyPatch) -> None: - with patch("IPython.display.display_html") as display_html: - df = pl.DataFrame( - { - "foo": [1, 2, 3, 4, 5, 6, 7], - "bar": ["a", "b", "c", "d", "e", "f", "g"], - } - ) - df.show(7) - display_html.assert_called_once() - args, _ = display_html.call_args - assert len(args) == 1 - assert_frame_equal(args[0], df) From 1145f04f0a982835dd8d36c4b91b4c2304091d56 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Tue, 5 Nov 2024 20:30:59 +0100 Subject: [PATCH 04/20] refactor: replace `n` with `limit` Refactor both `show` methods to use a limit rather than a number of rows to show. The `limit` parameter is an extension of the `n` number of rows parameter, and can be set to None. In that case, the `show` method will display all frame rows. --- py-polars/polars/dataframe/frame.py | 19 +++++-- py-polars/polars/lazyframe/frame.py | 19 +++++-- py-polars/tests/unit/dataframe/test_show.py | 55 ++++++++++++++++++++- py-polars/tests/unit/lazyframe/test_show.py | 16 +++--- 4 files changed, 93 insertions(+), 16 deletions(-) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index 95f5903f41a4..bbb7bbde2440 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -11267,7 +11267,7 @@ def melt( def show( self, - n: int = 5, + limit: int | None = 5, *, float_precision: int | None = None, fmt_str_lengths: int | None = None, @@ -11279,9 +11279,9 @@ def show( Parameters ---------- - n : int + limit : int Numbers of rows to show. If a negative value is passed, return all rows - except the last `abs(n)`. + except the last `abs(n)`. If None is passed, return all rows. float_precision : int Number of decimal places to display for floating point values. See :func:`Config.set_float_precision` for more information. @@ -11333,13 +11333,22 @@ def show( │ 2 ┆ 7 ┆ b │ └─────┴─────┴─────┘ """ - df = self.head(n) + if limit is None: + df = self + tbl_rows = self.height + else: + df = self.head(limit) + if limit < 0: + tbl_rows = self.height - abs(limit) + else: + tbl_rows = limit + with Config( float_precision=float_precision, fmt_str_lengths=fmt_str_lengths, fmt_table_cell_list_len=fmt_table_cell_list_len, tbl_cols=tbl_cols, - tbl_rows=n, + tbl_rows=tbl_rows, ): if _in_notebook(): print("In notebook") diff --git a/py-polars/polars/lazyframe/frame.py b/py-polars/polars/lazyframe/frame.py index 41ad125730d8..a24603fbcc32 100644 --- a/py-polars/polars/lazyframe/frame.py +++ b/py-polars/polars/lazyframe/frame.py @@ -6909,7 +6909,7 @@ def melt( def show( self, - n: int = 5, + limit: int | None = 5, *, float_precision: int | None = None, fmt_str_lengths: int | None = None, @@ -6922,7 +6922,7 @@ def show( Parameters ---------- n : int - Number of rows to show. + Number of rows to show. If None is passed, return all rows. float_precision : int Number of decimal places to display for floating point values. See :func:`Config.set_float_precision` for more information. @@ -6973,8 +6973,19 @@ def show( │ 2 ┆ 8 │ └─────┴─────┘ """ - self.head(n).collect().show( - n, + if limit is None: + lf = self + issue_warning( + "Showing a LazyFrame without a limit requires collecting the whole " + "LazyFrame, which could be an expensive operation. Set a limit to " + "show the LazyFrame without this warning.", + category=PerformanceWarning, + ) + else: + lf = self.head(limit) + + lf.collect().show( + limit, float_precision=float_precision, fmt_str_lengths=fmt_str_lengths, fmt_table_cell_list_len=fmt_table_cell_list_len, diff --git a/py-polars/tests/unit/dataframe/test_show.py b/py-polars/tests/unit/dataframe/test_show.py index 0c6dba346e5e..4ae34c250aaf 100644 --- a/py-polars/tests/unit/dataframe/test_show.py +++ b/py-polars/tests/unit/dataframe/test_show.py @@ -30,7 +30,7 @@ def test_df_show_default(capsys: pytest.CaptureFixture[str]) -> None: ) -def test_df_show_n_rows(capsys: pytest.CaptureFixture[str]) -> None: +def test_df_show_positive_limit(capsys: pytest.CaptureFixture[str]) -> None: df = pl.DataFrame( { "foo": [1, 2, 3, 4, 5, 6, 7], @@ -55,6 +55,59 @@ def test_df_show_n_rows(capsys: pytest.CaptureFixture[str]) -> None: ) +def test_df_show_negative_limit(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame( + { + "foo": [1, 2, 3, 4, 5, 6, 7], + "bar": ["a", "b", "c", "d", "e", "f", "g"], + } + ) + df.show(-5) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (2, 2) +┌─────┬─────┐ +│ foo ┆ bar │ +│ --- ┆ --- │ +│ i64 ┆ str │ +╞═════╪═════╡ +│ 1 ┆ a │ +│ 2 ┆ b │ +└─────┴─────┘ +""" + ) + + +def test_df_show_no_limit(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame( + { + "foo": [1, 2, 3, 4, 5, 6, 7], + "bar": ["a", "b", "c", "d", "e", "f", "g"], + } + ) + df.show(limit=None) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (7, 2) +┌─────┬─────┐ +│ foo ┆ bar │ +│ --- ┆ --- │ +│ i64 ┆ str │ +╞═════╪═════╡ +│ 1 ┆ a │ +│ 2 ┆ b │ +│ 3 ┆ c │ +│ 4 ┆ d │ +│ 5 ┆ e │ +│ 6 ┆ f │ +│ 7 ┆ g │ +└─────┴─────┘ +""" + ) + + def test_df_show_float_precision(capsys: pytest.CaptureFixture[str]) -> None: from math import e, pi diff --git a/py-polars/tests/unit/lazyframe/test_show.py b/py-polars/tests/unit/lazyframe/test_show.py index 9363390f10b1..cee36e3a5c1d 100644 --- a/py-polars/tests/unit/lazyframe/test_show.py +++ b/py-polars/tests/unit/lazyframe/test_show.py @@ -1,7 +1,10 @@ from inspect import signature from unittest.mock import patch +import pytest + import polars as pl +from polars.exceptions import PerformanceWarning def test_show_signature_match() -> None: @@ -9,12 +12,7 @@ def test_show_signature_match() -> None: def test_lf_show_calls_df_show() -> None: - lf = pl.LazyFrame( - { - "foo": ["a", "b", "c", "d", "e", "f", "g"], - "bar": [1, 2, 3, 4, 5, 6, 7], - } - ) + lf = pl.LazyFrame({}) with patch.object(pl.DataFrame, "show") as df_show: lf.show(5) @@ -25,3 +23,9 @@ def test_lf_show_calls_df_show() -> None: fmt_table_cell_list_len=None, tbl_cols=None, ) + + +def test_lf_show_no_limit_issues_warning() -> None: + lf = pl.LazyFrame({}) + with pytest.warns(PerformanceWarning): + lf.show(limit=None) From e4c1fb840a877810eca08fa27b0f8eb26d9ef267 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 00:57:55 +0100 Subject: [PATCH 05/20] decorate existing tests with Config --- py-polars/tests/unit/dataframe/test_show.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/py-polars/tests/unit/dataframe/test_show.py b/py-polars/tests/unit/dataframe/test_show.py index 4ae34c250aaf..44ca312731aa 100644 --- a/py-polars/tests/unit/dataframe/test_show.py +++ b/py-polars/tests/unit/dataframe/test_show.py @@ -108,6 +108,7 @@ def test_df_show_no_limit(capsys: pytest.CaptureFixture[str]) -> None: ) +@pl.Config(float_precision=8) def test_df_show_float_precision(capsys: pytest.CaptureFixture[str]) -> None: from math import e, pi @@ -145,6 +146,7 @@ def test_df_show_float_precision(capsys: pytest.CaptureFixture[str]) -> None: ) +@pl.Config(fmt_str_lengths=20) def test_df_show_fmt_str_lengths(capsys: pytest.CaptureFixture[str]) -> None: df = pl.DataFrame( { @@ -186,6 +188,7 @@ def test_df_show_fmt_str_lengths(capsys: pytest.CaptureFixture[str]) -> None: ) +@pl.Config(fmt_table_cell_list_len=5) def test_df_show_fmt_table_cell_list_len(capsys: pytest.CaptureFixture[str]) -> None: df = pl.DataFrame({"nums": [list(range(10))]}) @@ -220,6 +223,7 @@ def test_df_show_fmt_table_cell_list_len(capsys: pytest.CaptureFixture[str]) -> ) +@pl.Config(tbl_cols=2) def test_df_show_tbl_cols(capsys: pytest.CaptureFixture[str]) -> None: df = pl.DataFrame({str(i): [i] for i in range(10)}) From 6c93c77e0ff3da537ec432408e5370a79236fb15 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 00:59:59 +0100 Subject: [PATCH 06/20] use shorthand for unlimited rows --- py-polars/polars/dataframe/frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index bbb7bbde2440..d5cdb4333153 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -11335,7 +11335,7 @@ def show( """ if limit is None: df = self - tbl_rows = self.height + tbl_rows = -1 else: df = self.head(limit) if limit < 0: From b9dd3f6a452d518d0db592869f8576882240f724 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 01:45:25 +0100 Subject: [PATCH 07/20] more formatting options for DataFrame.show --- py-polars/polars/dataframe/frame.py | 33 +++++++ py-polars/tests/unit/dataframe/test_show.py | 100 ++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index d5cdb4333153..24af087bd601 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -178,6 +178,7 @@ UnstackDirection, ) from polars._utils.various import NoDefault + from polars.config import TableFormatNames from polars.interchange.dataframe import PolarsDataFrame from polars.ml.torch import PolarsDataset @@ -11272,6 +11273,9 @@ def show( float_precision: int | None = None, fmt_str_lengths: int | None = None, fmt_table_cell_list_len: int | None = None, + tbl_cell_alignment: Literal["LEFT", "CENTER", "RIGHT"] | None = None, + tbl_cell_numeric_alignment: Literal["LEFT", "CENTER", "RIGHT"] | None = None, + tbl_formatting: TableFormatNames | None = None, tbl_cols: int | None = None, ) -> None: """ @@ -11291,6 +11295,32 @@ def show( fmt_table_cell_list_len : int Number of elements to display for List values. See :func:`Config.set_fmt_table_cell_list_len` for more information. + tbl_cell_alignment : str + Set table cell alignment. Supported options are: + * "LEFT": left aligned + * "CENTER": center aligned + * "RIGHT": right aligned + tbl_cell_numeric_alignment : str + Set table cell alignment for numeric columns. Supported options are: + * "LEFT": left aligned + * "CENTER": center aligned + * "RIGHT": right aligned + tbl_formatting : str + Set table formatting style. Supported options are: + * "ASCII_FULL": ASCII, with all borders and lines, including row dividers. + * "ASCII_FULL_CONDENSED": Same as ASCII_FULL, but with dense row spacing. + * "ASCII_NO_BORDERS": ASCII, no borders. + * "ASCII_BORDERS_ONLY": ASCII, borders only. + * "ASCII_BORDERS_ONLY_CONDENSED": ASCII, borders only, dense row spacing. + * "ASCII_HORIZONTAL_ONLY": ASCII, horizontal lines only. + * "ASCII_MARKDOWN": Markdown format (ascii ellipses for truncated values). + * "MARKDOWN": Markdown format (utf8 ellipses for truncated values). + * "UTF8_FULL": UTF8, with all borders and lines, including row dividers. + * "UTF8_FULL_CONDENSED": Same as UTF8_FULL, but with dense row spacing. + * "UTF8_NO_BORDERS": UTF8, no borders. + * "UTF8_BORDERS_ONLY": UTF8, borders only. + * "UTF8_HORIZONTAL_ONLY": UTF8, horizontal lines only. + * "NOTHING": No borders or other lines. tbl_cols : int Number of columns to display. See :func:`Config.set_tbl_cols` for more information. @@ -11347,6 +11377,9 @@ def show( float_precision=float_precision, fmt_str_lengths=fmt_str_lengths, fmt_table_cell_list_len=fmt_table_cell_list_len, + tbl_cell_alignment=tbl_cell_alignment, + tbl_cell_numeric_alignment=tbl_cell_numeric_alignment, + tbl_formatting=tbl_formatting, tbl_cols=tbl_cols, tbl_rows=tbl_rows, ): diff --git a/py-polars/tests/unit/dataframe/test_show.py b/py-polars/tests/unit/dataframe/test_show.py index 44ca312731aa..549f4419a9ce 100644 --- a/py-polars/tests/unit/dataframe/test_show.py +++ b/py-polars/tests/unit/dataframe/test_show.py @@ -10,6 +10,7 @@ def test_df_show_default(capsys: pytest.CaptureFixture[str]) -> None: "bar": ["a", "b", "c", "d", "e", "f", "g"], } ) + df.show() out, _ = capsys.readouterr() assert ( @@ -37,6 +38,7 @@ def test_df_show_positive_limit(capsys: pytest.CaptureFixture[str]) -> None: "bar": ["a", "b", "c", "d", "e", "f", "g"], } ) + df.show(3) out, _ = capsys.readouterr() assert ( @@ -62,6 +64,7 @@ def test_df_show_negative_limit(capsys: pytest.CaptureFixture[str]) -> None: "bar": ["a", "b", "c", "d", "e", "f", "g"], } ) + df.show(-5) out, _ = capsys.readouterr() assert ( @@ -86,6 +89,7 @@ def test_df_show_no_limit(capsys: pytest.CaptureFixture[str]) -> None: "bar": ["a", "b", "c", "d", "e", "f", "g"], } ) + df.show(limit=None) out, _ = capsys.readouterr() assert ( @@ -113,6 +117,7 @@ def test_df_show_float_precision(capsys: pytest.CaptureFixture[str]) -> None: from math import e, pi df = pl.DataFrame({"const": ["pi", "e"], "value": [pi, e]}) + df.show(float_precision=15) out, _ = capsys.readouterr() assert ( @@ -156,6 +161,7 @@ def test_df_show_fmt_str_lengths(capsys: pytest.CaptureFixture[str]) -> None: ] } ) + df.show(fmt_str_lengths=10) out, _ = capsys.readouterr() assert ( @@ -171,6 +177,7 @@ def test_df_show_fmt_str_lengths(capsys: pytest.CaptureFixture[str]) -> None: └─────────────┘ """ ) + df.show(fmt_str_lengths=50) out, _ = capsys.readouterr() assert ( @@ -223,6 +230,99 @@ def test_df_show_fmt_table_cell_list_len(capsys: pytest.CaptureFixture[str]) -> ) +@pl.Config(tbl_cell_alignment="LEFT") +def test_df_show_tbl_cell_alignment(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame( + {"column_abc": [1.0, 2.5, 5.0], "column_xyz": [True, False, True]} + ) + + df.show(tbl_cell_alignment="RIGHT") + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 2) +┌────────────┬────────────┐ +│ column_abc ┆ column_xyz │ +│ --- ┆ --- │ +│ f64 ┆ bool │ +╞════════════╪════════════╡ +│ 1.0 ┆ true │ +│ 2.5 ┆ false │ +│ 5.0 ┆ true │ +└────────────┴────────────┘ +""" + ) + + +@pl.Config(tbl_cell_numeric_alignment="LEFT") +def test_df_show_tbl_cell_numeric_alignment(capsys: pytest.CaptureFixture[str]) -> None: + from datetime import date + + df = pl.DataFrame( + { + "abc": [11, 2, 333], + "mno": [date(2023, 10, 29), None, date(2001, 7, 5)], + "xyz": [True, False, None], + } + ) + + df.show(tbl_cell_numeric_alignment="RIGHT") + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 3) +┌─────┬────────────┬───────┐ +│ abc ┆ mno ┆ xyz │ +│ --- ┆ --- ┆ --- │ +│ i64 ┆ date ┆ bool │ +╞═════╪════════════╪═══════╡ +│ 11 ┆ 2023-10-29 ┆ true │ +│ 2 ┆ null ┆ false │ +│ 333 ┆ 2001-07-05 ┆ null │ +└─────┴────────────┴───────┘ +""" + ) + + +@pl.Config(tbl_formatting="UTF8_FULL") +def test_df_show_tbl_formatting(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]}) + + df.show(tbl_formatting="ASCII_FULL") + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 3) ++-----+-----+-----+ +| a | b | c | +| --- | --- | --- | +| i64 | i64 | i64 | ++=================+ +| 1 | 4 | 7 | +|-----+-----+-----| +| 2 | 5 | 8 | +|-----+-----+-----| +| 3 | 6 | 9 | ++-----+-----+-----+ +""" + ) + + df.show(tbl_formatting="MARKDOWN") + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 3) +| a | b | c | +| --- | --- | --- | +| i64 | i64 | i64 | +|-----|-----|-----| +| 1 | 4 | 7 | +| 2 | 5 | 8 | +| 3 | 6 | 9 | +""" + ) + + @pl.Config(tbl_cols=2) def test_df_show_tbl_cols(capsys: pytest.CaptureFixture[str]) -> None: df = pl.DataFrame({str(i): [i] for i in range(10)}) From 1c6a1672cb46bade495b96d7f56e37d3f46fe322 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 01:51:39 +0100 Subject: [PATCH 08/20] mandatory OCD commit --- py-polars/polars/dataframe/frame.py | 10 +-- py-polars/tests/unit/dataframe/test_show.py | 70 ++++++++++----------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index 24af087bd601..8128c21bed87 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -11275,8 +11275,8 @@ def show( fmt_table_cell_list_len: int | None = None, tbl_cell_alignment: Literal["LEFT", "CENTER", "RIGHT"] | None = None, tbl_cell_numeric_alignment: Literal["LEFT", "CENTER", "RIGHT"] | None = None, - tbl_formatting: TableFormatNames | None = None, tbl_cols: int | None = None, + tbl_formatting: TableFormatNames | None = None, ) -> None: """ Show the first `n` rows. @@ -11305,6 +11305,9 @@ def show( * "LEFT": left aligned * "CENTER": center aligned * "RIGHT": right aligned + tbl_cols : int + Number of columns to display. See :func:`Config.set_tbl_cols` for more + information. tbl_formatting : str Set table formatting style. Supported options are: * "ASCII_FULL": ASCII, with all borders and lines, including row dividers. @@ -11321,9 +11324,6 @@ def show( * "UTF8_BORDERS_ONLY": UTF8, borders only. * "UTF8_HORIZONTAL_ONLY": UTF8, horizontal lines only. * "NOTHING": No borders or other lines. - tbl_cols : int - Number of columns to display. See :func:`Config.set_tbl_cols` for more - information. See Also -------- @@ -11379,8 +11379,8 @@ def show( fmt_table_cell_list_len=fmt_table_cell_list_len, tbl_cell_alignment=tbl_cell_alignment, tbl_cell_numeric_alignment=tbl_cell_numeric_alignment, - tbl_formatting=tbl_formatting, tbl_cols=tbl_cols, + tbl_formatting=tbl_formatting, tbl_rows=tbl_rows, ): if _in_notebook(): diff --git a/py-polars/tests/unit/dataframe/test_show.py b/py-polars/tests/unit/dataframe/test_show.py index 549f4419a9ce..3247f9a8de96 100644 --- a/py-polars/tests/unit/dataframe/test_show.py +++ b/py-polars/tests/unit/dataframe/test_show.py @@ -284,6 +284,41 @@ def test_df_show_tbl_cell_numeric_alignment(capsys: pytest.CaptureFixture[str]) ) +@pl.Config(tbl_cols=2) +def test_df_show_tbl_cols(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({str(i): [i] for i in range(10)}) + + df.show(tbl_cols=3) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (1, 10) +┌─────┬─────┬───┬─────┐ +│ 0 ┆ 1 ┆ … ┆ 9 │ +│ --- ┆ --- ┆ ┆ --- │ +│ i64 ┆ i64 ┆ ┆ i64 │ +╞═════╪═════╪═══╪═════╡ +│ 0 ┆ 1 ┆ … ┆ 9 │ +└─────┴─────┴───┴─────┘ +""" + ) + + df.show(tbl_cols=7) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (1, 10) +┌─────┬─────┬─────┬─────┬───┬─────┬─────┬─────┐ +│ 0 ┆ 1 ┆ 2 ┆ 3 ┆ … ┆ 7 ┆ 8 ┆ 9 │ +│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- │ +│ i64 ┆ i64 ┆ i64 ┆ i64 ┆ ┆ i64 ┆ i64 ┆ i64 │ +╞═════╪═════╪═════╪═════╪═══╪═════╪═════╪═════╡ +│ 0 ┆ 1 ┆ 2 ┆ 3 ┆ … ┆ 7 ┆ 8 ┆ 9 │ +└─────┴─────┴─────┴─────┴───┴─────┴─────┴─────┘ +""" + ) + + @pl.Config(tbl_formatting="UTF8_FULL") def test_df_show_tbl_formatting(capsys: pytest.CaptureFixture[str]) -> None: df = pl.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]}) @@ -321,38 +356,3 @@ def test_df_show_tbl_formatting(capsys: pytest.CaptureFixture[str]) -> None: | 3 | 6 | 9 | """ ) - - -@pl.Config(tbl_cols=2) -def test_df_show_tbl_cols(capsys: pytest.CaptureFixture[str]) -> None: - df = pl.DataFrame({str(i): [i] for i in range(10)}) - - df.show(tbl_cols=3) - out, _ = capsys.readouterr() - assert ( - out - == """shape: (1, 10) -┌─────┬─────┬───┬─────┐ -│ 0 ┆ 1 ┆ … ┆ 9 │ -│ --- ┆ --- ┆ ┆ --- │ -│ i64 ┆ i64 ┆ ┆ i64 │ -╞═════╪═════╪═══╪═════╡ -│ 0 ┆ 1 ┆ … ┆ 9 │ -└─────┴─────┴───┴─────┘ -""" - ) - - df.show(tbl_cols=7) - out, _ = capsys.readouterr() - assert ( - out - == """shape: (1, 10) -┌─────┬─────┬─────┬─────┬───┬─────┬─────┬─────┐ -│ 0 ┆ 1 ┆ 2 ┆ 3 ┆ … ┆ 7 ┆ 8 ┆ 9 │ -│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- │ -│ i64 ┆ i64 ┆ i64 ┆ i64 ┆ ┆ i64 ┆ i64 ┆ i64 │ -╞═════╪═════╪═════╪═════╪═══╪═════╪═════╪═════╡ -│ 0 ┆ 1 ┆ 2 ┆ 3 ┆ … ┆ 7 ┆ 8 ┆ 9 │ -└─────┴─────┴─────┴─────┴───┴─────┴─────┴─────┘ -""" - ) From 96cf7ad78efdc266806f6cefb9989d9e37272aab Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 02:55:31 +0100 Subject: [PATCH 09/20] rename `LazyFrame.show` parameter to `limit` --- py-polars/polars/lazyframe/frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py-polars/polars/lazyframe/frame.py b/py-polars/polars/lazyframe/frame.py index a24603fbcc32..02a9fa80cd07 100644 --- a/py-polars/polars/lazyframe/frame.py +++ b/py-polars/polars/lazyframe/frame.py @@ -6921,7 +6921,7 @@ def show( Parameters ---------- - n : int + limit : int Number of rows to show. If None is passed, return all rows. float_precision : int Number of decimal places to display for floating point values. See From b5fcbecd37c1da7aa6277ab3592bca1d32bcd15a Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 02:57:31 +0100 Subject: [PATCH 10/20] add all config options to show methods --- py-polars/polars/dataframe/frame.py | 58 ++++ py-polars/polars/lazyframe/frame.py | 91 ++++++ py-polars/tests/unit/dataframe/test_show.py | 294 ++++++++++++++++++++ py-polars/tests/unit/lazyframe/test_show.py | 16 ++ 4 files changed, 459 insertions(+) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index 8128c21bed87..bc63a2e9c85a 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -31,6 +31,7 @@ from polars import functions as F from polars._typing import ( DbWriteMode, + FloatFmt, JaxExportType, TorchExportType, ) @@ -11270,13 +11271,26 @@ def show( self, limit: int | None = 5, *, + ascii_tables: bool | None = None, + auto_structify: bool | None = None, + decimal_separator: str | None = None, + thousands_separator: str | bool | None = None, float_precision: int | None = None, + fmt_float: FloatFmt | None = None, fmt_str_lengths: int | None = None, fmt_table_cell_list_len: int | None = None, tbl_cell_alignment: Literal["LEFT", "CENTER", "RIGHT"] | None = None, tbl_cell_numeric_alignment: Literal["LEFT", "CENTER", "RIGHT"] | None = None, tbl_cols: int | None = None, + tbl_column_data_type_inline: bool | None = None, + tbl_dataframe_shape_below: bool | None = None, tbl_formatting: TableFormatNames | None = None, + tbl_hide_column_data_types: bool | None = None, + tbl_hide_column_names: bool | None = None, + tbl_hide_dtype_separator: bool | None = None, + tbl_hide_dataframe_shape: bool | None = None, + tbl_width_chars: int | None = None, + trim_decimal_zeros: bool | None = None, ) -> None: """ Show the first `n` rows. @@ -11286,9 +11300,23 @@ def show( limit : int Numbers of rows to show. If a negative value is passed, return all rows except the last `abs(n)`. If None is passed, return all rows. + ascii_tables : bool + Use ASCII characters to display table outlines. Set False to revert to the + default UTF8_FULL_CONDENSED formatting style. + auto_structify : bool + Allow multi-output expressions to be automatically turned into Structs. + decimal_separator : str + Set the decimal separator character. + thousands_separator : str + Set the thousands grouping separator character. float_precision : int Number of decimal places to display for floating point values. See :func:`Config.set_float_precision` for more information. + fmt_float : {"mixed", "full"} + Control how floating point values are displayed. Supported options are: + * "mixed": Limit the number of decimal places and use scientific notation + for large/small values. + * "full": Print the full precision of the floating point number. fmt_str_lengths : int Number of characters to display for string values. See :func:`Config.set_fmt_str_lengths` for more information. @@ -11308,6 +11336,11 @@ def show( tbl_cols : int Number of columns to display. See :func:`Config.set_tbl_cols` for more information. + tbl_column_data_type_inline : bool + Moves the data type inline with the column name (to the right, in + parentheses). + tbl_dataframe_shape_below : bool + Print the DataFrame shape information below the data when displaying tables. tbl_formatting : str Set table formatting style. Supported options are: * "ASCII_FULL": ASCII, with all borders and lines, including row dividers. @@ -11324,6 +11357,18 @@ def show( * "UTF8_BORDERS_ONLY": UTF8, borders only. * "UTF8_HORIZONTAL_ONLY": UTF8, horizontal lines only. * "NOTHING": No borders or other lines. + tbl_hide_column_data_types : bool + Hide table column data types (i64, f64, str etc.). + tbl_hide_column_names : bool + Hide table column names. + tbl_hide_dtype_separator : bool + Hide the '---' separator between the column names and column types. + tbl_hide_dataframe_shape : bool + Hide the DataFrame shape information when displaying tables. + tbl_width_chars : int + Set the maximum width of a table in characters. + trim_decimal_zeros : bool + Strip trailing zeros from Decimal data type values. See Also -------- @@ -11374,14 +11419,27 @@ def show( tbl_rows = limit with Config( + ascii_tables=ascii_tables, + auto_structify=auto_structify, + decimal_separator=decimal_separator, + thousands_separator=thousands_separator, float_precision=float_precision, + fmt_float=fmt_float, fmt_str_lengths=fmt_str_lengths, fmt_table_cell_list_len=fmt_table_cell_list_len, tbl_cell_alignment=tbl_cell_alignment, tbl_cell_numeric_alignment=tbl_cell_numeric_alignment, tbl_cols=tbl_cols, + tbl_column_data_type_inline=tbl_column_data_type_inline, + tbl_dataframe_shape_below=tbl_dataframe_shape_below, tbl_formatting=tbl_formatting, + tbl_hide_column_data_types=tbl_hide_column_data_types, + tbl_hide_column_names=tbl_hide_column_names, + tbl_hide_dtype_separator=tbl_hide_dtype_separator, + tbl_hide_dataframe_shape=tbl_hide_dataframe_shape, tbl_rows=tbl_rows, + tbl_width_chars=tbl_width_chars, + trim_decimal_zeros=trim_decimal_zeros, ): if _in_notebook(): print("In notebook") diff --git a/py-polars/polars/lazyframe/frame.py b/py-polars/polars/lazyframe/frame.py index 02a9fa80cd07..a8e2efeaab8f 100644 --- a/py-polars/polars/lazyframe/frame.py +++ b/py-polars/polars/lazyframe/frame.py @@ -103,6 +103,7 @@ EngineType, ExplainFormat, FillNullStrategy, + FloatFmt, FrameInitTypes, IntoExpr, IntoExprColumn, @@ -118,6 +119,7 @@ StartBy, UniqueKeepStrategy, ) + from polars.config import TableFormatNames from polars.dependencies import numpy as np if sys.version_info >= (3, 10): @@ -6911,10 +6913,26 @@ def show( self, limit: int | None = 5, *, + ascii_tables: bool | None = None, + auto_structify: bool | None = None, + decimal_separator: str | None = None, + thousands_separator: str | bool | None = None, float_precision: int | None = None, + fmt_float: FloatFmt | None = None, fmt_str_lengths: int | None = None, fmt_table_cell_list_len: int | None = None, + tbl_cell_alignment: Literal["LEFT", "CENTER", "RIGHT"] | None = None, + tbl_cell_numeric_alignment: Literal["LEFT", "CENTER", "RIGHT"] | None = None, tbl_cols: int | None = None, + tbl_column_data_type_inline: bool | None = None, + tbl_dataframe_shape_below: bool | None = None, + tbl_formatting: TableFormatNames | None = None, + tbl_hide_column_data_types: bool | None = None, + tbl_hide_column_names: bool | None = None, + tbl_hide_dtype_separator: bool | None = None, + tbl_hide_dataframe_shape: bool | None = None, + tbl_width_chars: int | None = None, + trim_decimal_zeros: bool | None = None, ) -> None: """ Show the first `n` rows. @@ -6923,18 +6941,75 @@ def show( ---------- limit : int Number of rows to show. If None is passed, return all rows. + ascii_tables : bool + Use ASCII characters to display table outlines. Set False to revert to the + default UTF8_FULL_CONDENSED formatting style. + auto_structify : bool + Allow multi-output expressions to be automatically turned into Structs. + decimal_separator : str + Set the decimal separator character. + thousands_separator : str + Set the thousands grouping separator character. float_precision : int Number of decimal places to display for floating point values. See :func:`Config.set_float_precision` for more information. + fmt_float : {"mixed", "full"} + Control how floating point values are displayed. Supported options are: + * "mixed": Limit the number of decimal places and use scientific notation + for large/small values. + * "full": Print the full precision of the floating point number. fmt_str_lengths : int Number of characters to display for string values. See :func:`Config.set_fmt_str_lengths` for more information. fmt_table_cell_list_len : int Number of elements to display for List values. See :func:`Config.set_fmt_table_cell_list_len` for more information. + tbl_cell_alignment : str + Set table cell alignment. Supported options are: + * "LEFT": left aligned + * "CENTER": center aligned + * "RIGHT": right aligned + tbl_cell_numeric_alignment : str + Set table cell alignment for numeric columns. Supported options are: + * "LEFT": left aligned + * "CENTER": center aligned + * "RIGHT": right aligned tbl_cols : int Number of columns to display. See :func:`Config.set_tbl_cols` for more information. + tbl_column_data_type_inline : bool + Moves the data type inline with the column name (to the right, in + parentheses). + tbl_dataframe_shape_below : bool + Print the DataFrame shape information below the data when displaying tables. + tbl_formatting : str + Set table formatting style. Supported options are: + * "ASCII_FULL": ASCII, with all borders and lines, including row dividers. + * "ASCII_FULL_CONDENSED": Same as ASCII_FULL, but with dense row spacing. + * "ASCII_NO_BORDERS": ASCII, no borders. + * "ASCII_BORDERS_ONLY": ASCII, borders only. + * "ASCII_BORDERS_ONLY_CONDENSED": ASCII, borders only, dense row spacing. + * "ASCII_HORIZONTAL_ONLY": ASCII, horizontal lines only. + * "ASCII_MARKDOWN": Markdown format (ascii ellipses for truncated values). + * "MARKDOWN": Markdown format (utf8 ellipses for truncated values). + * "UTF8_FULL": UTF8, with all borders and lines, including row dividers. + * "UTF8_FULL_CONDENSED": Same as UTF8_FULL, but with dense row spacing. + * "UTF8_NO_BORDERS": UTF8, no borders. + * "UTF8_BORDERS_ONLY": UTF8, borders only. + * "UTF8_HORIZONTAL_ONLY": UTF8, horizontal lines only. + * "NOTHING": No borders or other lines. + tbl_hide_column_data_types : bool + Hide table column data types (i64, f64, str etc.). + tbl_hide_column_names : bool + Hide table column names. + tbl_hide_dtype_separator : bool + Hide the '---' separator between the column names and column types. + tbl_hide_dataframe_shape : bool + Hide the DataFrame shape information when displaying tables. + tbl_width_chars : int + Set the maximum width of a table in characters. + trim_decimal_zeros : bool + Strip trailing zeros from Decimal data type values. Warnings -------- @@ -6986,10 +7061,26 @@ def show( lf.collect().show( limit, + ascii_tables=ascii_tables, + auto_structify=auto_structify, + decimal_separator=decimal_separator, + thousands_separator=thousands_separator, float_precision=float_precision, + fmt_float=fmt_float, fmt_str_lengths=fmt_str_lengths, fmt_table_cell_list_len=fmt_table_cell_list_len, + tbl_cell_alignment=tbl_cell_alignment, + tbl_cell_numeric_alignment=tbl_cell_numeric_alignment, tbl_cols=tbl_cols, + tbl_column_data_type_inline=tbl_column_data_type_inline, + tbl_dataframe_shape_below=tbl_dataframe_shape_below, + tbl_formatting=tbl_formatting, + tbl_hide_column_data_types=tbl_hide_column_data_types, + tbl_hide_column_names=tbl_hide_column_names, + tbl_hide_dtype_separator=tbl_hide_dtype_separator, + tbl_hide_dataframe_shape=tbl_hide_dataframe_shape, + tbl_width_chars=tbl_width_chars, + trim_decimal_zeros=trim_decimal_zeros, ) def _to_metadata( diff --git a/py-polars/tests/unit/dataframe/test_show.py b/py-polars/tests/unit/dataframe/test_show.py index 3247f9a8de96..58eba1efc144 100644 --- a/py-polars/tests/unit/dataframe/test_show.py +++ b/py-polars/tests/unit/dataframe/test_show.py @@ -112,6 +112,98 @@ def test_df_show_no_limit(capsys: pytest.CaptureFixture[str]) -> None: ) +# FIXME: ascii_tables config option doesn't work. +@pytest.mark.skip("`ascii_tables` doesn't work") +@pl.Config(ascii_tables=False) +def test_df_show_ascii_tables(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({"abc": [1.0, 2.5, 5.0], "xyz": [True, False, True]}) + + df.show(ascii_tables=True) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 2) ++-----+-------+ +| abc | xyz | +| --- | --- | +| f64 | bool | ++=============+ +| 1.0 | true | +| 2.5 | false | +| 5.0 | true | ++-----+-------+ +""" + ) + + +# FIXME: auto_structify config option doesn't work. +@pytest.mark.skip("`auto_structify` doesn't work") +@pl.Config(auto_structify=False) +def test_df_show_auto_structify(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({"v": [1, 2, 3], "v2": [4, 5, 6]}) + + df.show(auto_structify=True) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 1) +┌───────────┐ +│ v │ +│ --- │ +│ struct[2] │ +╞═══════════╡ +│ {1,4} │ +│ {2,5} │ +│ {3,6} │ +└───────────┘ +""" + ) + + +@pl.Config(decimal_separator=",") +def test_df_show_decimal_separator(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({"v": [9876.54321, 1010101.0, -123456.78]}) + + df.show(decimal_separator=",") + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 1) +┌────────────┐ +│ v │ +│ --- │ +│ f64 │ +╞════════════╡ +│ 9876,54321 │ +│ 1,010101e6 │ +│ -123456,78 │ +└────────────┘ +""" + ) + + +@pl.Config(thousands_separator=".") +def test_df_show_thousands_separator(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({"v": [9876.54321, 1010101.0, -123456.78]}) + + df.show(thousands_separator=" ") + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 1) +┌─────────────┐ +│ v │ +│ --- │ +│ f64 │ +╞═════════════╡ +│ 9 876.54321 │ +│ 1.010101e6 │ +│ -123 456.78 │ +└─────────────┘ +""" + ) + + @pl.Config(float_precision=8) def test_df_show_float_precision(capsys: pytest.CaptureFixture[str]) -> None: from math import e, pi @@ -151,6 +243,28 @@ def test_df_show_float_precision(capsys: pytest.CaptureFixture[str]) -> None: ) +@pl.Config(fmt_float="full") +def test_df_show_fmt_float(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({"num": [1.2304980958725870923, 1e6, 1e-8]}) + + df.show(fmt_float="mixed") + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 1) +┌───────────┐ +│ num │ +│ --- │ +│ f64 │ +╞═══════════╡ +│ 1.230498 │ +│ 1e6 │ +│ 1.0000e-8 │ +└───────────┘ +""" + ) + + @pl.Config(fmt_str_lengths=20) def test_df_show_fmt_str_lengths(capsys: pytest.CaptureFixture[str]) -> None: df = pl.DataFrame( @@ -319,6 +433,48 @@ def test_df_show_tbl_cols(capsys: pytest.CaptureFixture[str]) -> None: ) +@pl.Config(tbl_column_data_type_inline=False) +def test_df_show_tbl_column_data_type_inline( + capsys: pytest.CaptureFixture[str], +) -> None: + df = pl.DataFrame({"abc": [1.0, 2.5, 5.0], "xyz": [True, False, True]}) + + df.show(tbl_column_data_type_inline=True) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 2) +┌───────────┬────────────┐ +│ abc (f64) ┆ xyz (bool) │ +╞═══════════╪════════════╡ +│ 1.0 ┆ true │ +│ 2.5 ┆ false │ +│ 5.0 ┆ true │ +└───────────┴────────────┘ +""" + ) + + +@pl.Config(tbl_dataframe_shape_below=False) +def test_df_show_tbl_dataframe_shape_below(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({"abc": [1.0, 2.5, 5.0], "xyz": [True, False, True]}) + + df.show(tbl_dataframe_shape_below=True) + out, _ = capsys.readouterr() + assert out == ( + "┌─────┬───────┐\n" + "│ abc ┆ xyz │\n" + "│ --- ┆ --- │\n" + "│ f64 ┆ bool │\n" + "╞═════╪═══════╡\n" + "│ 1.0 ┆ true │\n" + "│ 2.5 ┆ false │\n" + "│ 5.0 ┆ true │\n" + "└─────┴───────┘\n" + "shape: (3, 2)\n" + ) + + @pl.Config(tbl_formatting="UTF8_FULL") def test_df_show_tbl_formatting(capsys: pytest.CaptureFixture[str]) -> None: df = pl.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]}) @@ -356,3 +512,141 @@ def test_df_show_tbl_formatting(capsys: pytest.CaptureFixture[str]) -> None: | 3 | 6 | 9 | """ ) + + +@pl.Config(tbl_hide_column_data_types=False) +def test_df_show_tbl_hide_column_data_types(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({"abc": [1.0, 2.5, 5.0], "xyz": [True, False, True]}) + + df.show(tbl_hide_column_data_types=True) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 2) +┌─────┬───────┐ +│ abc ┆ xyz │ +╞═════╪═══════╡ +│ 1.0 ┆ true │ +│ 2.5 ┆ false │ +│ 5.0 ┆ true │ +└─────┴───────┘ +""" + ) + + +@pl.Config(tbl_hide_column_names=False) +def test_df_show_tbl_hide_column_names(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({"abc": [1.0, 2.5, 5.0], "xyz": [True, False, True]}) + + df.show(tbl_hide_column_names=True) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 2) +┌─────┬───────┐ +│ f64 ┆ bool │ +╞═════╪═══════╡ +│ 1.0 ┆ true │ +│ 2.5 ┆ false │ +│ 5.0 ┆ true │ +└─────┴───────┘ +""" + ) + + +@pl.Config(tbl_hide_dtype_separator=False) +def test_df_show_tbl_hide_dtype_separator(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({"abc": [1.0, 2.5, 5.0], "xyz": [True, False, True]}) + + df.show(tbl_hide_dtype_separator=True) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (3, 2) +┌─────┬───────┐ +│ abc ┆ xyz │ +│ f64 ┆ bool │ +╞═════╪═══════╡ +│ 1.0 ┆ true │ +│ 2.5 ┆ false │ +│ 5.0 ┆ true │ +└─────┴───────┘ +""" + ) + + +@pl.Config(tbl_hide_dataframe_shape=False) +def test_df_show_tbl_hide_dataframe_shape(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame({"abc": [1.0, 2.5, 5.0], "xyz": [True, False, True]}) + + df.show(tbl_hide_dataframe_shape=True) + out, _ = capsys.readouterr() + assert out == ( + "┌─────┬───────┐\n" + "│ abc ┆ xyz │\n" + "│ --- ┆ --- │\n" + "│ f64 ┆ bool │\n" + "╞═════╪═══════╡\n" + "│ 1.0 ┆ true │\n" + "│ 2.5 ┆ false │\n" + "│ 5.0 ┆ true │\n" + "└─────┴───────┘\n" + ) + + +@pl.Config(tbl_width_chars=100) +def test_df_show_tbl_width_chars(capsys: pytest.CaptureFixture[str]) -> None: + df = pl.DataFrame( + { + "id": ["SEQ1", "SEQ2"], + "seq": ["ATGATAAAGGAG", "GCAACGCATATA"], + } + ) + + df.show(tbl_width_chars=12) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (2, 2) +┌─────┬─────┐ +│ id ┆ seq │ +│ --- ┆ --- │ +│ str ┆ str │ +╞═════╪═════╡ +│ SEQ ┆ ATG │ +│ 1 ┆ ATA │ +│ ┆ AAG │ +│ ┆ GAG │ +│ SEQ ┆ GCA │ +│ 2 ┆ ACG │ +│ ┆ CAT │ +│ ┆ ATA │ +└─────┴─────┘ +""" + ) + + +@pl.Config(trim_decimal_zeros=False) +def test_df_show_trim_decimal_zeros(capsys: pytest.CaptureFixture[str]) -> None: + from decimal import Decimal as D + + df = pl.DataFrame( + data={"d": [D("1.01000"), D("-5.67890")]}, + schema={"d": pl.Decimal(scale=5)}, + ) + + df.show(trim_decimal_zeros=True) + out, _ = capsys.readouterr() + assert ( + out + == """shape: (2, 1) +┌──────────────┐ +│ d │ +│ --- │ +│ decimal[*,5] │ +╞══════════════╡ +│ 1.01 │ +│ -5.6789 │ +└──────────────┘ +""" + ) diff --git a/py-polars/tests/unit/lazyframe/test_show.py b/py-polars/tests/unit/lazyframe/test_show.py index cee36e3a5c1d..1f81e020eacb 100644 --- a/py-polars/tests/unit/lazyframe/test_show.py +++ b/py-polars/tests/unit/lazyframe/test_show.py @@ -18,10 +18,26 @@ def test_lf_show_calls_df_show() -> None: df_show.assert_called_once_with( 5, + ascii_tables=None, + auto_structify=None, + decimal_separator=None, + thousands_separator=None, float_precision=None, + fmt_float=None, fmt_str_lengths=None, fmt_table_cell_list_len=None, + tbl_cell_alignment=None, + tbl_cell_numeric_alignment=None, tbl_cols=None, + tbl_column_data_type_inline=None, + tbl_dataframe_shape_below=None, + tbl_formatting=None, + tbl_hide_column_data_types=None, + tbl_hide_column_names=None, + tbl_hide_dtype_separator=None, + tbl_hide_dataframe_shape=None, + tbl_width_chars=None, + trim_decimal_zeros=None, ) From 221be3d59580d62c8adc8e9ac0a120085ba3994e Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 10:32:21 +0100 Subject: [PATCH 11/20] remove debug print --- py-polars/polars/dataframe/frame.py | 1 - 1 file changed, 1 deletion(-) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index bc63a2e9c85a..54297e127071 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -11442,7 +11442,6 @@ def show( trim_decimal_zeros=trim_decimal_zeros, ): if _in_notebook(): - print("In notebook") from IPython.display import display_html display_html(df) From c630cdac0738538fb818856e4a59824ba8b97e6f Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 10:47:52 +0100 Subject: [PATCH 12/20] fix ascii_tables setting --- py-polars/polars/dataframe/frame.py | 9 +++++++++ py-polars/tests/unit/dataframe/test_show.py | 2 -- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index 54297e127071..38c0ed1c7016 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -11418,6 +11418,15 @@ def show( else: tbl_rows = limit + if ascii_tables is not None and tbl_formatting is not None: + msg = "Can not set `ascii_tables` and `tbl_formatting` at the same time." + raise ValueError(msg) + if ascii_tables is not None: + if ascii_tables: + tbl_formatting = "ASCII_FULL_CONDENSED" + else: + tbl_formatting = "UTF8_FULL_CONDENSED" + with Config( ascii_tables=ascii_tables, auto_structify=auto_structify, diff --git a/py-polars/tests/unit/dataframe/test_show.py b/py-polars/tests/unit/dataframe/test_show.py index 58eba1efc144..2abc0a0bd0bb 100644 --- a/py-polars/tests/unit/dataframe/test_show.py +++ b/py-polars/tests/unit/dataframe/test_show.py @@ -112,8 +112,6 @@ def test_df_show_no_limit(capsys: pytest.CaptureFixture[str]) -> None: ) -# FIXME: ascii_tables config option doesn't work. -@pytest.mark.skip("`ascii_tables` doesn't work") @pl.Config(ascii_tables=False) def test_df_show_ascii_tables(capsys: pytest.CaptureFixture[str]) -> None: df = pl.DataFrame({"abc": [1.0, 2.5, 5.0], "xyz": [True, False, True]}) From 94dc6dcca22e02ee3ef88704d55e6e87f96d7f31 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 10:54:44 +0100 Subject: [PATCH 13/20] remove auto_structify option --- py-polars/polars/dataframe/frame.py | 4 ---- py-polars/polars/lazyframe/frame.py | 4 ---- py-polars/tests/unit/dataframe/test_show.py | 24 --------------------- py-polars/tests/unit/lazyframe/test_show.py | 1 - 4 files changed, 33 deletions(-) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index 38c0ed1c7016..b9fb85e14048 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -11272,7 +11272,6 @@ def show( limit: int | None = 5, *, ascii_tables: bool | None = None, - auto_structify: bool | None = None, decimal_separator: str | None = None, thousands_separator: str | bool | None = None, float_precision: int | None = None, @@ -11303,8 +11302,6 @@ def show( ascii_tables : bool Use ASCII characters to display table outlines. Set False to revert to the default UTF8_FULL_CONDENSED formatting style. - auto_structify : bool - Allow multi-output expressions to be automatically turned into Structs. decimal_separator : str Set the decimal separator character. thousands_separator : str @@ -11429,7 +11426,6 @@ def show( with Config( ascii_tables=ascii_tables, - auto_structify=auto_structify, decimal_separator=decimal_separator, thousands_separator=thousands_separator, float_precision=float_precision, diff --git a/py-polars/polars/lazyframe/frame.py b/py-polars/polars/lazyframe/frame.py index a8e2efeaab8f..c3e840ac4fba 100644 --- a/py-polars/polars/lazyframe/frame.py +++ b/py-polars/polars/lazyframe/frame.py @@ -6914,7 +6914,6 @@ def show( limit: int | None = 5, *, ascii_tables: bool | None = None, - auto_structify: bool | None = None, decimal_separator: str | None = None, thousands_separator: str | bool | None = None, float_precision: int | None = None, @@ -6944,8 +6943,6 @@ def show( ascii_tables : bool Use ASCII characters to display table outlines. Set False to revert to the default UTF8_FULL_CONDENSED formatting style. - auto_structify : bool - Allow multi-output expressions to be automatically turned into Structs. decimal_separator : str Set the decimal separator character. thousands_separator : str @@ -7062,7 +7059,6 @@ def show( lf.collect().show( limit, ascii_tables=ascii_tables, - auto_structify=auto_structify, decimal_separator=decimal_separator, thousands_separator=thousands_separator, float_precision=float_precision, diff --git a/py-polars/tests/unit/dataframe/test_show.py b/py-polars/tests/unit/dataframe/test_show.py index 2abc0a0bd0bb..df2734b32cf7 100644 --- a/py-polars/tests/unit/dataframe/test_show.py +++ b/py-polars/tests/unit/dataframe/test_show.py @@ -134,30 +134,6 @@ def test_df_show_ascii_tables(capsys: pytest.CaptureFixture[str]) -> None: ) -# FIXME: auto_structify config option doesn't work. -@pytest.mark.skip("`auto_structify` doesn't work") -@pl.Config(auto_structify=False) -def test_df_show_auto_structify(capsys: pytest.CaptureFixture[str]) -> None: - df = pl.DataFrame({"v": [1, 2, 3], "v2": [4, 5, 6]}) - - df.show(auto_structify=True) - out, _ = capsys.readouterr() - assert ( - out - == """shape: (3, 1) -┌───────────┐ -│ v │ -│ --- │ -│ struct[2] │ -╞═══════════╡ -│ {1,4} │ -│ {2,5} │ -│ {3,6} │ -└───────────┘ -""" - ) - - @pl.Config(decimal_separator=",") def test_df_show_decimal_separator(capsys: pytest.CaptureFixture[str]) -> None: df = pl.DataFrame({"v": [9876.54321, 1010101.0, -123456.78]}) diff --git a/py-polars/tests/unit/lazyframe/test_show.py b/py-polars/tests/unit/lazyframe/test_show.py index 1f81e020eacb..41ea0156138e 100644 --- a/py-polars/tests/unit/lazyframe/test_show.py +++ b/py-polars/tests/unit/lazyframe/test_show.py @@ -19,7 +19,6 @@ def test_lf_show_calls_df_show() -> None: df_show.assert_called_once_with( 5, ascii_tables=None, - auto_structify=None, decimal_separator=None, thousands_separator=None, float_precision=None, From fe028ebb8a03552d480e47896ba4a41ff9bcc255 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 10:57:46 +0100 Subject: [PATCH 14/20] fix lint --- py-polars/polars/dataframe/frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index b9fb85e14048..e3483da87d6a 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -31,7 +31,6 @@ from polars import functions as F from polars._typing import ( DbWriteMode, - FloatFmt, JaxExportType, TorchExportType, ) @@ -150,6 +149,7 @@ CsvQuoteStyle, DbWriteEngine, FillNullStrategy, + FloatFmt, FrameInitTypes, IndexOrder, IntoExpr, From c9653a5bdf6d0fa657d68b574af6a496f2c1d983 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 11:07:42 +0100 Subject: [PATCH 15/20] test incompatible settings ascii_tables & tbl_formatting --- py-polars/tests/unit/dataframe/test_show.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/py-polars/tests/unit/dataframe/test_show.py b/py-polars/tests/unit/dataframe/test_show.py index df2734b32cf7..7e5e5d593da0 100644 --- a/py-polars/tests/unit/dataframe/test_show.py +++ b/py-polars/tests/unit/dataframe/test_show.py @@ -1,6 +1,7 @@ import pytest import polars as pl +from polars.config import TableFormatNames def test_df_show_default(capsys: pytest.CaptureFixture[str]) -> None: @@ -134,6 +135,24 @@ def test_df_show_ascii_tables(capsys: pytest.CaptureFixture[str]) -> None: ) +@pytest.mark.parametrize( + ("ascii_tables", "tbl_formatting"), + [ + (True, "ASCII_FULL_CONDENSED"), + (True, "UTF8_FULL_CONDENSED"), + (False, "ASCII_FULL_CONDENSED"), + (False, "UTF8_FULL_CONDENSED"), + ], +) +def test_df_show_cannot_set_ascii_tables_and_tbl_formatting( + ascii_tables: bool, tbl_formatting: TableFormatNames +) -> None: + df = pl.DataFrame() + + with pytest.raises(ValueError): + df.show(ascii_tables=ascii_tables, tbl_formatting=tbl_formatting) + + @pl.Config(decimal_separator=",") def test_df_show_decimal_separator(capsys: pytest.CaptureFixture[str]) -> None: df = pl.DataFrame({"v": [9876.54321, 1010101.0, -123456.78]}) From 316ecc015b6a572f18764c23691afd5fab7f3a77 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 11:53:37 +0100 Subject: [PATCH 16/20] update docstrings with refs to config options --- py-polars/polars/dataframe/frame.py | 44 ++++++++++++++++++++--------- py-polars/polars/lazyframe/frame.py | 44 ++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 28 deletions(-) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index e3483da87d6a..be6ec88e421b 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -11301,16 +11301,20 @@ def show( except the last `abs(n)`. If None is passed, return all rows. ascii_tables : bool Use ASCII characters to display table outlines. Set False to revert to the - default UTF8_FULL_CONDENSED formatting style. + default UTF8_FULL_CONDENSED formatting style. See + :func:`Config.set_ascii_tables` for more information. decimal_separator : str - Set the decimal separator character. + Set the decimal separator character. See + :func:`Config.set_decimal_separator` for more information. thousands_separator : str - Set the thousands grouping separator character. + Set the thousands grouping separator character. See + :func:`Config.set_thousands_separator` for more information. float_precision : int Number of decimal places to display for floating point values. See :func:`Config.set_float_precision` for more information. fmt_float : {"mixed", "full"} - Control how floating point values are displayed. Supported options are: + Control how floating point values are displayed. See + :func:`Config.set_fmt_float` for more informations. Supported options are: * "mixed": Limit the number of decimal places and use scientific notation for large/small values. * "full": Print the full precision of the floating point number. @@ -11321,12 +11325,15 @@ def show( Number of elements to display for List values. See :func:`Config.set_fmt_table_cell_list_len` for more information. tbl_cell_alignment : str - Set table cell alignment. Supported options are: + Set table cell alignment. See :func:`Config.set_tbl_cell_alignment` for more + information. Supported options are: * "LEFT": left aligned * "CENTER": center aligned * "RIGHT": right aligned tbl_cell_numeric_alignment : str - Set table cell alignment for numeric columns. Supported options are: + Set table cell alignment for numeric columns. See + :func:`Config.set_tbl_cell_numeric_alignment` for more information. + Supported options are: * "LEFT": left aligned * "CENTER": center aligned * "RIGHT": right aligned @@ -11335,11 +11342,14 @@ def show( information. tbl_column_data_type_inline : bool Moves the data type inline with the column name (to the right, in - parentheses). + parentheses). See :func:`Config.set_tbl_column_data_type_inline` for more + information. tbl_dataframe_shape_below : bool Print the DataFrame shape information below the data when displaying tables. + See :func:`Config.set_tbl_dataframe_shape_below` for more information. tbl_formatting : str - Set table formatting style. Supported options are: + Set table formatting style. See :func:`Config.set_tbl_formatting` for more + information. Supported options are: * "ASCII_FULL": ASCII, with all borders and lines, including row dividers. * "ASCII_FULL_CONDENSED": Same as ASCII_FULL, but with dense row spacing. * "ASCII_NO_BORDERS": ASCII, no borders. @@ -11355,17 +11365,23 @@ def show( * "UTF8_HORIZONTAL_ONLY": UTF8, horizontal lines only. * "NOTHING": No borders or other lines. tbl_hide_column_data_types : bool - Hide table column data types (i64, f64, str etc.). + Hide table column data types (i64, f64, str etc.). See + :func:`Config.set_tbl_hide_column_data_types` for more information. tbl_hide_column_names : bool - Hide table column names. + Hide table column names. See :func:`Config.set_tbl_hide_column_names` for + more information. tbl_hide_dtype_separator : bool - Hide the '---' separator between the column names and column types. + Hide the '---' separator between the column names and column types. See + :func:`Config.set_tbl_hide_dtype_separator` for more information. tbl_hide_dataframe_shape : bool - Hide the DataFrame shape information when displaying tables. + Hide the DataFrame shape information when displaying tables. See + :func:`Config.set_tbl_hide_dataframe_shape` for more information. tbl_width_chars : int - Set the maximum width of a table in characters. + Set the maximum width of a table in characters. See + :func:`Config.set_tbl_width_chars` for more information. trim_decimal_zeros : bool - Strip trailing zeros from Decimal data type values. + Strip trailing zeros from Decimal data type values. See + :func:`Config.set_trim_decimal_zeros` for more information. See Also -------- diff --git a/py-polars/polars/lazyframe/frame.py b/py-polars/polars/lazyframe/frame.py index c3e840ac4fba..8894d31acfae 100644 --- a/py-polars/polars/lazyframe/frame.py +++ b/py-polars/polars/lazyframe/frame.py @@ -6942,16 +6942,20 @@ def show( Number of rows to show. If None is passed, return all rows. ascii_tables : bool Use ASCII characters to display table outlines. Set False to revert to the - default UTF8_FULL_CONDENSED formatting style. + default UTF8_FULL_CONDENSED formatting style. See + :func:`Config.set_ascii_tables` for more information. decimal_separator : str - Set the decimal separator character. + Set the decimal separator character. See + :func:`Config.set_decimal_separator` for more information. thousands_separator : str - Set the thousands grouping separator character. + Set the thousands grouping separator character. See + :func:`Config.set_thousands_separator` for more information. float_precision : int Number of decimal places to display for floating point values. See :func:`Config.set_float_precision` for more information. fmt_float : {"mixed", "full"} - Control how floating point values are displayed. Supported options are: + Control how floating point values are displayed. See + :func:`Config.set_fmt_float` for more informations. Supported options are: * "mixed": Limit the number of decimal places and use scientific notation for large/small values. * "full": Print the full precision of the floating point number. @@ -6962,12 +6966,15 @@ def show( Number of elements to display for List values. See :func:`Config.set_fmt_table_cell_list_len` for more information. tbl_cell_alignment : str - Set table cell alignment. Supported options are: + Set table cell alignment. See :func:`Config.set_tbl_cell_alignment` for more + information. Supported options are: * "LEFT": left aligned * "CENTER": center aligned * "RIGHT": right aligned tbl_cell_numeric_alignment : str - Set table cell alignment for numeric columns. Supported options are: + Set table cell alignment for numeric columns. See + :func:`Config.set_tbl_cell_numeric_alignment` for more information. + Supported options are: * "LEFT": left aligned * "CENTER": center aligned * "RIGHT": right aligned @@ -6976,11 +6983,14 @@ def show( information. tbl_column_data_type_inline : bool Moves the data type inline with the column name (to the right, in - parentheses). + parentheses). See :func:`Config.set_tbl_column_data_type_inline` for more + information. tbl_dataframe_shape_below : bool Print the DataFrame shape information below the data when displaying tables. + See :func:`Config.set_tbl_dataframe_shape_below` for more information. tbl_formatting : str - Set table formatting style. Supported options are: + Set table formatting style. See :func:`Config.set_tbl_formatting` for more + information. Supported options are: * "ASCII_FULL": ASCII, with all borders and lines, including row dividers. * "ASCII_FULL_CONDENSED": Same as ASCII_FULL, but with dense row spacing. * "ASCII_NO_BORDERS": ASCII, no borders. @@ -6996,17 +7006,23 @@ def show( * "UTF8_HORIZONTAL_ONLY": UTF8, horizontal lines only. * "NOTHING": No borders or other lines. tbl_hide_column_data_types : bool - Hide table column data types (i64, f64, str etc.). + Hide table column data types (i64, f64, str etc.). See + :func:`Config.set_tbl_hide_column_data_types` for more information. tbl_hide_column_names : bool - Hide table column names. + Hide table column names. See :func:`Config.set_tbl_hide_column_names` for + more information. tbl_hide_dtype_separator : bool - Hide the '---' separator between the column names and column types. + Hide the '---' separator between the column names and column types. See + :func:`Config.set_tbl_hide_dtype_separator` for more information. tbl_hide_dataframe_shape : bool - Hide the DataFrame shape information when displaying tables. + Hide the DataFrame shape information when displaying tables. See + :func:`Config.set_tbl_hide_dataframe_shape` for more information. tbl_width_chars : int - Set the maximum width of a table in characters. + Set the maximum width of a table in characters. See + :func:`Config.set_tbl_width_chars` for more information. trim_decimal_zeros : bool - Strip trailing zeros from Decimal data type values. + Strip trailing zeros from Decimal data type values. See + :func:`Config.set_trim_decimal_zeros` for more information. Warnings -------- From 3ad2d023d4f29764fa7dc338062c53fb00b2e984 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 11:55:30 +0100 Subject: [PATCH 17/20] fix typo --- py-polars/polars/dataframe/frame.py | 2 +- py-polars/polars/lazyframe/frame.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index be6ec88e421b..b437efb6c097 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -11314,7 +11314,7 @@ def show( :func:`Config.set_float_precision` for more information. fmt_float : {"mixed", "full"} Control how floating point values are displayed. See - :func:`Config.set_fmt_float` for more informations. Supported options are: + :func:`Config.set_fmt_float` for more information. Supported options are: * "mixed": Limit the number of decimal places and use scientific notation for large/small values. * "full": Print the full precision of the floating point number. diff --git a/py-polars/polars/lazyframe/frame.py b/py-polars/polars/lazyframe/frame.py index 8894d31acfae..13c24490e33b 100644 --- a/py-polars/polars/lazyframe/frame.py +++ b/py-polars/polars/lazyframe/frame.py @@ -6955,7 +6955,7 @@ def show( :func:`Config.set_float_precision` for more information. fmt_float : {"mixed", "full"} Control how floating point values are displayed. See - :func:`Config.set_fmt_float` for more informations. Supported options are: + :func:`Config.set_fmt_float` for more information. Supported options are: * "mixed": Limit the number of decimal places and use scientific notation for large/small values. * "full": Print the full precision of the floating point number. From d59feb2e60efaf7897c7701f861eb0aeccf8df5d Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 18:11:47 +0100 Subject: [PATCH 18/20] fix docstring indentation issue --- py-polars/polars/dataframe/frame.py | 2 +- py-polars/polars/lazyframe/frame.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index b437efb6c097..d4503159e8a1 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -11316,7 +11316,7 @@ def show( Control how floating point values are displayed. See :func:`Config.set_fmt_float` for more information. Supported options are: * "mixed": Limit the number of decimal places and use scientific notation - for large/small values. + for large/small values. * "full": Print the full precision of the floating point number. fmt_str_lengths : int Number of characters to display for string values. See diff --git a/py-polars/polars/lazyframe/frame.py b/py-polars/polars/lazyframe/frame.py index 13c24490e33b..08123f07c0fc 100644 --- a/py-polars/polars/lazyframe/frame.py +++ b/py-polars/polars/lazyframe/frame.py @@ -6957,7 +6957,7 @@ def show( Control how floating point values are displayed. See :func:`Config.set_fmt_float` for more information. Supported options are: * "mixed": Limit the number of decimal places and use scientific notation - for large/small values. + for large/small values. * "full": Print the full precision of the floating point number. fmt_str_lengths : int Number of characters to display for string values. See From 11b1ac898bd0e6440a87c109435ec3aff0819bac Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 18:24:01 +0100 Subject: [PATCH 19/20] feat: add doc entries for show methods --- py-polars/docs/source/reference/dataframe/descriptive.rst | 1 + py-polars/docs/source/reference/lazyframe/descriptive.rst | 1 + 2 files changed, 2 insertions(+) diff --git a/py-polars/docs/source/reference/dataframe/descriptive.rst b/py-polars/docs/source/reference/dataframe/descriptive.rst index 00fba0d0cad1..ad166c830253 100644 --- a/py-polars/docs/source/reference/dataframe/descriptive.rst +++ b/py-polars/docs/source/reference/dataframe/descriptive.rst @@ -16,3 +16,4 @@ Descriptive DataFrame.n_chunks DataFrame.n_unique DataFrame.null_count + DataFrame.show diff --git a/py-polars/docs/source/reference/lazyframe/descriptive.rst b/py-polars/docs/source/reference/lazyframe/descriptive.rst index 0f05afae8960..0d499ea37e3f 100644 --- a/py-polars/docs/source/reference/lazyframe/descriptive.rst +++ b/py-polars/docs/source/reference/lazyframe/descriptive.rst @@ -9,3 +9,4 @@ Descriptive LazyFrame.describe LazyFrame.explain LazyFrame.show_graph + LazyFrame.show From 04817aac16af3352d139322a86e5c50ba51b74c2 Mon Sep 17 00:00:00 2001 From: Guilhem de Viry Date: Thu, 7 Nov 2024 18:39:36 +0100 Subject: [PATCH 20/20] fix bullet lists --- py-polars/polars/dataframe/frame.py | 10 +++++++++- py-polars/polars/lazyframe/frame.py | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index d4503159e8a1..b073e7b61a35 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -11315,9 +11315,11 @@ def show( fmt_float : {"mixed", "full"} Control how floating point values are displayed. See :func:`Config.set_fmt_float` for more information. Supported options are: + * "mixed": Limit the number of decimal places and use scientific notation - for large/small values. + for large/small values. * "full": Print the full precision of the floating point number. + fmt_str_lengths : int Number of characters to display for string values. See :func:`Config.set_fmt_str_lengths` for more information. @@ -11327,16 +11329,20 @@ def show( tbl_cell_alignment : str Set table cell alignment. See :func:`Config.set_tbl_cell_alignment` for more information. Supported options are: + * "LEFT": left aligned * "CENTER": center aligned * "RIGHT": right aligned + tbl_cell_numeric_alignment : str Set table cell alignment for numeric columns. See :func:`Config.set_tbl_cell_numeric_alignment` for more information. Supported options are: + * "LEFT": left aligned * "CENTER": center aligned * "RIGHT": right aligned + tbl_cols : int Number of columns to display. See :func:`Config.set_tbl_cols` for more information. @@ -11350,6 +11356,7 @@ def show( tbl_formatting : str Set table formatting style. See :func:`Config.set_tbl_formatting` for more information. Supported options are: + * "ASCII_FULL": ASCII, with all borders and lines, including row dividers. * "ASCII_FULL_CONDENSED": Same as ASCII_FULL, but with dense row spacing. * "ASCII_NO_BORDERS": ASCII, no borders. @@ -11364,6 +11371,7 @@ def show( * "UTF8_BORDERS_ONLY": UTF8, borders only. * "UTF8_HORIZONTAL_ONLY": UTF8, horizontal lines only. * "NOTHING": No borders or other lines. + tbl_hide_column_data_types : bool Hide table column data types (i64, f64, str etc.). See :func:`Config.set_tbl_hide_column_data_types` for more information. diff --git a/py-polars/polars/lazyframe/frame.py b/py-polars/polars/lazyframe/frame.py index 08123f07c0fc..9448d4bffad1 100644 --- a/py-polars/polars/lazyframe/frame.py +++ b/py-polars/polars/lazyframe/frame.py @@ -6956,9 +6956,11 @@ def show( fmt_float : {"mixed", "full"} Control how floating point values are displayed. See :func:`Config.set_fmt_float` for more information. Supported options are: + * "mixed": Limit the number of decimal places and use scientific notation - for large/small values. + for large/small values. * "full": Print the full precision of the floating point number. + fmt_str_lengths : int Number of characters to display for string values. See :func:`Config.set_fmt_str_lengths` for more information. @@ -6968,16 +6970,20 @@ def show( tbl_cell_alignment : str Set table cell alignment. See :func:`Config.set_tbl_cell_alignment` for more information. Supported options are: + * "LEFT": left aligned * "CENTER": center aligned * "RIGHT": right aligned + tbl_cell_numeric_alignment : str Set table cell alignment for numeric columns. See :func:`Config.set_tbl_cell_numeric_alignment` for more information. Supported options are: + * "LEFT": left aligned * "CENTER": center aligned * "RIGHT": right aligned + tbl_cols : int Number of columns to display. See :func:`Config.set_tbl_cols` for more information. @@ -6991,6 +6997,7 @@ def show( tbl_formatting : str Set table formatting style. See :func:`Config.set_tbl_formatting` for more information. Supported options are: + * "ASCII_FULL": ASCII, with all borders and lines, including row dividers. * "ASCII_FULL_CONDENSED": Same as ASCII_FULL, but with dense row spacing. * "ASCII_NO_BORDERS": ASCII, no borders. @@ -7005,6 +7012,7 @@ def show( * "UTF8_BORDERS_ONLY": UTF8, borders only. * "UTF8_HORIZONTAL_ONLY": UTF8, horizontal lines only. * "NOTHING": No borders or other lines. + tbl_hide_column_data_types : bool Hide table column data types (i64, f64, str etc.). See :func:`Config.set_tbl_hide_column_data_types` for more information.