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(