diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e9507a4a..5c62d1b8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,6 +30,9 @@ Fixed - While parsing, internally preserve ``class_path`` for subclass disabled types to correctly support defaults from union of dataclasses (`#921 `__). +- Misleading error message for ``parse_optionals_as_positionals=True`` and + unrecognized non-positional arguments (`#922 + `__). Changed ^^^^^^^ diff --git a/jsonargparse/_core.py b/jsonargparse/_core.py index 81601287..f4c5335d 100644 --- a/jsonargparse/_core.py +++ b/jsonargparse/_core.py @@ -314,12 +314,19 @@ def _positional_optionals(self, cfg, unk): for action in get_optionals_as_positionals_actions(self, include_positionals=True): if action.option_strings == []: - if cfg.get(action.dest) is None: + if cfg.get(action.dest) is get_parsing_setting("unset_sentinel"): self._logger.debug(f"Positional argument {action.dest} missing, aborting _positional_optionals") break continue - cfg[action.dest] = self._check_value_key(action, unk.pop(0), action.dest, cfg) + value = unk.pop(0) + try: + cfg[action.dest] = self._check_value_key(action, value, action.dest, cfg) + except (TypeError, ValueError) as ex: + if isinstance(value, str) and value.startswith("--"): + raise argument_error(f"unrecognized arguments: {' '.join([value] + unk)}") from ex + raise + if len(unk) == 0: break diff --git a/jsonargparse_tests/test_parsing_settings.py b/jsonargparse_tests/test_parsing_settings.py index 8dd581bf..ce890d49 100644 --- a/jsonargparse_tests/test_parsing_settings.py +++ b/jsonargparse_tests/test_parsing_settings.py @@ -115,6 +115,12 @@ def test_parse_optionals_as_positionals_simple(parser, logger, subtests): parser.parse_args(["--unk=x"]) assert "Positional argument p1 missing, aborting _positional_optionals" in logs.getvalue() + with subtests.test("mixed unrecognized"): + with capture_logs(logger) as logs: + with pytest.raises(ArgumentError, match="unrecognized arguments: --unexpected arg xyz"): + parser.parse_args(["p1", "3", "--unexpected", "arg", "xyz"]) + assert "unrecognized arguments: --unexpected arg xyz" in logs.getvalue() + def test_parse_optionals_as_positionals_subcommands(parser, subparser, subtests): set_parsing_settings(parse_optionals_as_positionals=True) @@ -153,6 +159,10 @@ def test_parse_optionals_as_positionals_subcommands(parser, subparser, subtests) parser.parse_args(["subcmd", "p1", "o2", "5"]) assert re.match('Parser key "o1".*Given value: o2', ex.value.message, re.DOTALL) + with subtests.test("mixed unrecognized"): + with pytest.raises(ArgumentError, match="unrecognized arguments: --unexpected=arg"): + parser.parse_args(["subcmd", "p1", "3", "--unexpected=arg"]) + def test_optionals_as_positionals_usage_wrap(parser): set_parsing_settings(parse_optionals_as_positionals=True)