Skip to content

Commit

Permalink
Merge pull request #3509 from Textualize/panel-title-style
Browse files Browse the repository at this point in the history
respect text.style in panels
  • Loading branch information
willmcgugan authored Oct 1, 2024
2 parents 7022e20 + 7db6b63 commit 92abd70
Show file tree
Hide file tree
Showing 14 changed files with 377 additions and 388 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/codespell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ jobs:
- uses: actions/checkout@v4
- run: python3 -m pip install codespell
- run: codespell --ignore-words-list="ba,fo,hel,revered,womens"
--skip="./README.*.md,*.svg,*.ai,./benchmarks/snippets.py,./tests,./tools"
--skip="./README.*.md,*.svg,*.ai,./benchmarks/snippets.py,./tests,./tools,*.lock"
11 changes: 4 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

## [13.9.0]

### Changed

- Dropped support for Python3.7 https://github.com/Textualize/rich/pull/3509
- Rich will display tracebacks with finely grained error locations on python 3.11+ https://github.com/Textualize/rich/pull/3486


### Fixed

- Fixed issue with Segment._split_cells https://github.com/Textualize/rich/pull/3506
- Fix auto detection of terminal size on Windows https://github.com/Textualize/rich/pull/2916

### Added

- Add a new `column` object `IterationSpeedColumn`. https://github.com/Textualize/rich/pull/3332
- `Text.style` now respected in Panel title/subtitle https://github.com/Textualize/rich/pull/3509

## [13.8.1] - 2024-09-10

Expand Down Expand Up @@ -2088,6 +2084,7 @@ Major version bump for a breaking change to `Text.stylize signature`, which corr

- First official release, API still to be stabilized

[13.9.0]: https://github.com/textualize/rich/compare/v13.8.1...v13.9.0
[13.8.1]: https://github.com/textualize/rich/compare/v13.8.0...v13.8.1
[13.8.0]: https://github.com/textualize/rich/compare/v13.7.1...v13.8.0
[13.7.1]: https://github.com/textualize/rich/compare/v13.7.0...v13.7.1
Expand Down
643 changes: 313 additions & 330 deletions poetry.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "rich"
homepage = "https://github.com/Textualize/rich"
documentation = "https://rich.readthedocs.io/en/latest/"
version = "13.8.1"
version = "13.9.0"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
authors = ["Will McGugan <willmcgugan@gmail.com>"]
license = "MIT"
Expand All @@ -28,7 +28,7 @@ include = ["rich/py.typed"]


[tool.poetry.dependencies]
python = ">=3.7.0"
python = ">=3.8.0"
typing-extensions = { version = ">=4.0.0, <5.0", python = "<3.9" }
pygments = "^2.13.0"
ipywidgets = { version = ">=7.5.1,<9", optional = true }
Expand All @@ -40,7 +40,7 @@ jupyter = ["ipywidgets"]
[tool.poetry.dev-dependencies]
pytest = "^7.0.0"
black = "^22.6"
mypy = "^0.971"
mypy = "^1.11"
pytest-cov = "^3.0.0"
attrs = "^21.4.0"
pre-commit = "^2.17.0"
Expand Down
2 changes: 1 addition & 1 deletion rich/_null_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __iter__(self) -> Iterator[str]:
return iter([""])

def __enter__(self) -> IO[str]:
pass
return self

