From a0bed428a45b161ca2cfaaf7a776dd1d85896175 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Wed, 6 Nov 2024 12:11:16 -0500 Subject: [PATCH] Fixed ZeroDivisionError in async_alert() when shutil.get_terminal_size().columns returned 0. --- CHANGELOG.md | 5 +++++ cmd2/cmd2.py | 5 ++++- cmd2/constants.py | 3 +++ cmd2/utils.py | 3 ++- tests/test_utils.py | 5 ++++- 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b85424b68..af7c24307 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.5.4 (TBD) +* Bug Fixes + * Fixed `ZeroDivisionError` in `async_alert()` when `shutil.get_terminal_size().columns` + returned 0. + ## 2.5.3 (November 5, 2024) * Enhancements * Changed `CommandSet._cmd` to a read-only property which never returns `None` because it diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index b839205bf..cd3e8bc1c 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -5335,9 +5335,12 @@ def async_alert(self, alert_msg: str, new_prompt: Optional[str] = None) -> None: if update_terminal: import shutil + # Prior to Python 3.11 this can return 0, so use a fallback if needed. + terminal_columns = shutil.get_terminal_size().columns or constants.DEFAULT_TERMINAL_WIDTH + # Print a string which replaces the onscreen prompt and input lines with the alert. terminal_str = ansi.async_alert_str( - terminal_columns=shutil.get_terminal_size().columns, + terminal_columns=terminal_columns, prompt=rl_get_display_prompt(), line=readline.get_line_buffer(), cursor_offset=rl_get_point(), diff --git a/cmd2/constants.py b/cmd2/constants.py index 9f29be869..ebac5da95 100644 --- a/cmd2/constants.py +++ b/cmd2/constants.py @@ -57,3 +57,6 @@ # custom attributes added to argparse Namespaces NS_ATTR_SUBCMD_HANDLER = '__subcmd_handler__' + +# For cases prior to Python 3.11 when shutil.get_terminal_size().columns can return 0. +DEFAULT_TERMINAL_WIDTH = 80 diff --git a/cmd2/utils.py b/cmd2/utils.py index f718d5f14..bd4164ab4 100644 --- a/cmd2/utils.py +++ b/cmd2/utils.py @@ -874,7 +874,8 @@ def align_text( ) if width is None: - width = shutil.get_terminal_size().columns + # Prior to Python 3.11 this can return 0, so use a fallback if needed. + width = shutil.get_terminal_size().columns or constants.DEFAULT_TERMINAL_WIDTH if width < 1: raise ValueError("width must be at least 1") diff --git a/tests/test_utils.py b/tests/test_utils.py index 030fa3044..a173f7f45 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -17,6 +17,7 @@ import cmd2.utils as cu from cmd2 import ( ansi, + constants, ) from cmd2.constants import ( HORIZONTAL_ELLIPSIS, @@ -624,7 +625,9 @@ def test_align_text_term_width(): text = 'foo' fill_char = ' ' - term_width = shutil.get_terminal_size().columns + # Prior to Python 3.11 this can return 0, so use a fallback, so + # use the same fallback that cu.align_text() does if needed. + term_width = shutil.get_terminal_size().columns or constants.DEFAULT_TERMINAL_WIDTH expected_fill = (term_width - ansi.style_aware_wcswidth(text)) * fill_char aligned = cu.align_text(text, cu.TextAlignment.LEFT, fill_char=fill_char)