summaryrefslogtreecommitdiff
path: root/cmd2/argparse_custom.py
diff options
context:
space:
mode:
authorEric Lin <anselor@gmail.com>2021-08-19 17:03:42 -0400
committeranselor <anselor@gmail.com>2021-08-23 14:17:12 -0400
commit49805324772ec5fcd06217f4f0a241a9a8d07960 (patch)
treea1647a18085df118bbe12dc37c67104f2817024b /cmd2/argparse_custom.py
parent6d771e96c0507d9ef4ad3eaaf4bc83669396e591 (diff)
downloadcmd2-git-49805324772ec5fcd06217f4f0a241a9a8d07960.tar.gz
* New function `set_default_command_completer_type()` allows developer to extend and modify the
behavior of `ArgparseCompleter`. * New function `register_argparse_argument_parameter()` allows developers to specify custom parameters to be passed to the argparse parser's `add_argument()` method. These parameters will become accessible in the resulting argparse Action object when modifying `ArgparseCompleter` behavior.
Diffstat (limited to 'cmd2/argparse_custom.py')
-rw-r--r--cmd2/argparse_custom.py78
1 files changed, 78 insertions, 0 deletions
diff --git a/cmd2/argparse_custom.py b/cmd2/argparse_custom.py
index 770b1e5c..2bcb0af9 100644
--- a/cmd2/argparse_custom.py
+++ b/cmd2/argparse_custom.py
@@ -238,6 +238,7 @@ from typing import (
NoReturn,
Optional,
Sequence,
+ Set,
Tuple,
Type,
Union,
@@ -639,9 +640,73 @@ setattr(argparse.Action, 'set_suppress_tab_hint', _action_set_suppress_tab_hint)
############################################################################################################
+# Allow developers to add custom action attributes
+############################################################################################################
+
+CUSTOM_ACTION_ATTRIBS: Set[str] = set()
+_CUSTOM_ATTRIB_PFX = '_attr_'
+
+
+def register_argparse_argument_parameter(param_name: str, param_type: Optional[Type[Any]]) -> None:
+ """
+ Registers a custom argparse argument parameter.
+
+ The registered name will then be a recognized keyword parameter to the parser's `add_argument()` function.
+
+ An accessor functions will be added to the parameter's Action object in the form of: ``get_{param_name}()``
+ and ``set_{param_name}(value)``.
+
+ :param param_name: Name of the parameter to add.
+ """
+ attr_name = f'{_CUSTOM_ATTRIB_PFX}{param_name}'
+ if param_name in CUSTOM_ACTION_ATTRIBS or hasattr(argparse.Action, attr_name):
+ raise KeyError(f'Custom parameter {param_name} already exists')
+ if not re.search('^[A-Za-z_][A-Za-z0-9_]*$', param_name):
+ raise KeyError(f'Invalid parameter name {param_name} - cannot be used as a python identifier')
+
+ getter_name = f'get_{param_name}'
+
+ def _action_get_custom_parameter(self: argparse.Action) -> Any:
+ f"""
+ Get the custom {param_name} attribute of an argparse Action.
+
+ This function is added by cmd2 as a method called ``{getter_name}()`` to ``argparse.Action`` class.
+
+ To call: ``action.{getter_name}()``
+
+ :param self: argparse Action being queried
+ :return: The value of {param_name} or None if attribute does not exist
+ """
+ return getattr(self, attr_name, None)
+
+ setattr(argparse.Action, getter_name, _action_get_custom_parameter)
+
+ setter_name = f'set_{param_name}'
+
+ def _action_set_custom_parameter(self: argparse.Action, value: Any) -> None:
+ f"""
+ Set the custom {param_name} attribute of an argparse Action.
+
+ This function is added by cmd2 as a method called ``{setter_name}()`` to ``argparse.Action`` class.
+
+ To call: ``action.{setter_name}({param_name})``
+
+ :param self: argparse Action being updated
+ :param value: value being assigned
+ """
+ if param_type and not isinstance(value, param_type):
+ raise TypeError(f'{param_name} must be of type {param_type}, got: {value} ({type(value)})')
+ setattr(self, attr_name, value)
+
+ setattr(argparse.Action, setter_name, _action_set_custom_parameter)
+
+ CUSTOM_ACTION_ATTRIBS.add(param_name)
+
+############################################################################################################
# Patch _ActionsContainer.add_argument with our wrapper to support more arguments
############################################################################################################
+
# Save original _ActionsContainer.add_argument so we can call it in our wrapper
# noinspection PyProtectedMember
orig_actions_container_add_argument = argparse._ActionsContainer.add_argument
@@ -751,6 +816,14 @@ def _add_argument_wrapper(
# Add the argparse-recognized version of nargs to kwargs
kwargs['nargs'] = nargs_adjusted
+ # Extract registered custom keyword arguments
+ custom_attribs: Dict[str, Any] = {}
+ for keyword, value in kwargs.items():
+ if keyword in CUSTOM_ACTION_ATTRIBS:
+ custom_attribs[keyword] = value
+ for keyword in custom_attribs:
+ del kwargs[keyword]
+
# Create the argument using the original add_argument function
new_arg = orig_actions_container_add_argument(self, *args, **kwargs)
@@ -765,6 +838,11 @@ def _add_argument_wrapper(
new_arg.set_suppress_tab_hint(suppress_tab_hint) # type: ignore[attr-defined]
new_arg.set_descriptive_header(descriptive_header) # type: ignore[attr-defined]
+ for keyword, value in custom_attribs.items():
+ attr_setter = getattr(new_arg, f'set_{keyword}', None)
+ if attr_setter is not None:
+ attr_setter(value)
+
return new_arg