From bba5e50aa421e7f2a153a3ccf096b0b5dbffe84a Mon Sep 17 00:00:00 2001 From: Faheem12005 Date: Wed, 24 Dec 2025 23:45:04 +0530 Subject: [PATCH 1/2] Fix Live leaving blank line for empty renderables --- CHANGELOG.md | 5 +++++ CONTRIBUTORS.md | 1 + rich/live.py | 6 +++++- rich/live_render.py | 14 ++++++++++++-- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e53205666f..057d1faba6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### Added + +- Fixed `Live(transient=True)` leaving a blank line when the renderable produces no output. + + # Changelog All notable changes to this project will be documented in this file. diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 4b04786b9c..7dfc622f63 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -94,3 +94,4 @@ The following people have contributed to the development of Rich: - [Jonathan Helmus](https://github.com/jjhelmus) - [Brandon Capener](https://github.com/bcapener) - [Alex Zheng](https://github.com/alexzheng111) +- [Mohammed Faheem](https://github.com/Faheem12005) diff --git a/rich/live.py b/rich/live.py index cc3a39bd57..cf0f5db285 100644 --- a/rich/live.py +++ b/rich/live.py @@ -166,7 +166,11 @@ def stop(self) -> None: finally: self._disable_redirect_io() self.console.pop_render_hook() - if not self._alt_screen and self.console.is_terminal: + if ( + not self._alt_screen + and self.console.is_terminal + and self._live_render.has_rendered_rows() + ): self.console.line() self.console.show_cursor(True) if self._alt_screen: diff --git a/rich/live_render.py b/rich/live_render.py index d3da5111d8..e22c921afe 100644 --- a/rich/live_render.py +++ b/rich/live_render.py @@ -1,5 +1,4 @@ -from typing import Optional, Tuple, Literal - +from typing import Literal, Optional, Tuple from ._loop import loop_last from .console import Console, ConsoleOptions, RenderableType, RenderResult @@ -59,6 +58,17 @@ def position_cursor(self) -> Control: ) return Control() + def has_rendered_rows(self) -> bool: + """Check if there are any rendered rows. + + Returns: + bool: True if there are rendered rows, False otherwise. + """ + if self._shape is not None: + _, height = self._shape + return height > 0 + return False + def restore_cursor(self) -> Control: """Get control codes to clear the render and restore the cursor to its previous position. From 61c305f193e625b79f4769c51a0e9d17b9b8942a Mon Sep 17 00:00:00 2001 From: Faheem12005 Date: Thu, 25 Dec 2025 12:46:20 +0530 Subject: [PATCH 2/2] add tests for changes to LiveRender --- tests/test_live_render.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/test_live_render.py b/tests/test_live_render.py index e8ae11087a..ec52fe93fd 100644 --- a/tests/test_live_render.py +++ b/tests/test_live_render.py @@ -1,8 +1,9 @@ import pytest -from rich.live_render import LiveRender + from rich.console import Console, ConsoleDimensions, ConsoleOptions -from rich.style import Style +from rich.live_render import LiveRender from rich.segment import Segment +from rich.style import Style @pytest.fixture @@ -28,6 +29,14 @@ def test_restore_cursor(live_render): assert str(live_render.restore_cursor()) == "\r\x1b[1A\x1b[2K\x1b[1A\x1b[2K" +def test_has_rendered_rows(live_render): + assert live_render.has_rendered_rows() is False + live_render._shape = (80, 0) + assert live_render.has_rendered_rows() is False + live_render._shape = (80, 1) + assert live_render.has_rendered_rows() is True + + def test_rich_console(live_render): options = ConsoleOptions( ConsoleDimensions(80, 25),