From 438ef95f2977c1b0102a856a04fa5a5f4dd0ee3d Mon Sep 17 00:00:00 2001 From: bambu <564972+bambu@users.noreply.github.com> Date: Wed, 22 Apr 2026 09:48:52 -0400 Subject: [PATCH 1/2] Silenced the set command on success by default and consolidated its output. (#1627) * Made the set command silent on success by default. * Added a -v/--verbose flag to the set command to display change confirmations. * Consolidated the verbose output into a single, colorized line (e.g., param: old -> new). * Updated unit tests to reflect the new default behavior and output format. --- cmd2/cmd2.py | 17 +++++++++++++++- tests/test_cmd2.py | 43 ++++++++++++++++------------------------ tests/test_commandset.py | 9 +++------ 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 0d80dd007..dd19007cb 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -4685,6 +4685,12 @@ def complete_set_value( def _build_set_parser(cls) -> Cmd2ArgumentParser: # Create the parser for the set command set_parser = cls._build_base_set_parser() + set_parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="show the change", + ) set_parser.add_argument( "value", nargs=argparse.OPTIONAL, @@ -4720,7 +4726,16 @@ def do_set(self, args: argparse.Namespace) -> None: except ValueError as ex: self.perror(f"Error setting {args.param}: {ex}") else: - self.poutput(f"{args.param} - was: {orig_value!r}\nnow: {settable.value!r}") + if args.verbose: + feedback_msg = Text.assemble( + args.param, + ": ", + (f"{orig_value!r}", "red"), + " -> ", + (f"{settable.value!r}", "green"), + ) + self.poutput(feedback_msg) + self.last_result = True return diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index 39aad2d27..b10a6849c 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -121,7 +121,7 @@ def test_base_argparse_help(base_app) -> None: def test_base_invalid_option(base_app) -> None: _out, err = run_cmd(base_app, "set -z") - assert err[0] == "Usage: set [-h] [param] [value]" + assert err[0] == "Usage: set [-h] [-v] [param] [value]" assert "Error: unrecognized arguments: -z" in err[1] @@ -161,26 +161,27 @@ def test_base_set(base_app) -> None: def test_set(base_app) -> None: + # Test silent by default out, _err = run_cmd(base_app, "set quiet True") - expected = normalize( - """ -quiet - was: False -now: True -""" - ) + assert not out + assert base_app.last_result is True + + # Test verbose + out, _err = run_cmd(base_app, "set -v quiet False") + expected = ["quiet: True -> False"] assert out == expected assert base_app.last_result is True line_found = False out, _err = run_cmd(base_app, "set quiet") for line in out: - if "quiet" in line and "True" in line and "False" not in line: + if "quiet" in line and "False" in line and "True" not in line: line_found = True break assert line_found assert len(base_app.last_result) == 1 - assert base_app.last_result["quiet"] is True + assert base_app.last_result["quiet"] is False def test_set_val_empty(base_app) -> None: @@ -231,7 +232,7 @@ def test_set_no_settables(base_app) -> None: @with_ansi_style(ru.AllowStyle.TERMINAL) def test_set_allow_style(base_app, new_val, is_valid, expected) -> None: # Use the set command to alter allow_style - out, err = run_cmd(base_app, f"set allow_style {new_val}") + out, err = run_cmd(base_app, f"set -v allow_style {new_val}") assert base_app.last_result is is_valid # Verify the results @@ -276,12 +277,11 @@ def onchange_app(): def test_set_onchange_hook(onchange_app) -> None: - out, _err = run_cmd(onchange_app, "set quiet True") + out, _err = run_cmd(onchange_app, "set -v quiet True") expected = normalize( """ You changed quiet -quiet - was: False -now: True +quiet: False -> True """ ) assert out == expected @@ -874,12 +874,8 @@ def test_allow_clipboard(base_app) -> None: def test_base_timing(base_app) -> None: base_app.feedback_to_output = False - out, err = run_cmd(base_app, "set timing True") - expected = normalize( - """timing - was: False -now: True -""" - ) + out, err = run_cmd(base_app, "set -v timing True") + expected = ["timing: False -> True"] assert out == expected if sys.platform == "win32": @@ -898,13 +894,8 @@ def test_base_debug(base_app) -> None: assert "To enable full traceback" in err[3] # Set debug true - out, err = run_cmd(base_app, "set debug True") - expected = normalize( - """ -debug - was: False -now: True -""" - ) + out, err = run_cmd(base_app, "set -v debug True") + expected = ["debug: False -> True"] assert out == expected # Verify that we now see the exception traceback diff --git a/tests/test_commandset.py b/tests/test_commandset.py index 72d31e52e..03f7ca91d 100644 --- a/tests/test_commandset.py +++ b/tests/test_commandset.py @@ -1102,12 +1102,9 @@ def __init__(self) -> None: any("arbitrary_value" in line and "5" in line for line in out) # change the value and verify the value changed - out, err = run_cmd(app, "set arbitrary_value 10") - expected = """ -arbitrary_value - was: 5 -now: 10 -""" - assert out == normalize(expected) + out, err = run_cmd(app, "set -v arbitrary_value 10") + expected = ["arbitrary_value: 5 -> 10"] + assert out == expected out, err = run_cmd(app, "set arbitrary_value") any("arbitrary_value" in line and "10" in line for line in out) From 45f17c459acb52ebb972e14e90bd919cc774d61f Mon Sep 17 00:00:00 2001 From: bambu <564972+bambu@users.noreply.github.com> Date: Wed, 22 Apr 2026 22:04:34 -0400 Subject: [PATCH 2/2] Changed set command output unless quiet mode is enabled. * Updated do_set to use pfeedback for change confirmations, allowing it to be silenced via the quiet setting. * Updated unit tests to match the new output format and verify quiet mode behavior. --- CHANGELOG.md | 3 +++ cmd2/cmd2.py | 24 +++++++---------- tests/test_cmd2.py | 58 +++++++++++++++++++--------------------- tests/test_commandset.py | 6 ++--- 4 files changed, 43 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e24f2006..8b8b0b720 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -131,6 +131,9 @@ prompt is displayed. specific `cmd2.Cmd` subclass (e.g.,`class MyCommandSet(CommandSet[MyApp]):`). This provides full type hints and IDE autocompletion for `self._cmd` without needing to override and cast the property. + - Updated `set` command to consolidate its confirmation output into a single, colorized line. + The confirmation now uses `pfeedback()`, allowing it to be silenced when the `quiet` settable + is enabled. ## 3.5.0 (April 13, 2026) diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index dd19007cb..6cd333359 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -4685,12 +4685,6 @@ def complete_set_value( def _build_set_parser(cls) -> Cmd2ArgumentParser: # Create the parser for the set command set_parser = cls._build_base_set_parser() - set_parser.add_argument( - "-v", - "--verbose", - action="store_true", - help="show the change", - ) set_parser.add_argument( "value", nargs=argparse.OPTIONAL, @@ -4726,15 +4720,15 @@ def do_set(self, args: argparse.Namespace) -> None: except ValueError as ex: self.perror(f"Error setting {args.param}: {ex}") else: - if args.verbose: - feedback_msg = Text.assemble( - args.param, - ": ", - (f"{orig_value!r}", "red"), - " -> ", - (f"{settable.value!r}", "green"), - ) - self.poutput(feedback_msg) + # Create the feedback message using Rich Text for color + feedback_msg = Text.assemble( + args.param, + ": ", + (f"{orig_value!r}", "red"), + " -> ", + (f"{settable.value!r}", "green"), + ) + self.pfeedback(feedback_msg) self.last_result = True return diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index b10a6849c..4ae967498 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -121,7 +121,7 @@ def test_base_argparse_help(base_app) -> None: def test_base_invalid_option(base_app) -> None: _out, err = run_cmd(base_app, "set -z") - assert err[0] == "Usage: set [-h] [-v] [param] [value]" + assert err[0] == "Usage: set [-h] [param] [value]" assert "Error: unrecognized arguments: -z" in err[1] @@ -161,27 +161,28 @@ def test_base_set(base_app) -> None: def test_set(base_app) -> None: - # Test silent by default - out, _err = run_cmd(base_app, "set quiet True") + out, err = run_cmd(base_app, "set quiet True") assert not out assert base_app.last_result is True - # Test verbose - out, _err = run_cmd(base_app, "set -v quiet False") - expected = ["quiet: True -> False"] - assert out == expected + # Test quiet respect + out, err = run_cmd(base_app, "set timing False") + assert not out + assert not err assert base_app.last_result is True + # Show one settable (this always goes to out) line_found = False out, _err = run_cmd(base_app, "set quiet") for line in out: - if "quiet" in line and "False" in line and "True" not in line: + if "quiet" in line and "True" in line and "False" not in line: line_found = True break assert line_found assert len(base_app.last_result) == 1 - assert base_app.last_result["quiet"] is False + assert base_app.last_result["quiet"] is True + base_app.quiet = False def test_set_val_empty(base_app) -> None: @@ -232,14 +233,14 @@ def test_set_no_settables(base_app) -> None: @with_ansi_style(ru.AllowStyle.TERMINAL) def test_set_allow_style(base_app, new_val, is_valid, expected) -> None: # Use the set command to alter allow_style - out, err = run_cmd(base_app, f"set -v allow_style {new_val}") + out, err = run_cmd(base_app, f"set allow_style {new_val}") assert base_app.last_result is is_valid # Verify the results assert expected == ru.ALLOW_STYLE if is_valid: - assert not err - assert out + assert err + assert not out def test_set_with_choices(base_app) -> None: @@ -251,9 +252,10 @@ def test_set_with_choices(base_app) -> None: base_app.add_settable(fake_settable) # Try a valid choice - _out, err = run_cmd(base_app, f"set fake {fake_choices[1]}") + out, err = run_cmd(base_app, f"set fake {fake_choices[1]}") assert base_app.last_result is True - assert not err + assert not out + assert err == [f"fake: {fake_choices[0]!r} -> {fake_choices[1]!r}"] # Try an invalid choice _out, err = run_cmd(base_app, "set fake bad_value") @@ -277,14 +279,10 @@ def onchange_app(): def test_set_onchange_hook(onchange_app) -> None: - out, _err = run_cmd(onchange_app, "set -v quiet True") - expected = normalize( - """ -You changed quiet -quiet: False -> True -""" - ) - assert out == expected + out, err = run_cmd(onchange_app, "set quiet True") + assert out == ["You changed quiet"] + # quiet: False -> True is not shown because quiet is now True + assert not err assert onchange_app.last_result is True @@ -874,14 +872,14 @@ def test_allow_clipboard(base_app) -> None: def test_base_timing(base_app) -> None: base_app.feedback_to_output = False - out, err = run_cmd(base_app, "set -v timing True") - expected = ["timing: False -> True"] - assert out == expected + out, err = run_cmd(base_app, "set timing True") + assert not out + assert err[0] == "timing: False -> True" if sys.platform == "win32": - assert err[0].startswith("Elapsed: 0:00:00") + assert err[1].startswith("Elapsed: 0:00:00") else: - assert err[0].startswith("Elapsed: 0:00:00.0") + assert err[1].startswith("Elapsed: 0:00:00.0") def test_base_debug(base_app) -> None: @@ -894,9 +892,9 @@ def test_base_debug(base_app) -> None: assert "To enable full traceback" in err[3] # Set debug true - out, err = run_cmd(base_app, "set -v debug True") - expected = ["debug: False -> True"] - assert out == expected + out, err = run_cmd(base_app, "set debug True") + assert not out + assert err == ["debug: False -> True"] # Verify that we now see the exception traceback out, err = run_cmd(base_app, "edit") diff --git a/tests/test_commandset.py b/tests/test_commandset.py index 03f7ca91d..a9478f997 100644 --- a/tests/test_commandset.py +++ b/tests/test_commandset.py @@ -1102,9 +1102,9 @@ def __init__(self) -> None: any("arbitrary_value" in line and "5" in line for line in out) # change the value and verify the value changed - out, err = run_cmd(app, "set -v arbitrary_value 10") - expected = ["arbitrary_value: 5 -> 10"] - assert out == expected + out, err = run_cmd(app, "set arbitrary_value 10") + assert not out + assert err == ["arbitrary_value: 5 -> 10"] out, err = run_cmd(app, "set arbitrary_value") any("arbitrary_value" in line and "10" in line for line in out)