Skip to content

Commit 9b5e154

Browse files
committed
Only redirect sys.stdout when it's the same as self.stdout.
1 parent 076d0e0 commit 9b5e154

File tree

3 files changed

+36
-28
lines changed

3 files changed

+36
-28
lines changed

cmd2/cmd2.py

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
Easy transcript-based testing of applications (see examples/example.py)
1414
Bash-style ``select`` available
1515
16-
Note that redirection with > and | will only work if `self.poutput()`
17-
is used in place of `print`.
16+
Note, if self.stdout is different than sys.stdout, then redirection with > and |
17+
will only work if `self.poutput()` is used in place of `print`.
1818
1919
- Catherine Devlin, Jan 03 2008 - catherinedevlin.blogspot.com
2020
@@ -200,8 +200,6 @@ def __init__(self) -> None:
200200
self.readline_settings = _SavedReadlineSettings()
201201
self.readline_module: Optional[ModuleType] = None
202202
self.history: list[str] = []
203-
self.sys_stdout: Optional[TextIO] = None
204-
self.sys_stdin: Optional[TextIO] = None
205203

206204

207205
# Contains data about a disabled command which is used to restore its original functions when the command is enabled
@@ -2854,9 +2852,12 @@ def _redirect_output(self, statement: Statement) -> utils.RedirectionSavedState:
28542852
"""
28552853
import subprocess
28562854

2855+
# Only redirect sys.stdout if it's the same as self.stdout
2856+
stdouts_match = self.stdout == sys.stdout
2857+
28572858
# Initialize the redirection saved state
28582859
redir_saved_state = utils.RedirectionSavedState(
2859-
cast(TextIO, self.stdout), sys.stdout, self._cur_pipe_proc_reader, self._redirecting
2860+
cast(TextIO, self.stdout), stdouts_match, self._cur_pipe_proc_reader, self._redirecting
28602861
)
28612862

28622863
# The ProcReader for this command
@@ -2912,7 +2913,10 @@ def _redirect_output(self, statement: Statement) -> utils.RedirectionSavedState:
29122913
raise RedirectionError(f'Pipe process exited with code {proc.returncode} before command could run')
29132914
redir_saved_state.redirecting = True # type: ignore[unreachable]
29142915
cmd_pipe_proc_reader = utils.ProcReader(proc, cast(TextIO, self.stdout), sys.stderr)
2915-
sys.stdout = self.stdout = new_stdout
2916+
2917+
self.stdout = new_stdout
2918+
if stdouts_match:
2919+
sys.stdout = self.stdout
29162920

29172921
elif statement.output:
29182922
if statement.output_to:
@@ -2926,7 +2930,10 @@ def _redirect_output(self, statement: Statement) -> utils.RedirectionSavedState:
29262930
raise RedirectionError('Failed to redirect output') from ex
29272931

29282932
redir_saved_state.redirecting = True
2929-
sys.stdout = self.stdout = new_stdout
2933+
2934+
self.stdout = new_stdout
2935+
if stdouts_match:
2936+
sys.stdout = self.stdout
29302937

29312938
else:
29322939
# Redirecting to a paste buffer
@@ -2944,7 +2951,10 @@ def _redirect_output(self, statement: Statement) -> utils.RedirectionSavedState:
29442951
# create a temporary file to store output
29452952
new_stdout = cast(TextIO, tempfile.TemporaryFile(mode="w+")) # noqa: SIM115
29462953
redir_saved_state.redirecting = True
2947-
sys.stdout = self.stdout = new_stdout
2954+
2955+
self.stdout = new_stdout
2956+
if stdouts_match:
2957+
sys.stdout = self.stdout
29482958

29492959
if statement.output == constants.REDIRECTION_APPEND:
29502960
self.stdout.write(current_paste_buffer)
@@ -2974,7 +2984,8 @@ def _restore_output(self, statement: Statement, saved_redir_state: utils.Redirec
29742984

29752985
# Restore the stdout values
29762986
self.stdout = cast(TextIO, saved_redir_state.saved_self_stdout)
2977-
sys.stdout = cast(TextIO, saved_redir_state.saved_sys_stdout)
2987+
if saved_redir_state.stdouts_match:
2988+
sys.stdout = self.stdout
29782989

29792990
# Check if we need to wait for the process being piped to
29802991
if self._cur_pipe_proc_reader is not None:
@@ -4449,22 +4460,13 @@ def _set_up_py_shell_env(self, interp: InteractiveConsole) -> _SavedCmd2Env:
44494460
# Set up sys module for the Python console
44504461
self._reset_py_display()
44514462

4452-
cmd2_env.sys_stdout = sys.stdout
4453-
sys.stdout = self.stdout # type: ignore[assignment]
4454-
4455-
cmd2_env.sys_stdin = sys.stdin
4456-
sys.stdin = self.stdin # type: ignore[assignment]
4457-
44584463
return cmd2_env
44594464

44604465
def _restore_cmd2_env(self, cmd2_env: _SavedCmd2Env) -> None:
44614466
"""Restore cmd2 environment after exiting an interactive Python shell.
44624467
44634468
:param cmd2_env: the environment settings to restore
44644469
"""
4465-
sys.stdout = cmd2_env.sys_stdout # type: ignore[assignment]
4466-
sys.stdin = cmd2_env.sys_stdin # type: ignore[assignment]
4467-
44684470
# Set up readline for cmd2
44694471
if rl_type != RlType.NONE:
44704472
# Save py's history

cmd2/py_bridge.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
"""
55

