Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ Fixed
- A positional-only parameter that has a default being required, even though
the call can omit it (`#986
<https://github.com/mauvilsa/jsonargparse/pull/986>`__).
- Parse errors logged multiple times when raised from a nested parse, e.g. an
invalid value in a config given as argument (`#989
<https://github.com/mauvilsa/jsonargparse/pull/989>`__).

Changed
^^^^^^^
Expand Down
4 changes: 3 additions & 1 deletion DOCUMENTATION.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3662,7 +3662,9 @@ When a parse method fails, by default it prints a short message and exits with a
non-zero code. During development this is not enough information to find the
root of the problem. Setting the ``JSONARGPARSE_DEBUG`` environment variable to
``true`` changes this, without touching the source code: an
:class:`.ArgumentError` is raised and the full stack trace is printed.
:class:`.ArgumentError` is raised, the full stack trace is printed and parsers
without a logger log at debug level. Debug logs can include the raw input given
to parsers, secrets included, so only enable them for troubleshooting.

The parsers log some basic events, though this is disabled by default. To enable
it, set the ``logger`` argument when creating an :class:`.ArgumentParser`. The
Expand Down
4 changes: 3 additions & 1 deletion jsonargparse/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1201,7 +1201,9 @@
error = argument_error(message)
if source is not None:
error.value_source_reported = True # type: ignore[attr-defined] # so that it is not added again
self._logger.error(message)
if not getattr(ex, "error_logged", False): # a nested error was already logged
self._logger.error(message)
Comment thread
mauvilsa marked this conversation as resolved.
Dismissed
Comment thread
mauvilsa marked this conversation as resolved.
error.error_logged = True # type: ignore[attr-defined]
if not self.exit_on_error:
raise error from ex
elif debug_mode_active():
Expand Down
9 changes: 9 additions & 0 deletions jsonargparse_tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,15 @@ def test_debug_environment_variable(logger):
assert "Debug enabled, thus raising exception instead of exit" in logs.getvalue()


def test_nested_error_logged_once(logger):
parser = ArgumentParser(exit_on_error=False, logger=logger)
parser.add_argument("--cfg", action="config")
parser.add_argument("--int", type=int)
with pytest.raises(ArgumentError), capture_logs(logger) as logs:
parser.parse_args(["--cfg", '{"int": "invalid"}'])
assert 1 == logs.getvalue().count('Parser key "int"')


def test_parse_known_args_not_implemented(parser):
pytest.raises(NotImplementedError, lambda: parser.parse_known_args([]))

Expand Down
Loading