proj/pkgcore/snakeoil:master commit in: src/snakeoil/cli/, /, tests/cli/

"Arthur Zamarin" <[email protected]>
Newsgroups gmane.linux.gentoo.cvs
Message-ID <1786169442.a831aed3e017109f85502cf877f58d42937b7ef9.arthurzam@gentoo>
commit:     a831aed3e017109f85502cf877f58d42937b7ef9
Author:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
AuthorDate: Sat Aug  8 06:10:42 2026 +0000
Commit:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
CommitDate: Sat Aug  8 06:10:42 2026 +0000
URL:        https://gitweb.gentoo.org/proj/pkgcore/snakeoil.git/commit/?id=a831aed3

arghparse: accept space-separated option values starting with a dash

Stock argparse classifies any prefixed token that doesn't match a known
option (e.g. "-VisibilityCheck") as an unknown optional, so an option
expecting a value refuses to consume the following token and fails with
"expected one argument" unless the "--opt=value" form is used.

Override ArgumentParser._parse_optional to reclassify such single-dash
unknown tokens as plain values, which is exactly what the csv_negations
and csv_elements actions expect ("-Foo", "+Foo"). Double-dash tokens are
left untouched so genuine option typos ("--typo") keep reporting as
unrecognized arguments.

Resolves: https://github.com/pkgcore/snakeoil/issues/97
Signed-off-by: Arthur Zamarin <arthurzam <AT> gentoo.org>

 NEWS.rst                      |  5 +++++
 src/snakeoil/cli/arghparse.py | 22 +++++++++++++++++++---
 tests/cli/test_arghparse.py   | 17 +++++++++++++++--
 3 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/NEWS.rst b/NEWS.rst
index 556a36d..abcd9f0 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -5,6 +5,11 @@ Release Notes
 snakeoil 0.11.4 (unreleased)
 ----------------------------
 
+- ``snakeoil.cli.arghparse.ArgumentParser``: options now accept space-separated
+  values that start with a single dash (e.g. ``--checks -VisibilityCheck``),
+  matching the previously required ``--checks=-VisibilityCheck`` form.  Unknown
+  ``--`` options keep reporting as unrecognized arguments (Arthur Zamarin, #97)
+
 - ``snakeoil.dist.generate_man_rsts``: fix man page generation failing under
   Python 3.14 with ``TypeError: 'str' object cannot be interpreted as an
   integer``, caused by ``functools.partial`` becoming a method descriptor

diff --git a/src/snakeoil/cli/arghparse.py b/src/snakeoil/cli/arghparse.py
index cd872f1..e5ff3e3 100644
--- a/src/snakeoil/cli/arghparse.py
+++ b/src/snakeoil/cli/arghparse.py
@@ -1224,6 +1224,22 @@ class ArgumentParser(OptionalsParser, CsvActionsParser):
                 for subcmd in subcmd_modules:
                     subparsers.add_command(subcmd)
 
+    def _parse_optional(self, arg_string):
+        """Treat unknown single-dash tokens as values rather than options."""
+        result = super()._parse_optional(arg_string)
+        if result is None:
+            return result
+        option_tuples = result if isinstance(result, list) else [result]
+        # the "unknown optional" fallthrough is a lone tuple whose action is None
+        if (
+            len(option_tuples) == 1
+            and option_tuples[0][0] is None
+            and len(arg_string) >= 2
+            and arg_string[1] not in self.prefix_chars
+        ):
+            return None
+        return result
+
     def _update_desc(self, description=None, docs=None):
         """Extract the description to use.
 
@@ -1516,7 +1532,7 @@ def existent_path(value):
         raise argparse.ArgumentTypeError(f"nonexistent path: {value!r}")
     try:
         return os.path.realpath(value)
-    except EnvironmentError as e:
+    except OSError as e:
         raise ValueError(
             f"while resolving path {value!r}, encountered error: {e}"
         ) from e
@@ -1530,7 +1546,7 @@ def existent_dir(value):
         raise argparse.ArgumentTypeError(f"file already exists: {value!r}")
     try:
         return os.path.realpath(value)
-    except EnvironmentError as e:
+    except OSError as e:
         raise ValueError(
             f"while resolving path {value!r}, encountered error: {e}"
         ) from e
@@ -1543,7 +1559,7 @@ def create_dir(value):
         os.makedirs(path, exist_ok=True)
     except FileExistsError:
         raise argparse.ArgumentTypeError(f"file already exists: {value!r}")
-    except IOError as e:
+    except OSError as e:
         raise argparse.ArgumentTypeError(f"failed creating dir: {e}")
     return path
 

diff --git a/tests/cli/test_arghparse.py b/tests/cli/test_arghparse.py
index 63d37ae..a3c5e71 100644
--- a/tests/cli/test_arghparse.py
+++ b/tests/cli/test_arghparse.py
@@ -201,8 +201,21 @@ class TestArgumentParser(TestCsvActionsParser, TestOptionalsParser):
                     arghparse.ArgumentParser(quiet=True, verbose=True)
                 )
                 namespace = parser.parse_args(args)
-                assert parser.verbosity == val, "{} failed".format(args)
-                assert namespace.verbosity == val, "{} failed".format(args)
+                assert parser.verbosity == val, f"{args} failed"
+                assert namespace.verbosity == val, f"{args} failed"
+
+    def test_dashed_value(self):
+        # options should accept space-separated values starting with a single dash
+        parser = argparse_helpers.mangle_parser(arghparse.ArgumentParser())
+        parser.add_argument("-c", "--checks", action="csv_negations")
+
+        for args in (["--checks", "-a,b"], ["-c", "-a,b"], ["--checks=-a,b"]):
+            namespace = parser.parse_args(args)
+            assert namespace.checks == (["a"], ["b"]), f"{args} failed"
+
+        # unknown double-dash options are still reported as errors
+        with pytest.raises(argparse_helpers.Error):
+            parser.parse_args(["--typo"])
 
     def test_verbosity_disabled(self):
         parser = argparse_helpers.mangle_parser(
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.