← eval3_submission

rich_3905

resolved RESOLVED PASS · 12 tool calls · 133 s · Textualize/rich

Task input

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 calls (13)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"class Progress\" rich | head -20"
}
{"status": "ok", "stdout": "rich/progress_bar.py:18:class ProgressBar(JupyterMixin):\nrich/progress.py:507:class ProgressColumn(ABC):\nrich/progress.py:926:clas
full
{"status": "ok", "stdout": "rich/progress_bar.py:18:class ProgressBar(JupyterMixin):\nrich/progress.py:507:class ProgressColumn(ABC):\nrich/progress.py:926:class ProgressSample(NamedTuple):\nrich/progress.py:1061:class Progress(JupyterMixin):\n", "exit_code": 0}
2read_file
{
 "filepath": "rich/progress.py",
 "start_line": 1061
}
{"status": "ok", "filepath": "rich/progress.py", "content": "class Progress(JupyterMixin):\n \"\"\"Renders an auto-updating progress bar(s).\n\n Args:\n console
full
{"status": "ok", "filepath": "rich/progress.py", "content": "class Progress(JupyterMixin):\n    \"\"\"Renders an auto-updating progress bar(s).\n\n    Args:\n        console (Console, optional): Optional Console instance. Defaults to an internal Console instance writing to stdout.\n        auto_refresh (bool, optional): Enable auto refresh. If disabled, you will need to call `refresh()`.\n        refresh_per_second (float, optional): Number of times per second to refresh the progress information. Defaults to 10.\n        speed_estimate_period: (float, optional): Period (in seconds) used to calculate the speed estimate. Defaults to 30.\n        transient: (bool, optional): Clear the progress on exit. Defaults to False.\n        redirect_stdout: (bool, optional): Enable redirection of stdout, so ``print`` may be used. Defaults to True.\n        redirect_stderr: (bool, optional): Enable redirection of stderr. Defaults to True.\n        get_time: (Callable, optional): A callable that gets the current time, or None to use Console.get_time. Defaults to None.\n        disable (bool, optional): Disable progress display. Defaults to False\n        expand (bool, optional): Expand tasks table to fit width. Defaults to False.\n    \"\"\"\n\n    def __init__(\n        self,\n        *columns: Union[str, ProgressColumn],\n        console: Optional[Console] = None,\n        auto_refresh: bool = True,\n        refresh_per_second: float = 10,\n        speed_estimate_period: float = 30.0,\n        transient: bool = False,\n        redirect_stdout: bool = True,\n        redirect_stderr: bool = True,\n        get_time: Optional[GetTimeCallable] = None,\n        disable: bool = False,\n        expand: bool = False,\n    ) -> None:\n        assert refresh_per_second > 0, \"refresh_per_second must be > 0\"\n        self._lock = RLock()\n        self.columns = columns or self.get_default_columns()\n        self.speed_estimate_period = speed_estimate_period\n\n        self.disable = disable
3read_file
{
 "filepath": "rich/progress.py",
 "start_line": 1160,
 "end_line": 1170
}
{"status": "ok", "filepath": "rich/progress.py", "content": " @property\n def finished(self) -> bool:\n \"\"\"Check if all tasks have been completed.\"\"\"\n wi
full
{"status": "ok", "filepath": "rich/progress.py", "content": "    @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", "start_line": 1160, "end_line": 1170, "total_lines": 1715, "is_truncated": false}
4read_file
{
 "end_line": 1180,
 "filepath": "rich/progress.py",
 "start_line": 1170
}
{"status": "ok", "filepath": "rich/progress.py", "content": " if not self.disable:\n self.live.start(refresh=True)\n\n def stop(self) -> None:\n \"\"\"Stop the
full
{"status": "ok", "filepath": "rich/progress.py", "content": "        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", "start_line": 1170, "end_line": 1180, "total_lines": 1715, "is_truncated": false}
5edit_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 +117
full
{"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}
6write_file
{
 "content": "from rich.progress import Progress\nfrom rich.console import Console\nimport io\n\ndef test_disabled_progress_no_blank_line():\n    # Use a non-interactive console (writing to a string buffer)\n    console = Console(file=io.StringIO(), force_terminal=False)\n    \n    # Case 1: disabled=True\n    with Progress(console=console, disable=True) as progress:\n        pass\n    \n    output = console.file.getvalue()\n    assert output == \"\", f\"Expected no output when disabled, got {repr(output)}\"\n\n    # Reset buffer\n    console.file.truncate(0)\n    console.file.seek(0)\n\n    # Case 2: disabled=False (should still output blank line on non-interactive console)\n    with Progress(console=console, disable=False) as progress:\n        pass\n    \n    output = console.file.getvalue()\n    # The Live.stop() might not print anything, but the stop() method in Progress does.\n    # Let's check if it prints a newline.\n    assert output == \"\\n\", f\"Expected newline when enabled on non-interactive console, got {repr(output)}\"\n\nif __name__ == \"__main__\":\n    test_disabled_progress_no_blank_line()\n    print(\"Test passed!\")\n",
 "filepath": "/tmp/test_progress_disabled.py"
}
{"status": "ok", "filepath": "/tmp/test_progress_disabled.py", "size": 1099}
full
{"status": "ok", "filepath": "/tmp/test_progress_disabled.py", "size": 1099}
7run_command
{
 "command": "python3 /tmp/test_progress_disabled.py"
}
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "python3: can't open f
full
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "python3: can't open file '/tmp/swe_work/eval3_submission/rich_3905/a/tmp/test_progress_disabled.py': [Errno 2] No such file or directory\n", "exit_code": 2}}
8run_command
{
 "command": "python3 /workspace/tmp/test_progress_disabled.py"
}
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "python3: can't open f
full
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "python3: can't open file '/tmp/swe_work/eval3_submission/rich_3905/a/workspace/tmp/test_progress_disabled.py': [Errno 2] No such file or directory\n", "exit_code": 2}}
9run_command
{
 "command": "ls -R /workspace"
}
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "ls: cannot access '/t
full
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 2", "details": {"stdout": "", "stderr": "ls: cannot access '/tmp/swe_work/eval3_submission/rich_3905/a/workspace': No such file or directory\n", "exit_code": 2}}
10run_command
{
 "command": "python3 -c \"from rich.progress import Progress; from rich.console import Console; import io; console = Console(file=io.StringIO(), force_terminal=False); Progress(console=console, disable=True).start(); Progress(console=console, disable=True).stop(); print(f'Output: {repr(console.file.getvalue())}')\""
}
{"status": "ok", "stdout": "Output: ''\n", "exit_code": 0}
full
{"status": "ok", "stdout": "Output: ''\n", "exit_code": 0}
11run_command
{
 "command": "python3 -c \"from rich.progress import import Progress; from rich.console import Console; import io; console = Console(file=io.StringIO(), force_terminal=False); Progress(console=console, disable=False).start(); Progress(console=console, disable=False).stop(); print(f'Output: {repr(console.file.getvalue())}')\""
}
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": " File \"<string>\", l
full
{"status": "error", "error_type": "CommandError", "error_message": "Command failed with exit code 1", "details": {"stdout": "", "stderr": "  File \"<string>\", line 1\n    from rich.progress import import Progress; from rich.console import Console; import io; console = Console(file=io.StringIO(), force_terminal=False); Progress(console=console, disable=False).start(); Progress(console=console, disable=False).stop(); print(f'Output: {repr(console.file.getvalue())}')\n                              ^^^^^^\nSyntaxError: invalid syntax\n", "exit_code": 1}}
12run_command
{
 "command": "python3 -c \"from rich.progress import Progress; from rich.console import Console; import io; console = Console(file=io.StringIO(), force_terminal=False); Progress(console=console, disable=False).start(); Progress(console=console, disable=False).stop(); print(f'Output: {repr(console.file.getvalue())}')\""
}
{"status": "ok", "stdout": "Output: '\\n'\n", "exit_code": 0}
full
{"status": "ok", "stdout": "Output: '\\n'\n", "exit_code": 0}
13submit_patch
[]
{"status": "ok", "patch_size": 1945, "files_changed": 2}
full
{"status": "ok", "patch_size": 1945, "files_changed": 2}

Patch

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/tmp/test_progress_disabled.py b/tmp/test_progress_disabled.py
new file mode 100644
index 00000000..e42b5dae
--- /dev/null
+++ b/tmp/test_progress_disabled.py
@@ -0,0 +1,31 @@
+from rich.progress import Progress
+from rich.console import Console
+import io
+
+def test_disabled_progress_no_blank_line():
+    # Use a non-interactive console (writing to a string buffer)
+    console = Console(file=io.StringIO(), force_terminal=False)
+    
+    # Case 1: disabled=True
+    with Progress(console=console, disable=True) as progress:
+        pass
+    
+    output = console.file.getvalue()
+    assert output == "", f"Expected no output when disabled, got {repr(output)}"
+
+    # Reset buffer
+    console.file.truncate(0)
+    console.file.seek(0)
+
+    # Case 2: disabled=False (should still output blank line on non-interactive console)
+    with Progress(console=console, disable=False) as progress:
+        pass
+    
+    output = console.file.getvalue()
+    # The Live.stop() might not print anything, but the stop() method in Progress does.
+    # Let's check if it prints a newline.
+    assert output == "\n", f"Expected newline when enabled on non-interactive console, got {repr(output)}"
+
+if __name__ == "__main__":
+    test_disabled_progress_no_blank_line()
+    print("Test passed!")

Test output

show
.......................................                                  [100%]
39 passed in 0.53s