diff options
| author | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2021-01-29 20:07:46 -0500 |
|---|---|---|
| committer | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2021-01-29 20:07:46 -0500 |
| commit | 434a01f44e7d2302b4deef8f2e8069cbc26df560 (patch) | |
| tree | cb3d5425668954fdd92989121ab53741c56908f8 /cmd2 | |
| parent | 82fe1d473ca2fe0278568036659fa78cb3c17f78 (diff) | |
| parent | cd377071cd122bc92a829322e00ae43fd5a5c254 (diff) | |
| download | cmd2-git-434a01f44e7d2302b4deef8f2e8069cbc26df560.tar.gz | |
Merge branch 'master' into 2.0
Diffstat (limited to 'cmd2')
| -rw-r--r-- | cmd2/cmd2.py | 8 | ||||
| -rw-r--r-- | cmd2/rl_utils.py | 4 | ||||
| -rw-r--r-- | cmd2/table_creator.py | 48 |
3 files changed, 40 insertions, 20 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index ef82c196..27746323 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -4049,7 +4049,13 @@ class Cmd(cmd.Cmd): self.history.clear() if self.persistent_history_file: - os.remove(self.persistent_history_file) + try: + os.remove(self.persistent_history_file) + except FileNotFoundError: + pass + except OSError as ex: + self.pexcept("Error removing history file '{}': {}".format(self.persistent_history_file, ex)) + return if rl_type != RlType.NONE: readline.clear_history() diff --git a/cmd2/rl_utils.py b/cmd2/rl_utils.py index e435c3f5..ca75fd8a 100644 --- a/cmd2/rl_utils.py +++ b/cmd2/rl_utils.py @@ -37,8 +37,8 @@ vt100_support = False # Explanation for why readline wasn't loaded _rl_warn_reason = '' -# The order of this check matters since importing pyreadline will also show readline in the modules list -if 'pyreadline' in sys.modules: +# The order of this check matters since importing pyreadline/pyreadline3 will also show readline in the modules list +if 'pyreadline' in sys.modules or 'pyreadline3' in sys.modules: rl_type = RlType.PYREADLINE from ctypes import byref diff --git a/cmd2/table_creator.py b/cmd2/table_creator.py index 419f12b4..5d6b444d 100644 --- a/cmd2/table_creator.py +++ b/cmd2/table_creator.py @@ -83,7 +83,7 @@ class Column: :param header: label for column header :param width: display width of column. This does not account for any borders or padding which may be added (e.g pre_line, inter_cell, and post_line). Header and data text wrap within - this width using word-based wrapping (defaults to width of header or 1 if header is blank) + this width using word-based wrapping (defaults to actual width of header or 1 if header is blank) :param header_horiz_align: horizontal alignment of header cells (defaults to left) :param header_vert_align: vertical alignment of header cells (defaults to bottom) :param data_horiz_align: horizontal alignment of data cells (defaults to left) @@ -95,12 +95,7 @@ class Column: """ self.header = header - if width is None: - # Use the width of the widest line in the header or 1 if the header has no width - line_widths = [ansi.style_aware_wcswidth(line) for line in self.header.splitlines()] - line_widths.append(1) - self.width = max(line_widths) - elif width < 1: + if width is not None and width < 1: raise ValueError("Column width cannot be less than 1") else: self.width = width @@ -137,12 +132,28 @@ class TableCreator: :param cols: column definitions for this table :param tab_width: all tabs will be replaced with this many spaces. If a row's fill_char is a tab, then it will be converted to one space. + :raises: ValueError if tab_width is less than 1 """ + if tab_width < 1: + raise ValueError("Tab width cannot be less than 1") + self.cols = copy.copy(cols) self.tab_width = tab_width + for col in self.cols: + # Replace tabs before calculating width of header strings + col.header = col.header.replace('\t', SPACE * self.tab_width) + + # For headers with the width not yet set, use the width of the + # widest line in the header or 1 if the header has no width + if col.width is None: + line_widths = [ansi.style_aware_wcswidth(line) for line in col.header.splitlines()] + line_widths.append(1) + col.width = max(line_widths) + @staticmethod - def _wrap_long_word(word: str, max_width: int, max_lines: Union[int, float], is_last_word: bool) -> Tuple[str, int, int]: + def _wrap_long_word(word: str, max_width: int, max_lines: Union[int, float], + is_last_word: bool) -> Tuple[str, int, int]: """ Used by _wrap_text() to wrap a long word over multiple lines @@ -351,14 +362,16 @@ class TableCreator: # Stop line loop if we've written to max_lines if total_lines == max_lines: - # If this isn't the last data line and there is space left on the final wrapped line, then add an ellipsis + # If this isn't the last data line and there is space + # left on the final wrapped line, then add an ellipsis if data_line_index < len(data_str_lines) - 1 and cur_line_width < max_width: wrapped_buf.write(constants.HORIZONTAL_ELLIPSIS) break return wrapped_buf.getvalue() - def _generate_cell_lines(self, cell_data: Any, is_header: bool, col: Column, fill_char: str) -> Tuple[Deque[str], int]: + def _generate_cell_lines(self, cell_data: Any, is_header: bool, + col: Column, fill_char: str) -> Tuple[Deque[str], int]: """ Generate the lines of a table cell @@ -398,14 +411,14 @@ class TableCreator: :param row_data: If this is None then a header row is generated. Otherwise data should have an entry for each column in the row. (Defaults to None) - :param fill_char: character that fills remaining space in a cell. Defaults to space. If this is a tab, then it will - be converted to one space. (Cannot be a line breaking character) + :param fill_char: character that fills remaining space in a cell. Defaults to space. If this is a tab, + then it will be converted to one space. (Cannot be a line breaking character) :param pre_line: string to print before each line of a row. This can be used for a left row border and padding before the first cell's text. (Defaults to blank) :param inter_cell: string to print where two cells meet. This can be used for a border between cells and padding between it and the 2 cells' text. (Defaults to 2 spaces) - :param post_line: string to print after each line of a row. This can be used for padding after the last cell's text - and a right row border. (Defaults to blank) + :param post_line: string to print after each line of a row. This can be used for padding after + the last cell's text and a right row border. (Defaults to blank) :return: row string :raises: ValueError if data isn't the same length as self.cols :raises: TypeError if fill_char is more than one character (not including ANSI style sequences) @@ -608,7 +621,8 @@ class SimpleTable(TableCreator): :param table_data: Data with an entry for each data row of the table. Each entry should have data for each column in the row. :param include_header: If True, then a header will be included at top of table. (Defaults to True) - :param row_spacing: A number 0 or greater specifying how many blank lines to place between each row (Defaults to 1) + :param row_spacing: A number 0 or greater specifying how many blank lines to place between + each row (Defaults to 1) :raises: ValueError if row_spacing is less than 0 """ if row_spacing < 0: @@ -820,8 +834,8 @@ class BorderedTable(TableCreator): class AlternatingTable(BorderedTable): """ - Implementation of BorderedTable which uses background colors to distinguish between rows instead of row border lines. - This class can be used to create the whole table at once or one row at a time. + Implementation of BorderedTable which uses background colors to distinguish between rows instead of row border + lines. This class can be used to create the whole table at once or one row at a time. """ def __init__(self, cols: Sequence[Column], *, tab_width: int = 4, column_borders: bool = True, padding: int = 1, bg_odd: Optional[ansi.bg] = None, bg_even: Optional[ansi.bg] = ansi.bg.bright_black) -> None: |
