Repository: python-cmd2/cmd2
Pull request #783 (2019-09-24 19:06:39)

Help fix
Fixed bug introduced by get_names() looking at self instead of self.__class__ where help functions for hidden and disabled commands were not being filtered out as help topics.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c20eab26..8135a086 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.9.18 (TBD, 2019)
+* Bug Fixes
+    * Fixed bug introduced in 0.9.17 where help functions for hidden and disabled commands were not being filtered
+     out as help topics
+
 ## 0.9.17 (September 23, 2019)
 * Bug Fixes
     * Fixed a bug when using WSL when all Windows paths have been removed from $PATH
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index d353af14..50d562b4 100755
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -1625,19 +1625,8 @@ class Cmd(cmd.Cmd):
 
     def get_visible_commands(self) -> List[str]:
         """Return a list of commands that have not been hidden or disabled"""
-        commands = self.get_all_commands()
-
-        # Remove the hidden commands
-        for name in self.hidden_commands:
-            if name in commands:
-                commands.remove(name)
-
-        # Remove the disabled commands
-        for name in self.disabled_commands:
-            if name in commands:
-                commands.remove(name)
-
-        return commands
+        return [command for command in self.get_all_commands()
+                if command not in self.hidden_commands and command not in self.disabled_commands]
 
     def _get_alias_completion_items(self) -> List[CompletionItem]:
         """Return list of current alias names and values as CompletionItems"""
@@ -1659,9 +1648,13 @@ class Cmd(cmd.Cmd):
         return list(visible_commands | alias_names | macro_names)
 
     def get_help_topics(self) -> List[str]:
-        """ Returns a list of help topics """
-        return [name[len(HELP_FUNC_PREFIX):] for name in self.get_names()
-                if name.startswith(HELP_FUNC_PREFIX) and callable(getattr(self, name))]
+        """Return a list of help topics"""
+        all_topics = [name[len(HELP_FUNC_PREFIX):] for name in self.get_names()
+                      if name.startswith(HELP_FUNC_PREFIX) and callable(getattr(self, name))]
+
+        # Filter out hidden and disabled commands
+        return [topic for topic in all_topics
+                if topic not in self.hidden_commands and topic not in self.disabled_commands]
 
     # noinspection PyUnusedLocal
     def sigint_handler(self, signum: int, frame) -> None:


Test patch:
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index 25273b4c..635e7ebd 100755
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -1981,6 +1981,23 @@ def test_get_help_topics(base_app):
     custom_help = base_app.get_help_topics()
     assert len(custom_help) == 0
 
+def test_get_help_topics_hidden():
+    # Verify get_help_topics() filters out hidden commands
+    class TestApp(cmd2.Cmd):
+        def __init__(self, *args, **kwargs):
+            super().__init__(*args, **kwargs)
+
+        def do_my_cmd(self, args):
+            pass
+
+        def help_my_cmd(self, args):
+            pass
+
+    app = TestApp()
+    assert 'my_cmd' in app.get_help_topics()
+
+    app.hidden_commands.append('my_cmd')
+    assert 'my_cmd' not in app.get_help_topics()
 
 class ReplWithExitCode(cmd2.Cmd):
     """ Example cmd2 application where we can specify an exit code when existing."""
@@ -2240,6 +2257,10 @@ def test_disable_and_enable_category(disable_commands_app):
     assert 'has_helper_funcs' not in visible_commands
     assert 'has_no_helper_funcs' not in visible_commands
 
+    # Make sure get_help_topics() filters out disabled commands
+    help_topics = disable_commands_app.get_help_topics()
+    assert 'has_helper_funcs' not in help_topics
+
     ##########################################################################
     # Enable the category
     ##########################################################################
@@ -2281,6 +2302,10 @@ def test_disable_and_enable_category(disable_commands_app):
     assert 'has_helper_funcs' in visible_commands
     assert 'has_no_helper_funcs' in visible_commands
 
+    # Make sure get_help_topics() contains our help function
+    help_topics = disable_commands_app.get_help_topics()
+    assert 'has_helper_funcs' in help_topics
+
 def test_enable_enabled_command(disable_commands_app):
     # Test enabling a command that is not disabled
     saved_len = len(disable_commands_app.disabled_commands)