table tests, optimizations

This commit is contained in:
Will McGugan 2020-06-06 15:34:59 +01:00
parent 7e029e343b
commit 17011e3338
6 changed files with 82 additions and 37 deletions

View File

@ -12,15 +12,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added overflow methods
- Added no_wrap option to print()
- Added width option to print
- Improved handling of compressed tables
### Fixed
- Improved handling of compressed tables
- Fixed erroneous space at end of log
### Changed
- Renamed \_ratio.ratio_divide to \_ratio.ratio_distribute
- Renamed JustifyValues to JustifyMethod
- Optimized \_trim_spans
## [1.3.1] - 2020-06-01

17
rich/_pick.py Normal file
View File

@ -0,0 +1,17 @@
from typing import Optional
def pick_bool(*values: Optional[bool]) -> bool:
"""Pick the first non-none bool or return the last value.
Args:
*values (bool): Any number of boolean or None values.
Returns:
bool: First non-none boolean.
"""
assert values, "1 or more values required"
for value in values:
if value is not None:
return value
return bool(value)

View File

@ -93,7 +93,7 @@ class ConsoleOptions:
encoding: str
justify: Optional[JustifyMethod] = None
overflow: Optional[OverflowMethod] = None
no_wrap: bool = False
no_wrap: Optional[bool] = False
def update(
self,

View File

@ -23,6 +23,7 @@ from .containers import Lines
from .control import strip_control_codes
from .jupyter import JupyterMixin
from .measure import Measurement
from ._pick import pick_bool
from .segment import Segment
from .style import Style, StyleType
@ -114,7 +115,7 @@ class Text(JupyterMixin):
style: Union[str, Style] = "",
justify: "JustifyMethod" = None,
overflow: "OverflowMethod" = None,
no_wrap: bool = False,
no_wrap: bool = None,
end: str = "\n",
tab_size: Optional[int] = 8,
spans: List[Span] = None,
@ -423,25 +424,13 @@ class Text(JupyterMixin):
"OverflowMethod", self.overflow or options.overflow or DEFAULT_OVERFLOW
)
if self.no_wrap or options.no_wrap:
render_text = self
if overflow in ("crop", "ellipsis"):
render_text = self.copy()
render_text.truncate(options.max_width, overflow)
if justify:
lines = Lines([render_text])
lines.justify(
console, options.max_width, justify=justify, overflow=overflow
)
render_text = lines[0]
yield from render_text.render(console, end=self.end)
else:
lines = self.wrap(
console,
options.max_width,
justify=justify,
overflow=overflow,
tab_size=tab_size or 8,
no_wrap=pick_bool(options.no_wrap, self.no_wrap, False),
)
all_lines = Text("\n").join(lines)
yield from all_lines.render(console, end=self.end)
@ -574,7 +563,7 @@ class Text(JupyterMixin):
Args:
max_width (int): Maximum number of characters in text.
overflow (str, optional): Overflow method: "crop", "fold", or "ellipisis". Defaults to None, to use self.overflow.
overflow (str, optional): Overflow method: "crop", "fold", or "ellipsis". Defaults to None, to use self.overflow.
pad (bool, optional): Pad with spaces if the length is less than max_width. Defaults to False.
"""
length = cell_len(self.plain)
@ -584,7 +573,6 @@ class Text(JupyterMixin):
self.plain = set_cell_size(self.plain, max_width - 1).rstrip() + ""
else:
self.plain = set_cell_size(self.plain, max_width)
length = cell_len(self.plain)
if pad and length < max_width:
spaces = max_width - length
self.plain = f"{self.plain}{' ' * spaces}"
@ -785,6 +773,7 @@ class Text(JupyterMixin):
justify: "JustifyMethod" = None,
overflow: "OverflowMethod" = None,
tab_size: int = 8,
no_wrap: bool = None,
) -> Lines:
"""Word wrap the text.
@ -792,9 +781,10 @@ class Text(JupyterMixin):
console (Console): Console instance.
width (int): Number of characters per line.
emoji (bool, optional): Also render emoji code. Defaults to True.
justify (str, optional): Justify method: "left", "center", "full", "right". Defaults to "left".
overflow (str, optional): Overflow method: "crop", "fold", or "ellipisis". Defaults to None.
justify (str, optional): Justify method: "default", "left", "center", "full", "right". Defaults to "default".
overflow (str, optional): Overflow method: "crop", "fold", or "ellipsis". Defaults to None.
tab_size (int, optional): Default tab size. Defaults to 8.
no_wrap (bool, optional): Disable wrapping, Defaults to False.
Returns:
Lines: Number of lines.
@ -803,10 +793,14 @@ class Text(JupyterMixin):
wrap_overflow = cast(
"OverflowMethod", overflow or self.overflow or DEFAULT_OVERFLOW
)
no_wrap = pick_bool(no_wrap, self.no_wrap, False)
lines: Lines = Lines()
for line in self.split():
if "\t" in line:
line = line.tabs_to_spaces(tab_size)
if no_wrap:
new_lines = Lines([line])
else:
offsets = divide_line(str(line), width, fold=wrap_overflow == "fold")
new_lines = line.divide(offsets)
for line in new_lines:
@ -815,10 +809,9 @@ class Text(JupyterMixin):
new_lines.justify(
console, width, justify=wrap_justify, overflow=wrap_overflow
)
lines.extend(new_lines)
for line in lines:
for line in new_lines:
line.truncate(width, wrap_overflow)
lines.extend(new_lines)
return lines

