Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@ Changed
parser/subcommand the option was given to. Also suggests running ``--help``
for the corresponding parser/subcommand (`#809
<https://github.com/omni-us/jsonargparse/pull/809>`__).
- The ``yaml_comments`` parameter of ``ArgumentParser.dump`` has been renamed to
``with_comments`` to allow future comments support of other formats (`#811
<https://github.com/omni-us/jsonargparse/pull/811>`__).

Deprecated
^^^^^^^^^^
- ``ArgumentParser.default_meta`` property and ``with_meta`` parameter of
``ArgumentParser.parse_*`` are deprecated and will be removed in v5.0.0.
Instead use ``.clone(with_meta=...)`` (`#810
<https://github.com/omni-us/jsonargparse/pull/810>`__).
- The ``yaml_comments`` parameter of ``ArgumentParser.dump`` is deprecated and
will be removed in v5.0.0. Use ``with_comments`` instead (`#811
<https://github.com/omni-us/jsonargparse/pull/811>`__).


v4.43.0 (2025-11-11)
Expand Down
12 changes: 6 additions & 6 deletions DOCUMENTATION.rst
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ Depending on the parse method used (see :class:`.ArgumentParser`) and how the
parser was built, some of the options above might not apply. Parsing of
environment variables must be explicitly enabled, except if using
:py:meth:`.ArgumentParser.parse_env`. If the parser does not have an
`action="config"` argument, then there is no parsing of a full config
``action="config"`` argument, then there is no parsing of a full config
environment variable or a way to provide a config file from command line.


Expand Down Expand Up @@ -755,9 +755,9 @@ If you import ``from jsonargparse import set_parsing_settings`` and then run
``set_parsing_settings(config_read_mode_fsspec_enabled=True)``, the following
functions and classes will also support loading from URLs:
:py:meth:`.ArgumentParser.parse_path`, :py:meth:`.ArgumentParser.get_defaults`
(``default_config_files`` argument), `action="config"`,
(``default_config_files`` argument), ``action="config"``,
:class:`.ActionJsonSchema`, :class:`.ActionJsonnet` and :class:`.ActionParser`.
This means that a tool that can receive a config file via `action="config"` is
This means that a tool that can receive a config file via ``action="config"`` is
able to get the content from a URL, thus something like the following would
work:

Expand Down Expand Up @@ -1338,7 +1338,7 @@ string respectively.
Serialization
-------------

Parsers that have an `action="config"` argument also include a
Parsers that have an ``action="config"`` argument also include a
``--print_config`` option. This is useful particularly for command line tools
with a large set of options to create an initial config file including all
default values. If the `ruamel.yaml <https://pypi.org/project/ruamel.yaml>`__
Expand Down Expand Up @@ -2550,7 +2550,7 @@ There is also the :py:meth:`.ArgumentParser.parse_env` function to only parse
environment variables, which might be useful for some use cases in which there
is no command line call involved.

If a parser includes an `action="config"` argument, then the environment
If a parser includes an ``action="config"`` argument, then the environment
variable for this config file will be parsed before all the other environment
variables.

Expand Down Expand Up @@ -2758,7 +2758,7 @@ following:
When using the :class:`.ActionParser` class, the value of the node in a config
file can be either the complex node itself, or the path to a file which will be
loaded and parsed with the corresponding inner parser. Naturally using
`action="config"` to parse a complete config file will parse the inner
``action="config"`` to parse a complete config file will parse the inner
nodes correctly.

