diff options
author | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2020-09-17 20:09:40 -0400 |
---|---|---|
committer | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2020-09-17 20:09:40 -0400 |
commit | ed3f9094c013cce618571a8718c76f5e0dbaba3d (patch) | |
tree | bfb7bbce00bad232a643c550f95b01831f7c0dc0 /cmd2/command_definition.py | |
parent | cf9516e5d25df5e4e330f75ab0f800ba8b4217c8 (diff) | |
parent | 92b8a38d66d255027a0440c45582d319f2694aab (diff) | |
download | cmd2-git-ed3f9094c013cce618571a8718c76f5e0dbaba3d.tar.gz |
Merge branch 'master' into silence
Diffstat (limited to 'cmd2/command_definition.py')
-rw-r--r-- | cmd2/command_definition.py | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/cmd2/command_definition.py b/cmd2/command_definition.py index 64adaada..3f05792c 100644 --- a/cmd2/command_definition.py +++ b/cmd2/command_definition.py @@ -4,7 +4,7 @@ Supports the definition of commands in separate classes to be composed into cmd2 """ from typing import Optional, Type -from .constants import COMMAND_FUNC_PREFIX +from .constants import CLASS_ATTR_DEFAULT_HELP_CATEGORY, COMMAND_FUNC_PREFIX from .exceptions import CommandSetRegistrationError # Allows IDEs to resolve types without impacting imports at runtime, breaking circular dependency issues @@ -17,22 +17,40 @@ except ImportError: # pragma: no cover pass -def with_default_category(category: str): +def with_default_category(category: str, *, heritable: bool = True): """ Decorator that applies a category to all ``do_*`` command methods in a class that do not already have a category specified. + CommandSets that are decorated by this with `heritable` set to True (default) will set a class attribute that is + inherited by all subclasses unless overridden. All commands of this CommandSet and all subclasses of this CommandSet + that do not declare an explicit category will be placed in this category. Subclasses may use this decorator to + override the default category. + + If `heritable` is set to False, then only the commands declared locally to this CommandSet will be placed in the + specified category. Dynamically created commands, and commands declared in sub-classes will not receive this + category. + :param category: category to put all uncategorized commands in + :param heritable: Flag whether this default category should apply to sub-classes. Defaults to True :return: decorator function """ def decorate_class(cls: Type[CommandSet]): + if heritable: + setattr(cls, CLASS_ATTR_DEFAULT_HELP_CATEGORY, category) + from .constants import CMD_ATTR_HELP_CATEGORY import inspect from .decorators import with_category + # get members of the class that meet the following criteria: + # 1. Must be a function + # 2. Must start with COMMAND_FUNC_PREFIX (do_) + # 3. Must be a member of the class being decorated and not one inherited from a parent declaration methods = inspect.getmembers( cls, - predicate=lambda meth: inspect.isfunction(meth) and meth.__name__.startswith(COMMAND_FUNC_PREFIX)) + predicate=lambda meth: inspect.isfunction(meth) and meth.__name__.startswith(COMMAND_FUNC_PREFIX) + and meth in inspect.getmro(cls)[0].__dict__.values()) category_decorator = with_category(category) for method in methods: if not hasattr(method[1], CMD_ATTR_HELP_CATEGORY): |