Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix max table width calculation #289

Merged
merged 10 commits into from
Mar 28, 2024
26 changes: 15 additions & 11 deletions src/prettytable/prettytable.py
Original file line number Diff line number Diff line change
Expand Up @@ -1558,13 +1558,18 @@ def _format_value(self, field, value):
return formatter(field, value)

def _compute_table_width(self, options):
table_width = 2 if options["vrules"] in (FRAME, ALL) else 0
if options["vrules"] == FRAME:
table_width = 2
if options["vrules"] == ALL:
table_width = 1
else:
table_width = 0
per_col_padding = sum(self._get_padding_widths(options))
for index, fieldname in enumerate(self.field_names):
if not options["fields"] or (
options["fields"] and fieldname in options["fields"]
):
table_width += self._widths[index] + per_col_padding
table_width += self._widths[index] + per_col_padding + 1
return table_width

def _compute_widths(self, rows, options) -> None:
Expand All @@ -1590,21 +1595,22 @@ def _compute_widths(self, rows, options) -> None:
widths[index] = max(widths[index], self.min_width[fieldname])
self._widths = widths

per_col_padding = sum(self._get_padding_widths(options))
# Are we exceeding max_table_width?
if self._max_table_width:
table_width = self._compute_table_width(options)
if table_width > self._max_table_width:
# Shrink widths in proportion
scale = 1.0 * self._max_table_width / table_width
widths = [int(w * scale) for w in widths]
self._widths = widths
markup_chars = per_col_padding * len(widths) + len(widths) - 1
scale = (self._max_table_width - markup_chars) / (
table_width - markup_chars
)
self._widths = [max(1, int(w * scale)) for w in widths]

# Are we under min_table_width or title width?
if self._min_table_width or options["title"]:
if options["title"]:
title_width = len(options["title"]) + sum(
self._get_padding_widths(options)
)
title_width = len(options["title"]) + per_col_padding
if options["vrules"] in (FRAME, ALL):
title_width += 2
else:
Expand All @@ -1619,9 +1625,7 @@ def _compute_widths(self, rows, options) -> None:
borders = 0

# Subtract padding for each column and borders
min_width -= (
sum([sum(self._get_padding_widths(options)) for _ in widths]) + borders
)
min_width -= sum([per_col_padding for _ in widths]) + borders
# What is being scaled is content so we sum column widths
content_width = sum(widths) or 1

Expand Down
134 changes: 129 additions & 5 deletions tests/test_prettytable.py
Original file line number Diff line number Diff line change
Expand Up @@ -2008,17 +2008,141 @@ def test_max_table_width(self) -> None:
table.max_table_width = 5
table.add_row([0])

# FIXME: Table is wider than table.max_table_width
assert (
table.get_string().strip()
== """
+-----+
| Fie |
+-----+
| 0 |
+-----+
+----+
| Fi |
+----+
| 0 |
+----+
""".strip()
)

def test_max_table_width_wide(self) -> None:
table = PrettyTable()
table.max_table_width = 52
table.add_row(
[
0,
0,
0,
0,
0,
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam "
"nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam "
"erat, sed diam voluptua",
]
)

assert (
table.get_string().strip()
== """
+---+---+---+---+---+------------------------------+
| F | F | F | F | F | Field 6 |
+---+---+---+---+---+------------------------------+
| 0 | 0 | 0 | 0 | 0 | Lorem ipsum dolor sit amet, |
| | | | | | consetetur sadipscing elitr, |
| | | | | | sed diam nonumy eirmod |
| | | | | | tempor invidunt ut labore et |
| | | | | | dolore magna aliquyam erat, |
| | | | | | sed diam voluptua |
+---+---+---+---+---+------------------------------+""".strip()
)

def test_max_table_width_wide2(self) -> None:
table = PrettyTable()
table.max_table_width = 70
table.add_row(
[
"Lorem",
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam ",
"ipsum",
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam ",
"dolor",
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam ",
]
)

assert (
table.get_string().strip()
== """
+---+-----------------+---+-----------------+---+-----------------+
| F | Field 2 | F | Field 4 | F | Field 6 |
+---+-----------------+---+-----------------+---+-----------------+
| L | Lorem ipsum | i | Lorem ipsum | d | Lorem ipsum |
| o | dolor sit amet, | p | dolor sit amet, | o | dolor sit amet, |
| r | consetetur | s | consetetur | l | consetetur |
| e | sadipscing | u | sadipscing | o | sadipscing |
| m | elitr, sed diam | m | elitr, sed diam | r | elitr, sed diam |
+---+-----------------+---+-----------------+---+-----------------+""".strip()
)

def test_max_table_width_wide_vrules_frame(self) -> None:
table = PrettyTable()
table.max_table_width = 52
table.vrules = FRAME
table.add_row(
[
0,
0,
0,
0,
0,
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam "
"nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam "
"erat, sed diam voluptua",
]
)

assert (
table.get_string().strip()
== """
+--------------------------------------------------+
| F F F F F Field 6 |
+--------------------------------------------------+
| 0 0 0 0 0 Lorem ipsum dolor sit amet, |
| consetetur sadipscing elitr, |
| sed diam nonumy eirmod |
| tempor invidunt ut labore et |
| dolore magna aliquyam erat, |
| sed diam voluptua |
+--------------------------------------------------+""".strip()
)

def test_max_table_width_wide_vrules_none(self) -> None:
table = PrettyTable()
table.max_table_width = 52
table.vrules = NONE
table.add_row(
[
0,
0,
0,
0,
0,
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam "
"nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam "
"erat, sed diam voluptua",
]
)

assert (
table.get_string().strip()
== """
----------------------------------------------------
F F F F F Field 6
----------------------------------------------------
0 0 0 0 0 Lorem ipsum dolor sit amet,
consetetur sadipscing elitr,
sed diam nonumy eirmod
tempor invidunt ut labore et
dolore magna aliquyam erat,
sed diam voluptua
----------------------------------------------------""".strip() # noqa: W291
)


class TestRowEndSection:
def test_row_end_section(self) -> None:
Expand Down
Loading