Skip to content

Commit ee44321

Browse files
committed
Added unit tests and updated change log.
1 parent 851de4b commit ee44321

File tree

4 files changed

+45
-11
lines changed

4 files changed

+45
-11
lines changed

CHANGELOG.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
- Added `Cmd.macro_arg_complete()` which tab completes arguments to a macro. Its default
1616
behavior is to perform path completion, but it can be overridden as needed.
1717

18-
- Bug Fixes
19-
- No longer redirecting `sys.stdout` if it's a different stream than `self.stdout`. This
20-
fixes issue where we overwrote an application's `sys.stdout` while redirecting.
18+
- All print methods (`poutput()`, `perror()`, `ppaged()`, etc.) have the ability to print Rich
19+
objects.
20+
21+
- Bug Fixes
22+
- No longer redirecting `sys.stdout` if it's a different stream than `self.stdout`. This fixes
23+
issue where we overwrote an application's `sys.stdout` while redirecting.
2124

2225
## 2.7.0 (June 30, 2025)
2326

cmd2/cmd2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1503,7 +1503,7 @@ def ppaged(
15031503
can_block = not (self._redirecting or self.in_pyscript() or self.in_script())
15041504

15051505
# Check if we are outputting to a pager.
1506-
if functional_terminal and can_block: # pragma: no cover
1506+
if functional_terminal and can_block:
15071507
prepared_objects = rich_utils.prepare_objects_for_rich_print(*objects)
15081508

15091509
# Chopping overrides soft_wrap

cmd2/rich_utils.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,7 @@ def __init__(self, file: IO[str]) -> None:
156156

157157
def on_broken_pipe(self) -> None:
158158
"""Override which raises BrokenPipeError instead of SystemExit."""
159-
import contextlib
160-
161-
with contextlib.suppress(SystemExit):
162-
super().on_broken_pipe()
163-
159+
self.quiet = True
164160
raise BrokenPipeError
165161

166162

tests/test_cmd2.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2058,6 +2058,19 @@ def test_poutput_ansi_terminal(outsim_app) -> None:
20582058
assert out == expected
20592059

20602060

2061+
def test_broken_pipe_error(outsim_app, monkeypatch, capsys):
2062+
write_mock = mock.MagicMock()
2063+
write_mock.side_effect = BrokenPipeError
2064+
monkeypatch.setattr("cmd2.utils.StdSim.write", write_mock)
2065+
2066+
outsim_app.broken_pipe_warning = "The pipe broke"
2067+
outsim_app.poutput("My test string")
2068+
2069+
out, err = capsys.readouterr()
2070+
assert not out
2071+
assert outsim_app.broken_pipe_warning in err
2072+
2073+
20612074
# These are invalid names for aliases and macros
20622075
invalid_command_name = [
20632076
'""', # Blank name
@@ -2519,8 +2532,30 @@ def test_pexcept_not_exception(base_app, capsys) -> None:
25192532
assert err.startswith("\x1b[91mEXCEPTION of type 'bool' occurred with message: False")
25202533

25212534

2522-
def test_ppaged(outsim_app) -> None:
2523-
"""ppaged() will just call poutput() since a pager won't run while testing."""
2535+
def test_ppaged_with_pager(outsim_app, monkeypatch) -> None:
2536+
"""Force ppaged() to run the pager by mocking an actual terminal state."""
2537+
2538+
# Make it look like we're in a terminal
2539+
stdin_mock = mock.MagicMock()
2540+
stdin_mock.isatty.return_value = True
2541+
monkeypatch.setattr(outsim_app, "stdin", stdin_mock)
2542+
2543+
stdout_mock = mock.MagicMock()
2544+
stdout_mock.isatty.return_value = True
2545+
monkeypatch.setattr(outsim_app, "stdout", stdout_mock)
2546+
2547+
if not sys.platform.startswith('win'):
2548+
os.environ.setdefault('TERM', 'simulated')
2549+
2550+
# This will force ppaged to call Popen to run a pager
2551+
popen_mock = mock.MagicMock(name='Popen')
2552+
monkeypatch.setattr("subprocess.Popen", popen_mock)
2553+
outsim_app.ppaged("Test", chop=True)
2554+
popen_mock.assert_called_once()
2555+
2556+
2557+
def test_ppaged_no_pager(outsim_app) -> None:
2558+
"""Since we're not in a fully-functional terminal, ppaged() will just call poutput()."""
25242559
msg = 'testing...'
25252560
end = '\n'
25262561
outsim_app.ppaged(msg)

0 commit comments

Comments
 (0)