View File

@ -248,6 +248,5 @@ def test_save_html():
def test_no_wrap():
console = Console(width=10, file=io.StringIO())
console.print("X" * 15)
console.print("Y" * 15, no_wrap=True)
assert console.file.getvalue() == "XXXXXXXXXX\nXXXXX\nYYYYYYYYYY\n"
console.print("foo bar baz egg", no_wrap=True)
assert console.file.getvalue() == "foo bar ba\n"

34
tests/test_table.py Normal file
View File

@ -0,0 +1,34 @@
# encoding=utf-8
import io
from rich.console import Console
from rich.table import Table
def render_tables():
console = Console(width=60, file=io.StringIO())
table = Table(title="test table", caption="table footer", expand=True)
table.add_column("foo", no_wrap=True, overflow="ellipsis")
table.add_column("bar", justify="center")
table.add_column("baz", justify="right")
table.add_row("Averlongwordgoeshere", "banana pancakes", None)
for width in range(10, 60, 5):
console.print(table, width=width)
return console.file.getvalue()
def test_render_table():
expected = "test table\n┏━━┳━━┳━━┓\n┃ ┃ ┃ ┃\n┡━━╇━━╇━━┩\n│ │ │ │\n└──┴──┴──┘\n table \n footer \n test table \n┏━━━━━┳━━━━┳━━┓\n┃ foo ┃ b… ┃ ┃\n┡━━━━━╇━━━━╇━━┩\n│ Av… │ b… │ │\n└─────┴────┴──┘\n table footer \n test table \n┏━━━━━━━━┳━━━━━┳━━━┓\n┃ foo ┃ bar ┃ … ┃\n┡━━━━━━━━╇━━━━━╇━━━┩\n│ Averl… │ ba… │ │\n└────────┴─────┴───┘\n table footer \n test table \n┏━━━━━━━━━━━━┳━━━━━━┳━━━┓\n┃ foo ┃ bar ┃ … ┃\n┡━━━━━━━━━━━━╇━━━━━━╇━━━┩\n│ Averlongw… │ ban… │ │\n└────────────┴──────┴───┘\n table footer \n test table \n┏━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━┓\n┃ foo ┃ bar ┃ b… ┃\n┡━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━┩\n│ Averlongword… │ bana… │ │\n└───────────────┴───────┴────┘\n table footer \n test table \n┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━┓\n┃ foo ┃ bar ┃ b… ┃\n┡━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━┩\n│ Averlongwordgoe… │ banana… │ │\n└──────────────────┴─────────┴────┘\n table footer \n test table \n┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━┓\n┃ foo ┃ bar ┃ baz ┃\n┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━┩\n│ Averlongwordgoeshe… │ banana │ │\n│ │ pancakes │ │\n└─────────────────────┴──────────┴─────┘\n table footer \n test table \n┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━┓\n┃ foo ┃ bar ┃ baz ┃\n┡━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━┩\n│ Averlongwordgoeshere │ banana │ │\n│ │ pancakes │ │\n└──────────────────────┴──────────────┴─────┘\n table footer \n test table \n┏━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━┓\n┃ foo ┃ bar ┃ baz ┃\n┡━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━┩\n│ Averlongwordgoeshere │ banana pancakes │ │\n└───────────────────────┴─────────────────┴──────┘\n table footer \n test table \n┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━┓\n┃ foo ┃ bar ┃ baz ┃\n┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━┩\n│ Averlongwordgoeshere │ banana pancakes │ │\n└─────────────────────────┴────────────────────┴──────┘\n table footer \n"
assert render_tables() == expected
if __name__ == "__main__":
render = render_tables()
print(render)
print(repr(render))