66
import sys
7-
from contextlib import (
8-
redirect_stderr,
9-
redirect_stdout,
10-
)
7+
from contextlib import redirect_stderr
118
from typing import (
129
IO,
1310
TYPE_CHECKING,
@@ -113,6 +110,8 @@ def __call__(self, command: str, *, echo: Optional[bool] = None) -> CommandResul
113110
if echo is None:
114111
echo = self.cmd_echo
115112

113+
stdouts_match = self._cmd2_app.stdout == sys.stdout
114+
116115
# This will be used to capture _cmd2_app.stdout and sys.stdout
117116
copy_cmd_stdout = StdSim(cast(Union[TextIO, StdSim], self._cmd2_app.stdout), echo=echo)
118117

@@ -126,8 +125,12 @@ def __call__(self, command: str, *, echo: Optional[bool] = None) -> CommandResul
126125

127126
stop = False
128127
try:
129-
self._cmd2_app.stdout = cast(TextIO, copy_cmd_stdout)
130-
with redirect_stdout(cast(IO[str], copy_cmd_stdout)), redirect_stderr(cast(IO[str], copy_stderr)):
128+
with self._cmd2_app.sigint_protection:
129+
self._cmd2_app.stdout = cast(TextIO, copy_cmd_stdout)
130+
if stdouts_match:
131+
sys.stdout = self._cmd2_app.stdout
132+
133+
with redirect_stderr(cast(IO[str], copy_stderr)):
131134
stop = self._cmd2_app.onecmd_plus_hooks(
132135
command,
133136
add_to_history=self._add_to_history,
@@ -136,6 +139,9 @@ def __call__(self, command: str, *, echo: Optional[bool] = None) -> CommandResul
136139
finally:
137140
with self._cmd2_app.sigint_protection:
138141
self._cmd2_app.stdout = cast(IO[str], copy_cmd_stdout.inner_stream)
142+
if stdouts_match:
143+
sys.stdout = self._cmd2_app.stdout
144+
139145
self.stop = stop or self.stop
140146

141147
# Save the result

cmd2/utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -683,23 +683,23 @@ class RedirectionSavedState:
683683
def __init__(
684684
self,
685685
self_stdout: Union[StdSim, TextIO],
686-
sys_stdout: Union[StdSim, TextIO],
686+
stdouts_match: bool,
687687
pipe_proc_reader: Optional[ProcReader],
688688
saved_redirecting: bool,
689689
) -> None:
690690
"""RedirectionSavedState initializer.
691691
692692
:param self_stdout: saved value of Cmd.stdout
693-
:param sys_stdout: saved value of sys.stdout
693+
:param stdouts_match: True if Cmd.stdout is equal to sys.stdout
694694
:param pipe_proc_reader: saved value of Cmd._cur_pipe_proc_reader
695695
:param saved_redirecting: saved value of Cmd._redirecting.
696696
"""
697697
# Tells if command is redirecting
698698
self.redirecting = False
699699

700-
# Used to restore values after redirection ends
700+
# Used to restore stdout values after redirection ends
701701
self.saved_self_stdout = self_stdout
702-
self.saved_sys_stdout = sys_stdout
702+
self.stdouts_match = stdouts_match
703703

704704
# Used to restore values after command ends regardless of whether the command redirected
705705
self.saved_pipe_proc_reader = pipe_proc_reader

0 commit comments

Comments
 (0)