summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.coveragerc3
-rw-r--r--cmd2/__init__.py3
-rw-r--r--cmd2/cmd2.py53
-rw-r--r--noxfile.py22
-rw-r--r--plugins/ext_test/cmd2_ext_test/__init__.py8
-rw-r--r--plugins/ext_test/cmd2_ext_test/cmd2_ext_test.py2
-rw-r--r--plugins/tasks.py5
-rw-r--r--plugins/template/cmd2_myplugin/__init__.py13
-rw-r--r--plugins/template/cmd2_myplugin/myplugin.py2
9 files changed, 66 insertions, 45 deletions
diff --git a/.coveragerc b/.coveragerc
index 96bf5d72..ad8b6730 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,7 +1,8 @@
# .coveragerc to control coverage.py
[run]
# Source
-source = cmd2/
+source = plugins/*/cmd2_*/
+ cmd2/
# (boolean, default False): whether to measure branch coverage in addition to statement coverage.
branch = False
diff --git a/cmd2/__init__.py b/cmd2/__init__.py
index 8c07fb80..c3c1f87e 100644
--- a/cmd2/__init__.py
+++ b/cmd2/__init__.py
@@ -11,7 +11,7 @@ except ImportError:
import importlib_metadata
try:
__version__ = importlib_metadata.version(__name__)
-except importlib_metadata.PackageNotFoundError:
+except importlib_metadata.PackageNotFoundError: # pragma: no cover
# package is not installed
pass
@@ -31,6 +31,7 @@ from .cmd2 import Cmd
from .constants import COMMAND_NAME, DEFAULT_SHORTCUTS
from .decorators import with_argument_list, with_argparser, with_argparser_and_unknown_args, with_category
from .exceptions import Cmd2ArgparseError, SkipPostcommandHooks
+from . import plugin
from .parsing import Statement
from .py_bridge import CommandResult
from .utils import categorize, CompletionError, Settable
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index cdee3523..70ec508c 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -200,7 +200,7 @@ class Cmd(cmd.Cmd):
self.max_completion_items = 50
# A dictionary mapping settable names to their Settable instance
- self.settables = dict()
+ self.settables = dict() # type: Dict[str, Settable]
self.build_settables()
# Use as prompt for multiline commands on the 2nd+ line of input
@@ -220,7 +220,7 @@ class Cmd(cmd.Cmd):
self.exclude_from_history = ['eof', 'history']
# Dictionary of macro names and their values
- self.macros = dict()
+ self.macros = dict() # type: Dict[str, Macro]
# Keeps track of typed command history in the Python shell
self._py_history = []
@@ -249,14 +249,14 @@ class Cmd(cmd.Cmd):
self.last_result = None
# Used by run_script command to store current script dir as a LIFO queue to support _relative_run_script command
- self._script_dir = []
+ self._script_dir = [] # type: List[str]
# Context manager used to protect critical sections in the main thread from stopping due to a KeyboardInterrupt
self.sigint_protection = utils.ContextFlag()
# If the current command created a process to pipe to, then this will be a ProcReader object.
# Otherwise it will be None. It's used to know when a pipe process can be killed and/or waited upon.
- self._cur_pipe_proc_reader = None
+ self._cur_pipe_proc_reader = None # type: Optional[utils.ProcReader]
# Used to keep track of whether we are redirecting or piping output
self._redirecting = False
@@ -280,7 +280,7 @@ class Cmd(cmd.Cmd):
self.broken_pipe_warning = ''
# Commands that will run at the beginning of the command loop
- self._startup_commands = []
+ self._startup_commands = [] # type: List[str]
# If a startup script is provided and exists, then execute it in the startup commands
if startup_script:
@@ -289,7 +289,7 @@ class Cmd(cmd.Cmd):
self._startup_commands.append("run_script {}".format(utils.quote_string(startup_script)))
# Transcript files to run instead of interactive command loop
- self._transcript_files = None
+ self._transcript_files = None # type: Optional[List[str]]
# Check for command line args
if allow_cli_args:
@@ -333,7 +333,7 @@ class Cmd(cmd.Cmd):
# Commands that have been disabled from use. This is to support commands that are only available
# during specific states of the application. This dictionary's keys are the command names and its
# values are DisabledCommand objects.
- self.disabled_commands = dict()
+ self.disabled_commands = dict() # type: Dict[str, DisabledCommand]
# If any command has been categorized, then all other commands that haven't been categorized
# will display under this section in the help output.
@@ -1910,7 +1910,7 @@ class Cmd(cmd.Cmd):
self._cur_pipe_proc_reader, self._redirecting)
# The ProcReader for this command
- cmd_pipe_proc_reader = None
+ cmd_pipe_proc_reader = None # type: Optional[utils.ProcReader]
if not self.allow_redirection:
# Don't return since we set some state variables at the end of the function
@@ -2694,16 +2694,31 @@ class Cmd(cmd.Cmd):
def _help_menu(self, verbose: bool = False) -> None:
"""Show a list of commands which help can be displayed for"""
+ cmds_cats, cmds_doc, cmds_undoc, help_topics = self._build_command_info()
+
+ if len(cmds_cats) == 0:
+ # No categories found, fall back to standard behavior
+ self.poutput("{}".format(str(self.doc_leader)))
+ self._print_topics(self.doc_header, cmds_doc, verbose)
+ else:
+ # Categories found, Organize all commands by category
+ self.poutput('{}'.format(str(self.doc_leader)))
+ self.poutput('{}'.format(str(self.doc_header)), end="\n\n")
+ for category in sorted(cmds_cats.keys(), key=self.default_sort_key):
+ self._print_topics(category, cmds_cats[category], verbose)
+ self._print_topics(self.default_category, cmds_doc, verbose)
+
+ self.print_topics(self.misc_header, help_topics, 15, 80)
+ self.print_topics(self.undoc_header, cmds_undoc, 15, 80)
+
+ def _build_command_info(self):
# Get a sorted list of help topics
help_topics = sorted(self.get_help_topics(), key=self.default_sort_key)
-
# Get a sorted list of visible command names
visible_commands = sorted(self.get_visible_commands(), key=self.default_sort_key)
-
cmds_doc = []
cmds_undoc = []
cmds_cats = {}
-
for command in visible_commands:
func = self.cmd_func(command)
has_help_func = False
@@ -2724,21 +2739,7 @@ class Cmd(cmd.Cmd):
cmds_doc.append(command)
else:
cmds_undoc.append(command)
-
- if len(cmds_cats) == 0:
- # No categories found, fall back to standard behavior
- self.poutput("{}".format(str(self.doc_leader)))
- self._print_topics(self.doc_header, cmds_doc, verbose)
- else:
- # Categories found, Organize all commands by category
- self.poutput('{}'.format(str(self.doc_leader)))
- self.poutput('{}'.format(str(self.doc_header)), end="\n\n")
- for category in sorted(cmds_cats.keys(), key=self.default_sort_key):
- self._print_topics(category, cmds_cats[category], verbose)
- self._print_topics(self.default_category, cmds_doc, verbose)
-
- self.print_topics(self.misc_header, help_topics, 15, 80)
- self.print_topics(self.undoc_header, cmds_undoc, 15, 80)
+ return cmds_cats, cmds_doc, cmds_undoc, help_topics
def _print_topics(self, header: str, cmds: List[str], verbose: bool) -> None:
"""Customized version of print_topics that can switch between verbose or traditional output"""
diff --git a/noxfile.py b/noxfile.py
index 1821c127..df4e97aa 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -3,7 +3,10 @@ import nox
@nox.session(python=['3.7'])
def docs(session):
- session.install('sphinx', 'sphinx-rtd-theme', '.')
+ session.install('sphinx',
+ 'sphinx-rtd-theme',
+ '.',
+ )
session.chdir('docs')
tmpdir = session.create_tmp()
@@ -12,16 +15,25 @@ def docs(session):
@nox.session(python=['3.5', '3.6', '3.7', '3.8', '3.9'])
-@nox.parametrize('plugin', [None, 'ext_test', 'template'])
+@nox.parametrize('plugin', [None,
+ 'ext_test',
+ 'template',
+ 'coverage'])
def tests(session, plugin):
if plugin is None:
session.install('invoke', './[test]')
session.run('invoke', 'pytest', '--junit', '--no-pty')
+ elif plugin == 'coverage':
+ session.install('invoke', 'codecov', 'coverage')
+ session.run('codecov')
else:
session.install('invoke', '.')
# cd into test directory to run other unit test
session.install('plugins/{}[test]'.format(plugin))
- session.run('invoke', 'plugin.{}.pytest'.format(plugin.replace('_', '-')), '--junit', '--no-pty')
-
- session.run('codecov')
+ session.run('invoke',
+ 'plugin.{}.pytest'.format(plugin.replace('_', '-')),
+ '--junit',
+ '--no-pty',
+ '--append-cov',
+ )
diff --git a/plugins/ext_test/cmd2_ext_test/__init__.py b/plugins/ext_test/cmd2_ext_test/__init__.py
index dbbc4250..21fd000b 100644
--- a/plugins/ext_test/cmd2_ext_test/__init__.py
+++ b/plugins/ext_test/cmd2_ext_test/__init__.py
@@ -1,19 +1,19 @@
#
# coding=utf-8
-"""Description of myplugin
+"""cmd2 External Python Testing Mixin
-An overview of what myplugin does.
+Allows developers to exercise their cmd2 application using the PyScript interface
"""
try:
# For python 3.8 and later
import importlib.metadata as importlib_metadata
-except ImportError:
+except ImportError: # pragma: no cover
# For everyone else
import importlib_metadata
try:
__version__ = importlib_metadata.version(__name__)
-except importlib_metadata.PackageNotFoundError:
+except importlib_metadata.PackageNotFoundError: # pragma: no cover
# package is not installed
__version__ = 'unknown'
diff --git a/plugins/ext_test/cmd2_ext_test/cmd2_ext_test.py b/plugins/ext_test/cmd2_ext_test/cmd2_ext_test.py
index 731a0f3b..df54e112 100644
--- a/plugins/ext_test/cmd2_ext_test/cmd2_ext_test.py
+++ b/plugins/ext_test/cmd2_ext_test/cmd2_ext_test.py
@@ -6,7 +6,7 @@ from typing import Optional, TYPE_CHECKING
import cmd2
-if TYPE_CHECKING:
+if TYPE_CHECKING: # pragma: no cover
_Base = cmd2.Cmd
else:
_Base = object
diff --git a/plugins/tasks.py b/plugins/tasks.py
index 06104429..26ec1adb 100644
--- a/plugins/tasks.py
+++ b/plugins/tasks.py
@@ -8,14 +8,15 @@ Make sure you satisfy the following Python module requirements if you are trying
- wheel >= 0.31.0
- setuptools >= 39.1.0
"""
-import os
import invoke
from plugins.ext_test import tasks as ext_test_tasks
from plugins.template import tasks as template_tasks
# create namespaces
-namespace = invoke.Collection(ext_test=ext_test_tasks, template=template_tasks)
+namespace = invoke.Collection(ext_test=ext_test_tasks,
+ template=template_tasks,
+ )
namespace_clean = invoke.Collection('clean')
namespace.add_collection(namespace_clean, 'clean')
diff --git a/plugins/template/cmd2_myplugin/__init__.py b/plugins/template/cmd2_myplugin/__init__.py
index 41f0b9cc..e66b62cd 100644
--- a/plugins/template/cmd2_myplugin/__init__.py
+++ b/plugins/template/cmd2_myplugin/__init__.py
@@ -5,11 +5,16 @@
An overview of what myplugin does.
"""
-from pkg_resources import get_distribution, DistributionNotFound
-
from .myplugin import empty_decorator, MyPluginMixin # noqa: F401
try:
- __version__ = get_distribution(__name__).version
-except DistributionNotFound:
+ # For python 3.8 and later
+ import importlib.metadata as importlib_metadata
+except ImportError: # pragma: no cover
+ # For everyone else
+ import importlib_metadata
+try:
+ __version__ = importlib_metadata.version(__name__)
+except importlib_metadata.PackageNotFoundError: # pragma: no cover
+ # package is not installed
__version__ = 'unknown'
diff --git a/plugins/template/cmd2_myplugin/myplugin.py b/plugins/template/cmd2_myplugin/myplugin.py
index 5fa12caf..4f1ff0e9 100644
--- a/plugins/template/cmd2_myplugin/myplugin.py
+++ b/plugins/template/cmd2_myplugin/myplugin.py
@@ -7,7 +7,7 @@ from typing import Callable, TYPE_CHECKING
import cmd2
-if TYPE_CHECKING:
+if TYPE_CHECKING: # pragma: no cover
_Base = cmd2.Cmd
else:
_Base = object