From e807a3126d048c5ede4b5acb812d981bdc405610 Mon Sep 17 00:00:00 2001 From: the Mulhern Date: Tue, 28 Jan 2025 15:14:04 -0500 Subject: [PATCH] Add secret command-line option to print all help text Suppress the help text for this option. In order to find all subcommands, the code needs to introspect on the parser, which is most easily achieved within stratis-cli source. Canonicalize the order of the help text output alphabetically by subparser name. Add a test for the --print-all-help option and remove the old test because it duplicates the --print-all-help option action. Suppress the output from the help text unit test. It's fairly verbose and after this PR the output will be available from the stratis-cli command-line, so there will be almost no utility in having it stored in every test run also. Signed-off-by: mulhern --- src/stratis_cli/_parser/_parser.py | 6 +++ src/stratis_cli/_parser/_range.py | 33 ++++++++++++ tests/whitebox/integration/test_help_text.py | 53 -------------------- tests/whitebox/integration/test_parser.py | 17 +++++++ 4 files changed, 56 insertions(+), 53 deletions(-) delete mode 100644 tests/whitebox/integration/test_help_text.py diff --git a/src/stratis_cli/_parser/_parser.py b/src/stratis_cli/_parser/_parser.py index 7be7294ff..68f7c2269 100644 --- a/src/stratis_cli/_parser/_parser.py +++ b/src/stratis_cli/_parser/_parser.py @@ -33,6 +33,7 @@ from ._logical import LOGICAL_SUBCMDS from ._physical import PHYSICAL_SUBCMDS from ._pool import POOL_SUBCMDS +from ._range import PrintHelpAction def print_help(parser): @@ -213,6 +214,11 @@ def gen_parser(): # version is special, it has explicit support in argparse parser.add_argument("--version", action="version", version=__version__) + # --print-all-help is special because it introspects on the parser + parser.add_argument( + "--print-all-help", action=PrintHelpAction, help=argparse.SUPPRESS, nargs=0 + ) + _add_args(parser, GEN_ARGS) subparsers = parser.add_subparsers(title="subcommands") diff --git a/src/stratis_cli/_parser/_range.py b/src/stratis_cli/_parser/_range.py index c41a5100c..b03c9c2cd 100644 --- a/src/stratis_cli/_parser/_range.py +++ b/src/stratis_cli/_parser/_range.py @@ -18,6 +18,7 @@ # isort: STDLIB import argparse import re +import sys # isort: THIRDPARTY from justbytes import B, GiB, KiB, MiB, PiB, Range, TiB @@ -98,3 +99,35 @@ class DefaultAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): setattr(namespace, self.dest, values) setattr(namespace, self.dest + "_default", False) + + +def gen_subparsers(parser, command_line): + """ + Yield all subparser/command_lines pairs for this parser and this prefix + command line. + + :param parser: an argparse parser + :param command_line: a prefix command line + :type command_line: list of str + """ + yield (parser, command_line) + for action in ( + action + for action in parser._actions # pylint: disable=protected-access + if isinstance( + action, argparse._SubParsersAction # pylint: disable=protected-access + ) + ): + for name, subparser in sorted(action.choices.items(), key=lambda x: x[0]): + yield from gen_subparsers(subparser, command_line + [name]) + + +class PrintHelpAction(argparse.Action): + """ + Print the help text for every subcommand. + """ + + def __call__(self, parser, namespace, values, option_string=None): + for subparser, _ in gen_subparsers(parser, []): + subparser.print_help() + sys.exit(0) diff --git a/tests/whitebox/integration/test_help_text.py b/tests/whitebox/integration/test_help_text.py deleted file mode 100644 index fd58994ce..000000000 --- a/tests/whitebox/integration/test_help_text.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2025 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -Test that printing out help text does not result in any error returns or -exceptions. -""" - -# isort: STDLIB -from argparse import _SubParsersAction - -# isort: LOCAL -from stratis_cli._parser import gen_parser - -from ._misc import RunTestCase - - -def gen_subcommands(parser, command_line): - """ - Recursively traverse the parser, yielding all possible subcommands. - """ - yield command_line - for action in ( - action - for action in parser._actions # pylint: disable=protected-access - if isinstance(action, _SubParsersAction) - ): - for name, subparser in action.choices.items(): - yield from gen_subcommands(subparser, command_line + [name]) - - -class ParserHelpTestCase(RunTestCase): - """ - Test various timeout inputs. - """ - - def test_help(self): - """ - Test all parser help. - """ - - for command_line in gen_subcommands(gen_parser(), []): - self.check_system_exit(command_line + ["--help"], 0) diff --git a/tests/whitebox/integration/test_parser.py b/tests/whitebox/integration/test_parser.py index 7076a5a49..2dc1f8a40 100644 --- a/tests/whitebox/integration/test_parser.py +++ b/tests/whitebox/integration/test_parser.py @@ -15,6 +15,10 @@ Test command-line argument parsing. """ +# isort: STDLIB +from io import StringIO +from unittest import mock + # isort: LOCAL from stratis_cli import StratisCliErrorCodes @@ -432,3 +436,16 @@ def test_stratis_list_default(self): for subcommand in [["pool"], ["filesystem"], ["blockdev"]]: for prefix in [[], ["--propagate"]]: self.assertEqual(RUNNER(prefix + subcommand), 0) + + +class TestAllHelp(RunTestCase): + """ + Verify that --print-all-help option succeeds. + """ + + def test_print_all_help(self): + """ + Test the --print-all-help option. + """ + with mock.patch("sys.stdout", new=StringIO()): + self.check_system_exit(["--print-all-help"], 0)