summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd2/cmd2.py11
-rw-r--r--cmd2/utils.py11
-rwxr-xr-xtests/test_cmd2.py6
-rw-r--r--tests/test_utils.py2
4 files changed, 25 insertions, 5 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 37779f56..7373188b 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -388,6 +388,17 @@ class Cmd(cmd.Cmd):
"""
self.settables[settable.name] = settable
+ def remove_settable(self, name: str) -> None:
+ """
+ Convenience method for removing a settable parameter from self.settables
+ :param name: name of the settable being removed
+ :raises: KeyError if the no Settable matches this name
+ """
+ try:
+ del self.settables[name]
+ except KeyError:
+ raise KeyError(name + " is not a settable parameter")
+
def build_settables(self):
"""Populates self.add_settable with parameters that can be edited via the set command"""
self.add_settable(Settable('allow_style', str,
diff --git a/cmd2/utils.py b/cmd2/utils.py
index 728c1ac3..9635be42 100644
--- a/cmd2/utils.py
+++ b/cmd2/utils.py
@@ -69,18 +69,18 @@ def str_to_bool(val: str) -> bool:
return True
elif val.capitalize() == str(False):
return False
- raise ValueError("must be True or False")
+ raise ValueError("must be True or False (case-insensitive)")
class Settable:
"""Used to configure a cmd2 instance member to be settable via the set command in the CLI"""
def __init__(self, name: str, val_type: Callable, description: str, *,
+ onchange_cb: Callable[[str, Any, Any], Any] = None,
choices: Iterable = None,
choices_function: Optional[Callable] = None,
choices_method: Optional[Callable] = None,
completer_function: Optional[Callable] = None,
- completer_method: Optional[Callable] = None,
- onchange_cb: Callable[[str, Any, Any], Any] = None):
+ completer_method: Optional[Callable] = None):
"""
Settable Initializer
@@ -90,6 +90,9 @@ class Settable:
validation using str_to_bool(). The val_type function should raise an exception if it fails.
This exception will be caught and printed by Cmd.do_set().
:param description: string describing this setting
+ :param onchange_cb: optional function to call when the value of this settable is altered by the set command
+ Callback signature:
+ val_changed_cb(param_name: str, old_value: Any, new_value: Any) -> Any
The following optional settings provide tab completion for a parameter's values. They correspond to the
same settings in argparse-based tab completion. A maximum of one of these should be provided.
@@ -107,12 +110,12 @@ class Settable:
self.name = name
self.val_type = val_type
self.description = description
+ self.onchange_cb = onchange_cb
self.choices = choices
self.choices_function = choices_function
self.choices_method = choices_method
self.completer_function = completer_function
self.completer_method = completer_method
- self.onchange_cb = onchange_cb
def namedtuple_with_defaults(typename: str, field_names: Union[str, List[str]],
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index 0615ed46..fecab628 100755
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -630,7 +630,7 @@ now: True
def test_debug_not_settable(base_app):
# Set debug to False and make it unsettable
base_app.debug = False
- del base_app.settables['debug']
+ base_app.remove_settable('debug')
# Cause an exception
out, err = run_cmd(base_app, 'bad "quote')
@@ -638,6 +638,10 @@ def test_debug_not_settable(base_app):
# Since debug is unsettable, the user will not be given the option to enable a full traceback
assert err == ['Invalid syntax: No closing quotation']
+def test_remove_settable_keyerror(base_app):
+ with pytest.raises(KeyError):
+ base_app.remove_settable('fake')
+
def test_edit_file(base_app, request, monkeypatch):
# Set a fake editor just to make sure we have one. We aren't really going to call it due to the mock
base_app.editor = 'fooedit'
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 804e58be..5030ce0e 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -537,11 +537,13 @@ def test_str_to_bool_true():
assert cu.str_to_bool('true')
assert cu.str_to_bool('True')
assert cu.str_to_bool('TRUE')
+ assert cu.str_to_bool('tRuE')
def test_str_to_bool_false():
assert not cu.str_to_bool('false')
assert not cu.str_to_bool('False')
assert not cu.str_to_bool('FALSE')
+ assert not cu.str_to_bool('fAlSe')
def test_str_to_bool_invalid():
with pytest.raises(ValueError):