Note that when adding ``inner_parser`` a title was given. In the help, the added
Expand Down
2 changes: 1 addition & 1 deletion jsonargparse/_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ def __call__(self, parser, namespace, value, option_string=None):
kwargs = {"subparser": parser, "key": None, "skip_none": False, "skip_validation": False}
valid_flags = {"": None, "skip_default": "skip_default", "skip_null": "skip_none"}
if ruamel_support:
valid_flags["comments"] = "yaml_comments"
valid_flags["comments"] = "with_comments"
if value is not None:
flags = value[0].split(",")
invalid_flags = [f for f in flags if f not in valid_flags]
Expand Down
10 changes: 6 additions & 4 deletions jsonargparse/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
argcomplete_namespace,
handle_completions,
)
from ._deprecated import ParserDeprecations, deprecated_skip_check
from ._deprecated import ParserDeprecations, deprecated_skip_check, deprecated_yaml_comments
from ._formatters import DefaultHelpFormatter, empty_help, get_env_var
from ._jsonnet import ActionJsonnet
from ._jsonschema import ActionJsonSchema
Expand Down Expand Up @@ -739,7 +739,7 @@ def dump(
skip_none: bool = True,
skip_default: bool = False,
skip_validation: bool = False,
yaml_comments: bool = False,
with_comments: bool = False,
skip_link_targets: bool = True,
**kwargs,
) -> str:
Expand All @@ -753,7 +753,7 @@ def dump(
skip_none: Whether to exclude entries whose value is None.
skip_default: Whether to exclude entries whose value is the same as the default.
skip_validation: Whether to skip parser checking.
yaml_comments: Whether to add help content as comments. ``yaml_comments=True`` implies ``format='yaml'``.
with_comments: Whether to add help content as comments. Currently only supported for ``format='yaml'``.
skip_link_targets: Whether to exclude link targets.

Returns:
Expand All @@ -762,7 +762,9 @@ def dump(
Raises:
TypeError: If any of the values of cfg is invalid according to the parser.
"""
with_comments = deprecated_yaml_comments(kwargs, with_comments)
skip_validation = deprecated_skip_check(ArgumentParser.dump, kwargs, skip_validation)

check_valid_dump_format(format)

cfg = cfg.clone(with_meta=False)
Expand All @@ -786,7 +788,7 @@ def dump(
self._dump_delete_default_entries(cfg_dict, defaults.as_dict())

with parser_context(parent_parser=self):
return dump_using_format(self, cfg_dict, "yaml_comments" if yaml_comments else format)
return dump_using_format(self, cfg_dict, dump_format=format, with_comments=with_comments)

def _dump_cleanup_actions(self, cfg, actions, dump_kwargs, prefix=""):
skip_none = dump_kwargs["skip_none"]
Expand Down
15 changes: 15 additions & 0 deletions jsonargparse/_deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,21 @@ def deprecated_skip_check(component, kwargs: dict, skip_validation: bool) -> boo
return skip_validation


def deprecated_yaml_comments(kwargs: dict, with_comments: bool) -> bool:
yaml_comments = kwargs.pop("yaml_comments", None)
if yaml_comments is not None:
deprecation_warning(
deprecated_yaml_comments,
(
"yaml_comments parameter was deprecated in v4.44.0 and will be removed in "
"v5.0.0. Instead use with_comments."
),
stacklevel=3,
)
return yaml_comments
return with_comments


ParserError = ArgumentError


Expand Down
10 changes: 8 additions & 2 deletions jsonargparse/_loaders_dumpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,16 @@ def check_valid_dump_format(dump_format: str):
raise ValueError(f'Unknown output format "{dump_format}".')


def dump_using_format(parser: ArgumentParser, data: dict, dump_format: str) -> str:
def dump_using_format(parser: ArgumentParser, data: dict, dump_format: str, with_comments: bool = False) -> str:
if dump_format == "parser_mode":
dump_format = parser.parser_mode if parser.parser_mode in dumpers else "yaml"
args = (data, parser) if dump_format == "yaml_comments" else (data,)
if with_comments:
if f"{dump_format}_comments" not in dumpers:
if dump_format == "yaml":
raise ValueError("ruamel.yaml is required for dumping YAML with comments.")
raise ValueError(f"Dumping with comments is not supported for format '{dump_format}'.")
dump_format = f"{dump_format}_comments"
args = (data, parser) if dump_format.endswith("_comments") else (data,)
dump = dumpers[dump_format](*args)
if parser.dump_header and comment_prefix.get(dump_format):
prefix = comment_prefix[dump_format]
Expand Down
18 changes: 18 additions & 0 deletions jsonargparse_tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,24 @@ def test_dump_order(parser, subtests):
assert dump == "\n".join(v + ": " + str(n) for n, v in args.items()) + "\n"


def test_dump_comments_not_supported(parser):
parser.parser_mode = "json"
parser.add_argument("--op", type=int, default=1)
cfg = parser.get_defaults()
with pytest.raises(ValueError, match="Dumping with comments is not supported for format 'json'"):
parser.dump(cfg, with_comments=True)


@skip_if_no_pyyaml
def test_dump_comments_missing_ruamel(parser):
parser.add_argument("--op", type=int, default=1)
cfg = parser.get_defaults()
with patch.dict("jsonargparse._loaders_dumpers.dumpers") as dumpers:
dumpers.pop("yaml_comments", None)
with pytest.raises(ValueError, match="ruamel.yaml is required for dumping YAML with comments"):
parser.dump(cfg, with_comments=True)


@pytest.fixture
def parser_schema_jsonnet(parser, example_parser):
parser.add_argument("--cfg", action="config")
Expand Down
13 changes: 13 additions & 0 deletions jsonargparse_tests/test_deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,19 @@ def test_DefaultHelpFormatter_yaml_comments(parser):
assert "formatter.set_yaml_argument_comment(" in source[w[-1].lineno - 1]


@pytest.mark.skipif(not ruamel_support, reason="ruamel.yaml package is required")
def test_deprecated_dump_yaml_comments_parameter(parser):
parser.add_argument("--arg", type=int, default=1, help="Description")
cfg = parser.get_defaults()
with catch_warnings(record=True) as w:
parser.dump(cfg, yaml_comments=True)
assert_deprecation_warn(
w,
message="yaml_comments parameter was deprecated in v4.44.0 and will be removed in v5.0.0",
code="parser.dump(cfg, yaml_comments=True)",
)


@dataclasses.dataclass
class ComposeA:
a: int = 1
Expand Down
Loading