diff options
-rw-r--r-- | cmd2/cmd2.py | 33 | ||||
-rw-r--r-- | cmd2/utils.py | 43 |
2 files changed, 39 insertions, 37 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 2ad38f23..a621e459 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -303,21 +303,6 @@ class EmptyStatement(Exception): DisabledCommand = namedtuple('DisabledCommand', ['command_function', 'help_function']) -class RedirectionSavedState(object): - # Created by each command to store information about their redirection - def __init__(self): - # Tells if the command is redirecting - self.redirecting = False - - # If the command created a process to pipe to, then then is its reader - self.pipe_proc_reader = None - - # Used to restore values after the command ends - self.saved_self_stdout = None - self.saved_sys_stdout = None - self.saved_pipe_proc_reader = None - - class Cmd(cmd.Cmd): """An easy but powerful framework for writing line-oriented command interpreters. @@ -433,12 +418,11 @@ class Cmd(cmd.Cmd): # Used load command to store the current script dir as a LIFO queue to support _relative_load command self._script_dir = [] - # A flag used to protect critical sections in the main thread from stopping due to a KeyboardInterrupt + # Context manager used to protect critical sections in the main thread from stopping due to a KeyboardInterrupt self.sigint_protection = utils.ContextFlag() # If the current command created a process to pipe to, then this will be a ProcReader object. - # Otherwise the value will be None. This member is used to know when a pipe process can be killed - # and also waited upon. + # Otherwise it will be None. Its used to know when a pipe process can be killed and/or waited upon. self.cur_pipe_proc_reader = None # Used by complete() for readline tab completion @@ -1724,7 +1708,7 @@ class Cmd(cmd.Cmd): # Keep track of whether or not we were already redirecting before this command already_redirecting = self.redirecting - # This will be a RedirectionSavedState object for the command + # This will be a utils.RedirectionSavedState object for the command saved_state = None try: @@ -1900,11 +1884,11 @@ class Cmd(cmd.Cmd): raise EmptyStatement() return statement - def _redirect_output(self, statement: Statement) -> Tuple[bool, RedirectionSavedState]: + def _redirect_output(self, statement: Statement) -> Tuple[bool, utils.RedirectionSavedState]: """Handles output redirection for >, >>, and |. :param statement: a parsed statement from the user - :return: A bool telling if an error occurred and a RedirectionSavedState object + :return: A bool telling if an error occurred and a utils.RedirectionSavedState object """ import io import subprocess @@ -1912,10 +1896,7 @@ class Cmd(cmd.Cmd): redir_error = False # Initialize the saved state - saved_state = RedirectionSavedState() - saved_state.saved_self_stdout = self.stdout - saved_state.saved_sys_stdout = sys.stdout - saved_state.saved_pipe_proc_reader = self.cur_pipe_proc_reader + saved_state = utils.RedirectionSavedState(self.stdout, sys.stdout, self.cur_pipe_proc_reader) if not self.allow_redirection: return redir_error, saved_state @@ -1990,7 +1971,7 @@ class Cmd(cmd.Cmd): return redir_error, saved_state - def _restore_output(self, statement: Statement, saved_state: RedirectionSavedState) -> None: + def _restore_output(self, statement: Statement, saved_state: utils.RedirectionSavedState) -> None: """Handles restoring state after output redirection as well as the actual pipe operation if present. diff --git a/cmd2/utils.py b/cmd2/utils.py index 4172e362..74f83c64 100644 --- a/cmd2/utils.py +++ b/cmd2/utils.py @@ -342,12 +342,14 @@ class StdSim(object): def clear(self) -> None: """Clear the internal contents""" - self.buffer.byte_buf = b'' + self.buffer.byte_buf = bytearray() - @staticmethod - def isatty() -> bool: - """StdSim will never be considered an interactive stream""" - return False + def isatty(self) -> bool: + """StdSim only be considered an interactive stream if `echo` is True and `inner_stream` is a tty.""" + if self.echo: + return self.inner_stream.isatty() + else: + return False def __getattr__(self, item: str): if item in self.__dict__: @@ -469,24 +471,43 @@ class ProcReader(object): class ContextFlag(object): - """ - A flag value that is used in a with statement. + """A context manager which is also used as a boolean flag value within the default sigint handler. + Its main use is as a flag to prevent the SIGINT handler in cmd2 from raising a KeyboardInterrupt while a critical code section has set the flag to True. Because signal handling is always done on the main thread, this class is not thread-safe since there is no need. """ - def __init__(self): + def __init__(self) -> None: # When this flag has a positive value, it is considered set. # When it is 0, it is not set. It should never go below 0. self.__count = 0 - def __bool__(self): + def __bool__(self) -> bool: return self.__count > 0 - def __enter__(self): + def __enter__(self) -> None: self.__count += 1 - def __exit__(self, *args): + def __exit__(self, *args) -> None: self.__count -= 1 if self.__count < 0: raise ValueError("count has gone below 0") + + +class RedirectionSavedState(object): + """Created by each command to store information about their redirection.""" + + def __init__(self, self_stdout: Union[StdSim, BinaryIO, TextIO], sys_stdout: Union[StdSim, BinaryIO, TextIO], + pipe_proc_reader: Optional[ProcReader]) -> None: + # Used to restore values after the command ends + self.saved_self_stdout = self_stdout + self.saved_sys_stdout = sys_stdout + self.saved_pipe_proc_reader = pipe_proc_reader + + # Tells if the command is redirecting + self.redirecting = False + + # If the command created a process to pipe to, then then is its reader + self.pipe_proc_reader = None + + |