def __exit__(
self,
Expand Down
7 changes: 3 additions & 4 deletions rich/_win32_console.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
The API that this module wraps is documented at https://docs.microsoft.com/en-us/windows/console/console-functions
"""

import ctypes
import sys
from typing import Any
Expand Down Expand Up @@ -380,7 +381,7 @@ def cursor_position(self) -> WindowsCoordinates:
WindowsCoordinates: The current cursor position.
"""
coord: COORD = GetConsoleScreenBufferInfo(self._handle).dwCursorPosition
return WindowsCoordinates(row=cast(int, coord.Y), col=cast(int, coord.X))
return WindowsCoordinates(row=coord.Y, col=coord.X)

@property
def screen_size(self) -> WindowsCoordinates:
Expand All @@ -390,9 +391,7 @@ def screen_size(self) -> WindowsCoordinates:
WindowsCoordinates: The width and height of the screen as WindowsCoordinates.
"""
screen_size: COORD = GetConsoleScreenBufferInfo(self._handle).dwSize
return WindowsCoordinates(
row=cast(int, screen_size.Y), col=cast(int, screen_size.X)
)
return WindowsCoordinates(row=screen_size.Y, col=screen_size.X)

def write_text(self, text: str) -> None:
"""Write text directly to the terminal without any modification of styles
Expand Down
11 changes: 6 additions & 5 deletions rich/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,15 @@ class NoChange:
NO_CHANGE = NoChange()

try:
_STDIN_FILENO = sys.__stdin__.fileno()
_STDIN_FILENO = sys.__stdin__.fileno() # type: ignore[union-attr]
except Exception:
_STDIN_FILENO = 0
try:
_STDOUT_FILENO = sys.__stdout__.fileno()
_STDOUT_FILENO = sys.__stdout__.fileno() # type: ignore[union-attr]
except Exception:
_STDOUT_FILENO = 1
try:
_STDERR_FILENO = sys.__stderr__.fileno()
_STDERR_FILENO = sys.__stderr__.fileno() # type: ignore[union-attr]
except Exception:
_STDERR_FILENO = 2

Expand Down Expand Up @@ -1005,7 +1005,8 @@ def size(self) -> ConsoleDimensions:
width: Optional[int] = None
height: Optional[int] = None

for file_descriptor in _STD_STREAMS_OUTPUT if WINDOWS else _STD_STREAMS:
streams = _STD_STREAMS_OUTPUT if WINDOWS else _STD_STREAMS
for file_descriptor in streams:
try:
width, height = os.get_terminal_size(file_descriptor)
except (AttributeError, ValueError, OSError): # Probably not a terminal
Expand Down Expand Up @@ -1302,7 +1303,7 @@ def render(

renderable = rich_cast(renderable)
if hasattr(renderable, "__rich_console__") and not isclass(renderable):
render_iterable = renderable.__rich_console__(self, _options) # type: ignore[union-attr]
render_iterable = renderable.__rich_console__(self, _options)
elif isinstance(renderable, str):
text_renderable = self.render_str(
renderable, highlight=_options.highlight, markup=_options.markup
Expand Down
10 changes: 5 additions & 5 deletions rich/padding.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import cast, List, Optional, Tuple, TYPE_CHECKING, Union
from typing import TYPE_CHECKING, List, Optional, Tuple, Union

if TYPE_CHECKING:
from .console import (
Expand All @@ -7,11 +7,11 @@
RenderableType,
RenderResult,
)

from .jupyter import JupyterMixin
from .measure import Measurement
from .style import Style
from .segment import Segment

from .style import Style

PaddingDimensions = Union[int, Tuple[int], Tuple[int, int], Tuple[int, int, int, int]]

Expand Down Expand Up @@ -66,10 +66,10 @@ def unpack(pad: "PaddingDimensions") -> Tuple[int, int, int, int]:
_pad = pad[0]
return (_pad, _pad, _pad, _pad)
if len(pad) == 2:
pad_top, pad_right = cast(Tuple[int, int], pad)
pad_top, pad_right = pad
return (pad_top, pad_right, pad_top, pad_right)
if len(pad) == 4:
top, right, bottom, left = cast(Tuple[int, int, int, int], pad)
top, right, bottom, left = pad
return (top, right, bottom, left)
raise ValueError(f"1, 2 or 4 integers required for padding; {len(pad)} given")

Expand Down
5 changes: 3 additions & 2 deletions rich/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ def align_text(
text = text.copy()
text.truncate(width)
excess_space = width - cell_len(text.plain)
if text.style:
text.stylize(console.get_style(text.style))

if excess_space:
if align == "left":
return Text.assemble(
Expand Down Expand Up @@ -203,8 +206,6 @@ def align_text(

title_text = self._title
if title_text is not None:
if title_text.style is not None:
title_text.stylize_before(title_text.style)
title_text.stylize_before(partial_border_style)

child_width = (
Expand Down
22 changes: 3 additions & 19 deletions rich/progress.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,9 @@ def tell(self) -> int:
def write(self, s: Any) -> int:
raise UnsupportedOperation("write")

def writelines(self, lines: Iterable[Any]) -> None:
raise UnsupportedOperation("writelines")


class _ReadContext(ContextManager[_I], Generic[_I]):
"""A utility class to handle a context for both a reader and a progress."""
Expand Down Expand Up @@ -922,25 +925,6 @@ def render(self, task: "Task") -> Text:
return Text(f"{data_speed}/s", style="progress.data.speed")


class IterationSpeedColumn(ProgressColumn):
"""Renders iterations per second, e.g. '11.4 it/s'."""

def render(self, task: "Task") -> Text:
last_speed = task.last_speed if hasattr(task, 'last_speed') else None
if task.finished and last_speed is not None:
return Text(f"{last_speed} it/s", style="progress.data.speed")
if task.speed is None:
return Text("", style="progress.data.speed")
unit, suffix = filesize.pick_unit_and_suffix(
int(task.speed),
["", "×10³", "×10⁶", "×10⁹", "×10¹²"],
1000,
)
data_speed = task.speed / unit
task.last_speed = f"{data_speed:.1f}{suffix}"
return Text(f"{task.last_speed} it/s", style="progress.data.speed")


class ProgressSample(NamedTuple):
"""Sample of progress for a given time."""

Expand Down
2 changes: 1 addition & 1 deletion rich/segment.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ def divide(
while True:
cut = next(iter_cuts, -1)
if cut == -1:
return []
return
if cut != 0:
break
yield []
Expand Down
5 changes: 3 additions & 2 deletions rich/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
List,
NamedTuple,
Optional,
Pattern,
Tuple,
Union,
)
Expand Down Expand Up @@ -173,7 +174,7 @@ def __str__(self) -> str:
return self.plain

def __repr__(self) -> str:
return f"<text {self.plain!r} {self._spans!r}>"
return f"<text {self.plain!r} {self._spans!r} {self.style!r}>"

def __add__(self, other: Any) -> "Text":
if isinstance(other, (str, Text)):
Expand Down Expand Up @@ -591,7 +592,7 @@ def extend_style(self, spaces: int) -> None:

def highlight_regex(
self,
re_highlight: Union[re.Pattern, str],
re_highlight: Union[Pattern[str], str],
style: Optional[Union[GetStyleCallable, StyleType]] = None,
*,
style_prefix: str = "",
Expand Down
35 changes: 30 additions & 5 deletions tests/test_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from rich.panel import Panel
from rich.segment import Segment
from rich.style import Style
from rich.text import Text

tests = [
Panel("Hello, World", padding=0),
Expand All @@ -31,31 +32,33 @@
def render(panel, width=50) -> str:
console = Console(file=io.StringIO(), width=50, legacy_windows=False)
console.print(panel)
return console.file.getvalue()
result = console.file.getvalue()
print(result)
return result


@pytest.mark.parametrize("panel,expected", zip(tests, expected))
def test_render_panel(panel, expected):
def test_render_panel(panel, expected) -> None:
assert render(panel) == expected


def test_console_width():
def test_console_width() -> None:
console = Console(file=io.StringIO(), width=50, legacy_windows=False)
panel = Panel("Hello, World", expand=False)
min_width, max_width = panel.__rich_measure__(console, console.options)
assert min_width == 16
assert max_width == 16


def test_fixed_width():
def test_fixed_width() -> None:
console = Console(file=io.StringIO(), width=50, legacy_windows=False)
panel = Panel("Hello World", width=20)
min_width, max_width = panel.__rich_measure__(console, console.options)
assert min_width == 20
assert max_width == 20


def test_render_size():
def test_render_size() -> None:
console = Console(width=63, height=46, legacy_windows=False)
options = console.options.update_dimensions(80, 4)
lines = console.render_lines(Panel("foo", title="Hello"), options=options)
Expand Down Expand Up @@ -99,6 +102,28 @@ def test_render_size():
assert lines == expected


def test_title_text() -> None:
panel = Panel(
"Hello, World",
title=Text("title", style="red"),
subtitle=Text("subtitle", style="magenta bold"),
)
console = Console(
file=io.StringIO(),
width=50,
height=20,
legacy_windows=False,
force_terminal=True,
color_system="truecolor",
)
console.print(panel)

result = console.file.getvalue()
print(repr(result))
expected = "╭────────────────────\x1b[31m title \x1b[0m─────────────────────╮\n│ Hello, World │\n╰───────────────────\x1b[1;35m subtitle \x1b[0m───────────────────╯\n"
assert result == expected


if __name__ == "__main__":
expected = []
for panel in tests:
Expand Down
Loading

0 comments on commit 92abd70

Please sign in to comment.