diff options
-rw-r--r-- | cmd2/cmd2.py | 40 | ||||
-rw-r--r-- | docs/unfreefeatures.rst | 4 | ||||
-rwxr-xr-x | examples/async_printing.py | 16 |
3 files changed, 30 insertions, 30 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index bf1e01df..ba8e47ed 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -530,7 +530,7 @@ class Cmd(cmd.Cmd): # This lock should be acquired before doing any asynchronous changes to the terminal to # ensure the updates to the terminal don't interfere with the input being typed. It can be # acquired any time there is a readline prompt on screen. - self._terminal_lock = threading.RLock() + self.terminal_lock = threading.RLock() # ----- Methods related to presenting output to the user ----- @@ -2085,10 +2085,10 @@ class Cmd(cmd.Cmd): if self.use_rawinput: try: if sys.stdin.isatty(): - # Wrap in try since _terminal_lock may not be locked when this function is called from unit tests + # Wrap in try since terminal_lock may not be locked when this function is called from unit tests try: # A prompt is about to be drawn. Allow asynchronous changes to the terminal. - self._terminal_lock.release() + self.terminal_lock.release() except RuntimeError: pass @@ -2104,7 +2104,7 @@ class Cmd(cmd.Cmd): finally: if sys.stdin.isatty(): # The prompt is gone. Do not allow asynchronous changes to the terminal. - self._terminal_lock.acquire() + self.terminal_lock.acquire() else: if self.stdin.isatty(): # on a tty, print the prompt first, then read the line @@ -3237,25 +3237,25 @@ Script should contain one command per line, just like command would be typed in return terminal_str - def _async_alert(self, alert_msg: str, new_prompt: Optional[str] = None) -> None: + def async_alert(self, alert_msg: str, new_prompt: Optional[str] = None) -> None: """ Used to display an important message to the user while they are at the prompt in between commands. To the user it appears as if an alert message is printed above the prompt and their current input text and cursor location is left alone. - IMPORTANT: Do not call this unless you have acquired self._terminal_lock + IMPORTANT: Do not call this unless you have acquired self.terminal_lock first, which ensures a prompt is onscreen :param alert_msg: the message to display to the user :param new_prompt: if you also want to change the prompt that is displayed, then include it here see async_update_prompt() docstring for guidance on updating a prompt - :raises RuntimeError if called while another thread holds _terminal_lock + :raises RuntimeError if called while another thread holds terminal_lock """ if not (vt100_support and self.use_rawinput): return - # Sanity check that can't fail if self._terminal_lock was acquired before calling this function - if self._terminal_lock.acquire(blocking=False): + # Sanity check that can't fail if self.terminal_lock was acquired before calling this function + if self.terminal_lock.acquire(blocking=False): # Generate a string to clear the prompt and input lines and replace with the alert terminal_str = self._clear_input_lines_str() @@ -3275,12 +3275,12 @@ Script should contain one command per line, just like command would be typed in # Redraw the prompt and input lines rl_force_redisplay() - self._terminal_lock.release() + self.terminal_lock.release() else: - raise RuntimeError("another thread holds _terminal_lock") + raise RuntimeError("another thread holds terminal_lock") - def _async_update_prompt(self, new_prompt: str) -> None: + def async_update_prompt(self, new_prompt: str) -> None: """ Updates the prompt while the user is still typing at it. This is good for alerting the user to system changes dynamically in between commands. For instance you could alter the color of the prompt to indicate @@ -3288,17 +3288,17 @@ Script should contain one command per line, just like command would be typed in it is best to keep the prompt the same width as what's on screen. Otherwise the user's input text will be shifted and the update will not be seamless. - IMPORTANT: Do not call this unless you have acquired self._terminal_lock + IMPORTANT: Do not call this unless you have acquired self.terminal_lock first, which ensures a prompt is onscreen :param new_prompt: what to change the prompt to - :raises RuntimeError if called while another thread holds _terminal_lock + :raises RuntimeError if called while another thread holds terminal_lock """ if not (vt100_support and self.use_rawinput): return - # Sanity check that can't fail if self._terminal_lock was acquired before calling this function - if self._terminal_lock.acquire(blocking=False): + # Sanity check that can't fail if self.terminal_lock was acquired before calling this function + if self.terminal_lock.acquire(blocking=False): # Generate a string to clear the prompt and input lines terminal_str = self._clear_input_lines_str() @@ -3316,10 +3316,10 @@ Script should contain one command per line, just like command would be typed in # Redraw the prompt and input lines rl_force_redisplay() - self._terminal_lock.release() + self.terminal_lock.release() else: - raise RuntimeError("another thread holds _terminal_lock") + raise RuntimeError("another thread holds terminal_lock") @staticmethod def set_window_title(title: str) -> None: @@ -3368,7 +3368,7 @@ Script should contain one command per line, just like command would be typed in signal.signal(signal.SIGINT, self.sigint_handler) # Grab terminal lock before the prompt has been drawn by readline - self._terminal_lock.acquire() + self.terminal_lock.acquire() # Always run the preloop first for func in self._preloop_hooks: @@ -3397,7 +3397,7 @@ Script should contain one command per line, just like command would be typed in # Release terminal lock now that postloop code should have stopped any terminal updater threads # This will also zero the lock count in case cmdloop() is called again - self._terminal_lock.release() + self.terminal_lock.release() # Restore the original signal handler signal.signal(signal.SIGINT, original_sigint_handler) diff --git a/docs/unfreefeatures.rst b/docs/unfreefeatures.rst index fd8b0a6d..1b8adb8d 100644 --- a/docs/unfreefeatures.rst +++ b/docs/unfreefeatures.rst @@ -198,12 +198,12 @@ the command line. This means the feedback is provided to the user when they are the prompt. To use this functionality, the application must be running in any terminal that supports VT100 control characters and readline. Linux, Mac, and Windows 10 and greater all support these. -_async_alert() +async_alert() Used to display an important message to the user while they are at the prompt in between commands. To the user it appears as if an alert message is printed above the prompt and their current input text and cursor location is left alone. -_async_update_prompt() +async_update_prompt() Updates the prompt while the user is still typing at it. This is good for alerting the user to system changes dynamically in between commands. For instance you could alter the color of the prompt to indicate a system status or increase a counter to report an event. diff --git a/examples/async_printing.py b/examples/async_printing.py index 23147865..feda24c0 100755 --- a/examples/async_printing.py +++ b/examples/async_printing.py @@ -45,7 +45,7 @@ class AlerterApp(cmd2.Cmd): def _preloop_hook(self) -> None: """ Start the alerter thread """ - # This runs after cmdloop() acquires self._terminal_lock, which will be locked until the prompt appears. + # This runs after cmdloop() acquires self.terminal_lock, which will be locked until the prompt appears. # Therefore this is the best place to start the alerter thread since there is no risk of it alerting # before the prompt is displayed. You can also start it via a command if its not something that should # be running during the entire application. See do_start_alerts(). @@ -57,7 +57,7 @@ class AlerterApp(cmd2.Cmd): def _postloop_hook(self) -> None: """ Stops the alerter thread """ - # After this function returns, cmdloop() releases self._terminal_lock which could make the alerter + # After this function returns, cmdloop() releases self.terminal_lock which could make the alerter # thread think the prompt is on screen. Therefore this is the best place to stop the alerter thread. # You can also stop it via a command. See do_stop_alerts(). self._stop_thread = True @@ -166,9 +166,9 @@ class AlerterApp(cmd2.Cmd): self._next_alert_time = 0 while not self._stop_thread: - # Always acquire _terminal_lock before printing alerts or updating the prompt + # Always acquire terminal_lock before printing alerts or updating the prompt # To keep the app responsive, do not block on this call - if self._terminal_lock.acquire(blocking=False): + if self.terminal_lock.acquire(blocking=False): # Get any alerts that need to be printed alert_str = self._generate_alert_str() @@ -178,15 +178,15 @@ class AlerterApp(cmd2.Cmd): # Check if we have alerts to print if alert_str: - # new_prompt is an optional parameter to _async_alert() - self._async_alert(alert_str, new_prompt) + # new_prompt is an optional parameter to async_alert() + self.async_alert(alert_str, new_prompt) # No alerts needed to be printed, check if the prompt changed elif new_prompt != self.prompt: - self._async_update_prompt(new_prompt) + self.async_update_prompt(new_prompt) # Don't forget to release the lock - self._terminal_lock.release() + self.terminal_lock.release() time.sleep(0.5) |