Repository: python-cmd2/cmd2
Pull request #1050 (2021-01-29 16:41:12)

Miscellaneous changes for the next release (1.4.1)
- Added more validation to TableCreator
- Printing error when OSError other than FileNotFoundError occurs when deleting persistent history file with history --clear command.
- Updated documentation.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9bb30141..582a4d7a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
 * Enhancements
     * Added `silent_startup_script` option to `cmd2.Cmd.__init__()`. If `True`, then the startup script's
       output will be suppressed. Anything written to stderr will still display.
+    * cmd2 now uses pyreadline3 when running Python 3.8 or greater on Windows  
 
 ## 1.4.0 (November 11, 2020)
 * Bug Fixes
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index ab72f1a6..51670235 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -3993,6 +3993,9 @@ class Cmd(cmd.Cmd):
                     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/table_creator.py b/cmd2/table_creator.py
index 2579f3c6..5d6b444d 100644
--- a/cmd2/table_creator.py
+++ b/cmd2/table_creator.py
@@ -132,7 +132,11 @@ 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
 
diff --git a/docs/features/startup_commands.rst b/docs/features/startup_commands.rst
index aaaf7722..f105054b 100644
--- a/docs/features/startup_commands.rst
+++ b/docs/features/startup_commands.rst
@@ -64,3 +64,12 @@ like so::
 This text file should contain a :ref:`Command Script
 <features/scripting:Command Scripts>`. See the AliasStartup_ example for a
 demonstration.
+
+You can silence a startup script's output by setting ``silent_startup_script``
+to True::
+
+    cmd2.Cmd.__init__(self, startup_script='.cmd2rc', silent_startup_script=True)
+
+Anything written to stderr will still print. Additionally, a startup script
+cannot be silenced if ``allow_redirection`` is False since silencing works
+by redirecting a script's output to ``os.devnull``.


Test patch:
diff --git a/tests/test_history.py b/tests/test_history.py
index ac8c6cb6..3021109c 100755
--- a/tests/test_history.py
+++ b/tests/test_history.py
@@ -520,7 +520,7 @@ def test_history_run_one_command(base_app):
     out2, err2 = run_cmd(base_app, 'history -r 1')
     assert out1 == out2
 
-def test_history_clear(hist_file):
+def test_history_clear(mocker, hist_file):
     # Add commands to history
     app = cmd2.Cmd(persistent_history_file=hist_file)
     run_cmd(app, 'help')
@@ -538,6 +538,17 @@ def test_history_clear(hist_file):
     assert out == []
     assert not os.path.exists(hist_file)
 
+    # Clear the history again and make sure the FileNotFoundError from trying to delete missing history file is silent
+    run_cmd(app, 'history --clear')
+
+    # Cause os.remove to fail and make sure error gets printed
+    mock_remove = mocker.patch('os.remove')
+    mock_remove.side_effect = OSError
+
+    out, err = run_cmd(app, 'history --clear')
+    assert out == []
+    assert 'Error removing history file' in err[0]
+
 def test_history_verbose_with_other_options(base_app):
     # make sure -v shows a usage error if any other options are present
     options_to_test = ['-r', '-e', '-o file', '-t file', '-c', '-x']
diff --git a/tests/test_table_creator.py b/tests/test_table_creator.py
index 0a0e712d..649674a4 100644
--- a/tests/test_table_creator.py
+++ b/tests/test_table_creator.py
@@ -259,6 +259,10 @@ def test_tabs():
                           inter_cell='\t', post_line='\t')
     assert row == '  Col  1                Col 2  '
 
+    with pytest.raises(ValueError) as excinfo:
+        TableCreator([column_1, column_2], tab_width=0)
+    assert "Tab width cannot be less than 1" in str(excinfo.value)
+
 
 def test_simple_table_creation():
     column_1 = Column("Col 1", width=16)