background style, table width calculation

This commit is contained in:
Will McGugan 2020-10-15 21:17:03 +01:00
parent c98bf070e4
commit 05ce5105b4
14 changed files with 68 additions and 49 deletions

View file

@ -16,15 +16,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support for Python 3.9
- Added legacy_windows to ConsoleOptions
- Added ascii_only to ConsoleOptions
- Addded box.SQUARE_DOUBLE_HEAD
- Added box.SQUARE_DOUBLE_HEAD
- Added highlighting of EUI-48 and EUI-64 (MAC addresses)
- Added Console.pager
- Added Console.out
- Added Progress.reset
- Added Style.background_style property
### Changed
- Dropped box.get_safe_box function in favor of Box.substitute
- Changed default padding in Panel from 0 to (0, 1) https://github.com/willmcgugan/rich/issues/385
- Table with row_styles will extend background color between cells if the box has no vertical dividerhttps://github.com/willmcgugan/rich/issues/383
### Fixed

View file

@ -79,7 +79,7 @@ class Box:
box = self
if options.legacy_windows and safe:
box = LEGACY_WINDOWS_SUBSTITUTIONS.get(box, box)
if options.ascii_only:
if options.ascii_only and not box.ascii:
box = ASCII
return box

View file

@ -45,7 +45,7 @@ class Panel(JupyterMixin):
style: StyleType = "none",
border_style: StyleType = "none",
width: Optional[int] = None,
padding: PaddingDimensions = 0,
padding: PaddingDimensions = (0, 1),
) -> None:
self.renderable = renderable
self.box = box
@ -70,7 +70,7 @@ class Panel(JupyterMixin):
style: StyleType = "none",
border_style: StyleType = "none",
width: Optional[int] = None,
padding: PaddingDimensions = 0,
padding: PaddingDimensions = (0, 1),
):
"""An alternative constructor that sets expand=False."""
return cls(

View file

@ -349,6 +349,11 @@ class Style:
"""Check if the style specified a transparent background."""
return self.bgcolor is None or self.bgcolor.is_default
@property
def background_style(self) -> "Style":
"""A Style with background only."""
return Style(bgcolor=self.bgcolor)
@classmethod
@lru_cache(maxsize=1024)
def parse(cls, style_definition: str) -> "Style":

View file

@ -300,7 +300,7 @@ class Table(JupyterMixin):
footer_style (Union[str, Style], optional): Style for the header. Defaults to "none".
style (Union[str, Style], optional): Style for the column cells. Defaults to "none".
justify (JustifyMethod, optional): Alignment for cells. Defaults to "left".
width (int, optional): A minimum width in characters. Defaults to None.
width (int, optional): Desired width of column in characters, or None to fit to contents. Defaults to None.
ratio (int, optional): Flexible ratio for the column (requires ``Table.expand`` or ``Table.width``). Defaults to None.
no_wrap (bool, optional): Set to ``True`` to disable wrapping of this column.
"""
@ -376,12 +376,10 @@ class Table(JupyterMixin):
max_width = options.max_width
if self.width is not None:
max_width = self.width
if self.box:
max_width -= len(self.columns) - 1
if self.show_edge:
max_width -= 2
widths = self._calculate_column_widths(console, max_width)
table_width = sum(widths) + self._extra_width
extra_width = self._extra_width
widths = self._calculate_column_widths(console, max_width - extra_width)
table_width = sum(widths) + extra_width
render_options = options.update(width=table_width)
@ -437,10 +435,11 @@ class Table(JupyterMixin):
if column.flexible:
widths[index] = fixed_widths[index] + next(iter_flex_widths)
table_width = sum(widths)
if table_width > max_width:
widths = self._collapse_widths(
widths, [not column.no_wrap for column in columns], max_width
widths,
[(column.width is None and not column.no_wrap) for column in columns],
max_width,
)
table_width = sum(widths)
@ -570,7 +569,7 @@ class Table(JupyterMixin):
# Fixed width column
return Measurement(
column.width + padding_width, column.width + padding_width
)
).with_maximum(max_width)
# Flexible column, we need to measure contents
min_widths: List[int] = []
max_widths: List[int] = []
@ -582,10 +581,11 @@ class Table(JupyterMixin):
append_min(_min)
append_max(_max)
return Measurement(
measurement = Measurement(
max(min_widths) if min_widths else 1,
max(max_widths) if max_widths else max_width,
)
).with_maximum(max_width)
return measurement
def _render(
self, console: "Console", options: "ConsoleOptions", widths: List[int]
@ -683,13 +683,16 @@ class Table(JupyterMixin):
_box.get_row(widths, "foot", edge=show_edge), border_style
)
yield new_line
if first:
left, right, divider = box_segments[0]
elif last:
left, right, divider = box_segments[2]
else:
left, right, divider = box_segments[1]
left, right, _divider = box_segments[0 if first else (2 if last else 1)]
# If the column divider is whitespace also style it with the row background
divider = (
_divider
if _divider.text.strip()
else _Segment(
_divider.text, row_style.background_style + _divider.style
)
)
for line_no in range(max_height):
if show_edge:
yield left
@ -706,7 +709,7 @@ class Table(JupyterMixin):
yield from rendered_cell[line_no]
yield new_line
if _box and first and show_header:
yield Segment(
yield _Segment(
_box.get_row(widths, "head", edge=show_edge), border_style
)
yield new_line
@ -735,24 +738,24 @@ class Table(JupyterMixin):
if __name__ == "__main__": # pragma: no cover
from .console import Console
from . import box
c = Console()
table = Table(
show_lines=False,
row_styles=["red", "green"],
row_styles=["on blue", "on red"],
expand=False,
show_header=True,
show_footer=False,
show_edge=True,
box=box.SIMPLE,
)
table.add_column("foo", no_wrap=True, footer="BAR")
table.add_column("bar")
table.add_column("baz")
table.add_row("Magnet", "foo" * 20, "bar" * 10, "egg" * 15)
table.add_row("Magnet", "foo" * 20, "bar" * 10, "egg" * 15)
table.add_row("Magnet", "foo" * 20, "bar" * 10, "egg" * 15)
table.add_row("Magnet", "foo" * 20, "bar" * 10, "egg" * 15)
for width in range(170, 1, -1):
print(" " * width + "<|")
c = Console(width=width)
c.print(table)
c.print("Some more words", width=4, overflow="ellipsis")
c.print(table)

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@ from rich.panel import Panel
def render():
console = Console(file=io.StringIO(), width=100, legacy_windows=False)
panel = Panel.fit("foo", box=box.SQUARE)
panel = Panel.fit("foo", box=box.SQUARE, padding=0)
columns = Columns([panel] * 4)
columns.expand = True
console.rule("no align")

View file

@ -232,7 +232,7 @@ def test_justify_renderable_none():
console = Console(
file=io.StringIO(), force_terminal=True, width=20, legacy_windows=False
)
console.print(Panel("FOO", expand=False), justify=None)
console.print(Panel("FOO", expand=False, padding=0), justify=None)
assert console.file.getvalue() == "╭───╮\n│FOO│\n╰───╯\n"
@ -240,7 +240,7 @@ def test_justify_renderable_left():
console = Console(
file=io.StringIO(), force_terminal=True, width=10, legacy_windows=False
)
console.print(Panel("FOO", expand=False), justify="left")
console.print(Panel("FOO", expand=False, padding=0), justify="left")
assert console.file.getvalue() == "╭───╮ \n│FOO│ \n╰───╯ \n"
@ -248,7 +248,7 @@ def test_justify_renderable_center():
console = Console(
file=io.StringIO(), force_terminal=True, width=10, legacy_windows=False
)
console.print(Panel("FOO", expand=False), justify="center")
console.print(Panel("FOO", expand=False, padding=0), justify="center")
assert console.file.getvalue() == " ╭───╮ \n │FOO│ \n ╰───╯ \n"
@ -256,7 +256,7 @@ def test_justify_renderable_right():
console = Console(
file=io.StringIO(), force_terminal=True, width=20, legacy_windows=False
)
console.print(Panel("FOO", expand=False), justify="right")
console.print(Panel("FOO", expand=False, padding=0), justify="right")
assert (
console.file.getvalue()
== " ╭───╮\n │FOO│\n ╰───╯\n"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -5,12 +5,12 @@ from rich.panel import Panel
import pytest
tests = [
Panel("Hello, World"),
Panel("Hello, World", expand=False),
Panel.fit("Hello, World"),
Panel("Hello, World", width=8),
Panel(Panel("Hello, World")),
Panel("Hello, World", title="FOO"),
Panel("Hello, World", padding=0),
Panel("Hello, World", expand=False, padding=0),
Panel.fit("Hello, World", padding=0),
Panel("Hello, World", width=8, padding=0),
Panel(Panel("Hello, World", padding=0), padding=0),
Panel("Hello, World", title="FOO", padding=0),
]
expected = [
@ -38,8 +38,8 @@ def test_console_width():
console = Console(file=io.StringIO(), width=50, legacy_windows=False)
panel = Panel("Hello, World", expand=False)
min_width, max_width = panel.__rich_measure__(console, 50)
assert min_width == 14
assert max_width == 14
assert min_width == 16
assert max_width == 16
if __name__ == "__main__":

View file

@ -20,5 +20,5 @@ def test_rich_cast():
def test_rich_cast_container():
foo = Foo()
console = Console(file=io.StringIO(), legacy_windows=False)
console.print(Panel.fit(foo))
console.print(Panel.fit(foo, padding=0))
assert console.file.getvalue() == "╭───╮\n│Foo│\n╰───╯\n"

View file

@ -190,3 +190,9 @@ def test_style_stack():
def test_pick_first():
with pytest.raises(ValueError):
Style.pick_first()
def test_background_style():
assert Style(bold=True, color="yellow", bgcolor="red").background_style == Style(
bgcolor="red"
)

View file

@ -45,7 +45,8 @@ def test_python_render():
theme="foo",
code_width=60,
word_wrap=True,
)
),
padding=0,
)
rendered_syntax = render(syntax)
print(repr(rendered_syntax))
@ -192,7 +193,8 @@ if __name__ == "__main__":
theme="foo",
code_width=60,
word_wrap=True,
)
),
padding=0,
)
rendered = render(markdown)
print(rendered)