Repository: jonathanhaigh/multiconfparse

Issue:
Allow `SUPPRESS` value for `help` argument

Discussion:

Patch:
diff --git a/multiconfparse/__init__.py b/multiconfparse/__init__.py
index 12e455d..0d0f524 100644
--- a/multiconfparse/__init__.py
+++ b/multiconfparse/__init__.py
@@ -542,9 +542,12 @@ class ArgparseSource(Source):
         def __init__(self, option_strings, dest, action_obj, priority):
             self._action = action_obj
             self._priority = priority
+            help = action_obj.help
+            if help is SUPPRESS:
+                help = argparse.SUPPRESS
             super().__init__(
                 option_strings,
-                help=action_obj.help,
+                help=help,
                 default=[],
                 dest=dest,
                 nargs=action_obj.nargs,
@@ -1027,8 +1030,8 @@ class Action(abc.ABC):
     def _set_name(self, name):
         if not self._is_python_identifier(name):
             raise ValueError(
-                f"invalid config name '{name}', "
-                "must be a valid Python identifier"
+                f"invalid config name '{name}', must be a valid Python"
+                " identifier"
             )
         self.name = name
 
@@ -1037,7 +1040,7 @@ class Action(abc.ABC):
             dest = name
         if not self._is_python_identifier(dest):
             raise ValueError(
-                f"invalid dest '{dest}', " "must be a valid Python identifier"
+                f"invalid dest '{dest}', must be a valid Python identifier"
             )
         self.dest = dest
 
@@ -1146,7 +1149,7 @@ class StoreAction(Action):
         if const is not None and self.nargs != "?":
             raise ValueError(
                 f"const cannot be supplied to the {self.action_name} action "
-                f'unless nargs is "?"'
+                'unless nargs is "?"'
             )
         self.const = const
 
@@ -1396,7 +1399,7 @@ class AppendAction(Action):
         if const is not None and self.nargs != "?":
             raise ValueError(
                 f"const cannot be supplied to the {self.action_name} action "
-                f'unless nargs is "?"'
+                'unless nargs is "?"'
             )
         self.const = const
 
@@ -1678,7 +1681,9 @@ class ConfigParser:
           config item will be looked for by all sources added to the
           :class:`ConfigParser`.
 
-        * ``help``: the help text/description for the config item.
+        * ``help``: the help text/description for the config item. Set this to
+          :data:`SUPPRESS` to prevent this config item from being mentioned in
+          generated documentation.
 
         The other arguments are all keyword arguments and are passed on to the
         class that implements the config items action and may have different


Test patch:
diff --git a/tests/test_multiconfparse.py b/tests/test_multiconfparse.py
index 65b03e4..f58d3f4 100644
--- a/tests/test_multiconfparse.py
+++ b/tests/test_multiconfparse.py
@@ -161,7 +161,7 @@ class UcStoreAction(mcp.Action):
         if const is not None and self.nargs != "?":
             raise ValueError(
                 f"const cannot be supplied to the {self.action} action "
-                f'unless nargs is "?"'
+                'unless nargs is "?"'
             )
         self.const = const
 
@@ -177,8 +177,7 @@ class UcStoreAction(mcp.Action):
 
 class RaisingArgumentParser(argparse.ArgumentParser):
     def exit(self, status=0, message=None):
-        if status:
-            raise ArgparseError(message)
+        raise ArgparseError(message)
 
 
 class JsonEncoderWithPath(json.JSONEncoder):
@@ -609,6 +608,24 @@ def test_dest_with_simple_argparse():
     assert values == expected
 
 
+def test_suppress_help(capfd):
+    mcp_parser = mcp.ConfigParser()
+    mcp_parser.add_config("config_item1")
+    mcp_parser.add_config("config_item2", help=mcp.SUPPRESS)
+    mcp_parser.add_config("config_item3")
+    mcp_parser.add_source(
+        "simple_argparse", argument_parser_class=RaisingArgumentParser,
+    )
+    argv = "prog --help".split()
+    with utm.patch.object(sys, "argv", argv):
+        with pytest.raises(ArgparseError):
+            mcp_parser.parse_config()
+        out, err = capfd.readouterr()
+        assert "--config-item1" in out
+        assert "--config-item2" not in out
+        assert "--config-item3" in out
+
+
 test_specs = []
 
 nargs_test_specs = []
@@ -800,7 +817,7 @@ for action, nargs in itertools.product(
             id=(
                 f"nargs_with_default_and_global_default, action={action}, "
                 f"nargs={nargs}, args=yes_{nargs}, type={type.__name__},"
-                f"default=yes, global_default=yes"
+                "default=yes, global_default=yes"
             ),
             config_parser_args={"config_default": global_default_value},
             config_args={
@@ -820,7 +837,7 @@ for action, nargs in itertools.product(
             id=(
                 f"nargs_with_default_and_global_default, action={action}, "
                 f"nargs={nargs}, args=no, type={type.__name__}, "
-                f"default=yes, global_default=yes"
+                "default=yes, global_default=yes"
             ),
             config_parser_args={"config_default": global_default_value},
             config_args={
@@ -1102,7 +1119,7 @@ for action, nargs, const in itertools.chain(
         Spec(
             id=(
                 f"suppress, action={action}, nargs={nargs}, args=no, "
-                f"default=suppress"
+                "default=suppress"
             ),
             config_args={
                 "action": action,
@@ -1119,7 +1136,7 @@ for action, nargs, const in itertools.chain(
         Spec(
             id=(
                 f"suppress, action={action}, nargs={nargs}, args=no, "
-                f"default=none, config_default=suppress"
+                "default=none, config_default=suppress"
             ),
             config_args={"action": action, **extra_config_args},
             config_parser_args={"config_default": mcp.SUPPRESS},