resolved RESOLVED LOOP PASS · 11 tool calls · 105 s · Textualize/rich
Update progress.py Don't output extraneous blank line when progress display is disabled <!-- Please note that Rich isn't accepting any new features at this point. If a feature can be implemented without modifying the core library, then they should be released as a third-party module. I can accept updates to the core library that make it easier to extend (think hooks). Bugfixes are always welcome of course. Sometimes it is not clear what is a feature and what is a bug fix. If there is any doubt, please open a discussion first. --> <!-- *Are you contributing typo fixes?* If your PR solely consists of typos, at least one must be in the docs to warrant an addition to CONTRIBUTORS.md --> ## Type of changes - [x] Bug fix - [ ] New feature - [ ] Documentation / docstrings - [ ] Tests - [ ] Other ## AI? - [ ] AI was used to generate this PR AI generated PRs may be accepted, but only if @willmcgugan has responded on an issue or discussion. ## Checklist - [x] I've run the latest [black](https://github.com/psf/black) with default args on new code. - [x] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate (see note about typos above). - [x] I've added tests for new code. - [x] I accept that @willmcgugan may be pedantic in the code review. ## Description When creating a `Progress` with `disabled=True`, it still outputs a blank line on non interactive consoles. This PR adds an `if not self.disable` to the `stop` function, symmetrically to the `start` function. **Important:** Link to an issue or discussion regarding these changes. https://github.com/Textualize/rich/issues/110
| # | Tool | Arguments | Result |
|---|---|---|---|
| 1 | run_command | {
"command": "find rich -name \"progress.py\""
} | {"status": "ok", "stdout": "rich/progress.py\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "rich/progress.py\n", "stderr": "", "exit_code": 0} |
| 2 | read_file | {
"filepath": "rich/progress.py"
} | {"status": "ok", "filepath": "rich/progress.py", "content": "from __future__ import annotations\n\nimport io\nimport typing\nimport warnings\nfrom abc import ABfull{"status": "ok", "filepath": "rich/progress.py", "content": "from __future__ import annotations\n\nimport io\nimport typing\nimport warnings\nfrom abc import ABC, abstractmethod\nfrom collections import deque\nfrom dataclasses import dataclass, field\nfrom datetime import timedelta\nfrom io import RawIOBase, UnsupportedOperation\nfrom math import ceil\nfrom mmap import mmap\nfrom operator import length_hint\nfrom os import PathLike, stat\nfrom threading import Event, RLock, Thread\nfrom types import TracebackType\nfrom typing import (\n TYPE_CHECKING,\n Any,\n BinaryIO,\n Callable,\n ContextManager,\n Deque,\n Dict,\n Generic,\n Iterable,\n List,\n Literal,\n NamedTuple,\n NewType,\n Optional,\n TextIO,\n Tuple,\n Type,\n TypeVar,\n Union,\n)\n\nif TYPE_CHECKING:\n # Can be replaced with `from typing import Self` in Python 3.11+\n from typing_extensions import Self # pragma: no cover\n\nfrom . import filesize, get_console\nfrom .console import Console, Group, JustifyMethod, RenderableType\nfrom .highlighter import Highlighter\nfrom .jupyter import JupyterMixin\nfrom .live import Live\nfrom .progress_bar import ProgressBar\nfrom .spinner import Spinner\nfrom .style import StyleType\nfrom .table import Column, Table\nfrom .text import Text, TextType\n\nTaskID = NewType(\"TaskID\", int)\n\nProgressType = TypeVar(\"ProgressType\")\n\nGetTimeCallable = Callable[[], float]\n\n\n_I = typing.TypeVar(\"_I\", TextIO, BinaryIO)\n\n\nclass _TrackThread(Thread):\n \"\"\"A thread to periodically update progress.\"\"\"\n\n def __init__(self, progress: \"Progress\", task_id: \"TaskID\", update_period: float):\n self.progress = progress\n self.task_id = task_id\n self.update_period = update_period\n self.done = Event()\n\n self.completed = 0\n super().__init__(daemon=True)\n\n def run(self) -> None:\n task_id = self.task_id\n advance = self.progress.advanc |
| 3-5 ×3 | read_file | {
"filepath": "rich/progress.py",
"start_line": "150"
} | {"status": "error", "error_type": "FileReadError", "error_message": "'>' not supported between instances of 'int' and 'str'"}full{"status": "error", "error_type": "FileReadError", "error_message": "'>' not supported between instances of 'int' and 'str'"} |
| 6 | run_command | {
"command": "grep -n \"def stop\" rich/progress.py"
} | {"status": "ok", "stdout": "1173: def stop(self) -> None:\n1401: def stop_task(self, task_id: TaskID) -> None:\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "1173: def stop(self) -> None:\n1401: def stop_task(self, task_id: TaskID) -> None:\n", "stderr": "", "exit_code": 0} |
| 7 | read_file | {
"filepath": "rich/progress.py",
"start_line": "1160",
"end_line": "1185"
} | {"status": "error", "error_type": "FileReadError", "error_message": "'>' not supported between instances of 'int' and 'str'"}full{"status": "error", "error_type": "FileReadError", "error_message": "'>' not supported between instances of 'int' and 'str'"} |
| 8 | run_command | {
"command": "sed -n '1160,1185p' rich/progress.py"
} | {"status": "ok", "stdout": " @property\n def finished(self) -> bool:\n \"\"\"Check if all tasks have been completed.\"\"\"\n with self._lock:\n if not self._tasfull{"status": "ok", "stdout": " @property\n def finished(self) -> bool:\n \"\"\"Check if all tasks have been completed.\"\"\"\n with self._lock:\n if not self._tasks:\n return True\n return all(task.finished for task in self._tasks.values())\n\n def start(self) -> None:\n \"\"\"Start the progress display.\"\"\"\n if not self.disable:\n self.live.start(refresh=True)\n\n def stop(self) -> None:\n \"\"\"Stop the progress display.\"\"\"\n self.live.stop()\n if not self.console.is_interactive and not self.console.is_jupyter:\n self.console.print()\n\n def __enter__(self) -> Self:\n self.start()\n return self\n\n def __exit__(\n self,\n exc_type: Optional[Type[BaseException]],\n", "stderr": "", "exit_code": 0} |
| 9 | edit_file | {
"filepath": "rich/progress.py",
"new_string": " def stop(self) -> None:\n \"\"\"Stop the progress display.\"\"\"\n if not self.disable:\n self.live.stop()\n if not self.console.is_interactive and not self.console.is_jupyter:\n self.console.print()",
"old_string": " def stop(self) -> None:\n \"\"\"Stop the progress display.\"\"\"\n self.live.stop()\n if not self.console.is_interactive and not self.console.is_jupyter:\n self.console.print()"
} | {"status": "ok", "filepath": "rich/progress.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/progress.py\n+++ b/rich/progress.py\n@@ -1172,9 +117full{"status": "ok", "filepath": "rich/progress.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/rich/progress.py\n+++ b/rich/progress.py\n@@ -1172,9 +1172,10 @@\n \n def stop(self) -> None:\n \"\"\"Stop the progress display.\"\"\"\n- self.live.stop()\n- if not self.console.is_interactive and not self.console.is_jupyter:\n- self.console.print()\n+ if not self.disable:\n+ self.live.stop()\n+ if not self.console.is_interactive and not self.console.is_jupyter:\n+ self.console.print()\n \n def __enter__(self) -> Self:\n self.start()\n", "is_truncated": false} |
| 10 | write_file | {
"content": "from rich.progress import Progress\nfrom rich.console import Console\nimport io\n\ndef test_progress_disabled_no_blank_line():\n # Use a non-interactive console to trigger the blank line behavior\n console = Console(force_terminal=False, file=io.StringIO())\n \n with Progress(console=console, disable=True) as progress:\n progress.add_task(\"Testing\", total=10)\n progress.update(0, completed=10)\n \n output = console.file.getvalue()\n # If disabled, there should be no output at all, including no blank lines.\n assert output == \"\", f\"Expected no output when progress is disabled, but got: {repr(output)}\"\n\nif __name__ == \"__main__\":\n test_progress_disabled_no_blank_line()\n print(\"Test passed!\")\n",
"filepath": "test_progress_disabled.py"
} | {"status": "ok", "filepath": "test_progress_disabled.py", "size": 729}full{"status": "ok", "filepath": "test_progress_disabled.py", "size": 729} |
| 11 | run_command | {
"command": "python test_progress_disabled.py"
} | {"status": "ok", "stdout": "Test passed!\n", "stderr": "", "exit_code": 0}full{"status": "ok", "stdout": "Test passed!\n", "stderr": "", "exit_code": 0} |
| 12 | submit_patch | {} | {"status": "ok", "patch_size": 1551, "files_changed": 2}full{"status": "ok", "patch_size": 1551, "files_changed": 2} |
diff --git a/rich/progress.py b/rich/progress.py
index 421e1411..f55b981e 100644
--- a/rich/progress.py
+++ b/rich/progress.py
@@ -1172,9 +1172,10 @@ class Progress(JupyterMixin):
def stop(self) -> None:
"""Stop the progress display."""
- self.live.stop()
- if not self.console.is_interactive and not self.console.is_jupyter:
- self.console.print()
+ if not self.disable:
+ self.live.stop()
+ if not self.console.is_interactive and not self.console.is_jupyter:
+ self.console.print()
def __enter__(self) -> Self:
self.start()
diff --git a/test_progress_disabled.py b/test_progress_disabled.py
new file mode 100644
index 00000000..08a6e1e9
--- /dev/null
+++ b/test_progress_disabled.py
@@ -0,0 +1,19 @@
+from rich.progress import Progress
+from rich.console import Console
+import io
+
+def test_progress_disabled_no_blank_line():
+ # Use a non-interactive console to trigger the blank line behavior
+ console = Console(force_terminal=False, file=io.StringIO())
+
+ with Progress(console=console, disable=True) as progress:
+ progress.add_task("Testing", total=10)
+ progress.update(0, completed=10)
+
+ output = console.file.getvalue()
+ # If disabled, there should be no output at all, including no blank lines.
+ assert output == "", f"Expected no output when progress is disabled, but got: {repr(output)}"
+
+if __name__ == "__main__":
+ test_progress_disabled_no_blank_line()
+ print("Test passed!")
....................................... [100%] 39 passed in 0.64s