Skip to content

Commit 64b3ad5

Browse files
committed
Some cleanup
1 parent f5531bd commit 64b3ad5

7 files changed

Lines changed: 130 additions & 95 deletions

File tree

CHANGELOG.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,22 @@ The semantic versioning only considers the public API as described in
1212
paths are considered internals and can change in minor and patch releases.
1313

1414

15+
v4.41.0 (2025-08-??)
16+
--------------------
17+
18+
Changed
19+
^^^^^^^
20+
- ``YAML`` comments feature is now implemented in a separate class to allow
21+
better support for custom help formatters without breaking the comments (`#754
22+
<https://github.com/omni-us/jsonargparse/pull/754>`__).
23+
24+
Deprecated
25+
^^^^^^^^^^
26+
- ``DefaultHelpFormatter.*_yaml*_comment*`` methods are deprecated and will be
27+
removed in v5.0.0. Instead use the new class ``YAMLCommentFormatter`` (`#754
28+
<https://github.com/omni-us/jsonargparse/pull/754>`__).
29+
30+
1531
v4.40.2 (2025-08-06)
1632
--------------------
1733

jsonargparse/_actions.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from ._common import Action, is_subclass, parser_context
1313
from ._loaders_dumpers import get_loader_exceptions, load_value
1414
from ._namespace import Namespace, NSKeyError, split_key, split_key_root
15-
from ._optionals import _get_config_read_mode
15+
from ._optionals import _get_config_read_mode, ruyaml_support
1616
from ._type_checking import ActionsContainer, ArgumentParser
1717
from ._util import (
1818
Path,
@@ -251,13 +251,16 @@ def __init__(
251251
help=(
252252
"Print the configuration after applying all other arguments and exit. The optional "
253253
"flags customizes the output and are one or more keywords separated by comma. The "
254-
"supported flags are: comments, skip_default, skip_null."
255-
),
254+
"supported flags are:%s skip_default, skip_null."
255+
)
256+
% (" comments," if ruyaml_support else ""),
256257
)
257258

258259
def __call__(self, parser, namespace, value, option_string=None):
259260
kwargs = {"subparser": parser, "key": None, "skip_none": False, "skip_validation": False}
260-
valid_flags = {"": None, "comments": "yaml_comments", "skip_default": "skip_default", "skip_null": "skip_none"}
261+
valid_flags = {"": None, "skip_default": "skip_default", "skip_null": "skip_none"}
262+
if ruyaml_support:
263+
valid_flags["comments"] = "yaml_comments"
261264
if value is not None:
262265
flags = value[0].split(",")
263266
invalid_flags = [f for f in flags if f not in valid_flags]

jsonargparse/_deprecated.py

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from ._common import Action, null_logger
1515
from ._common import LoggerProperty as InternalLoggerProperty
1616
from ._namespace import Namespace
17-
from ._type_checking import ArgumentParser
17+
from ._type_checking import ArgumentParser, ruyamlCommentedMap
1818

1919
__all__ = [
2020
"ActionEnum",
@@ -701,3 +701,70 @@ class LoggerProperty(InternalLoggerProperty):
701701
def namespace_to_dict(namespace: Namespace) -> Dict[str, Any]:
702702
"""Returns a copy of a nested namespace converted into a nested dictionary."""
703703
return namespace.clone().as_dict()
704+
705+
706+
class HelpFormatterDeprecations:
707+
def __init__(self, *args, **kwargs):
708+
from jsonargparse._formatters import YAMLCommentFormatter
709+
710+
super().__init__(*args, **kwargs)
711+
self._yaml_formatter = YAMLCommentFormatter(self)
712+
713+
@deprecated(
714+
"""
715+
The add_yaml_comments method is deprecated and will be removed in v5.0.0.
716+
Use :class:`YAMLCommentFormatter` instead.
717+
"""
718+
)
719+
def add_yaml_comments(self, cfg: str) -> str:
720+
"""Adds help text as yaml comments."""
721+
return self._yaml_formatter.add_yaml_comments(cfg)
722+
723+
@deprecated(
724+
"""
725+
The set_yaml_start_comment method is deprecated and will be removed in v5.0.0.
726+
Use :class:`YAMLCommentFormatter` instead.
727+
"""
728+
)
729+
def set_yaml_start_comment(self, text: str, cfg: ruyamlCommentedMap):
730+
"""Sets the start comment to a ruyaml object.
731+
732+
Args:
733+
text: The content to use for the comment.
734+
cfg: The ruyaml object.
735+
"""
736+
self._yaml_formatter.set_yaml_start_comment(text, cfg)
737+
738+
@deprecated(
739+
"""
740+
The set_yaml_group_comment method is deprecated and will be removed in v5.0.0.
741+
Use :class:`YAMLCommentFormatter` instead.
742+
"""
743+
)
744+
def set_yaml_group_comment(self, text: str, cfg: ruyamlCommentedMap, key: str, depth: int):
745+
"""Sets the comment for a group to a ruyaml object.
746+
747+
Args:
748+
text: The content to use for the comment.
749+
cfg: The parent ruyaml object.
750+
key: The key of the group.
751+
depth: The nested level of the group.
752+
"""
753+
self._yaml_formatter.set_yaml_group_comment(text, cfg, key, depth)
754+
755+
@deprecated(
756+
"""
757+
The set_yaml_argument_comment method is deprecated and will be removed in v5.0.0.
758+
Use :class:`YAMLCommentFormatter` instead.
759+
"""
760+
)
761+
def set_yaml_argument_comment(self, text: str, cfg: ruyamlCommentedMap, key: str, depth: int):
762+
"""Sets the comment for an argument to a ruyaml object.
763+
764+
Args:
765+
text: The content to use for the comment.
766+
cfg: The parent ruyaml object.
767+
key: The key of the argument.
768+
depth: The nested level of the argument.
769+
"""
770+
self._yaml_formatter.set_yaml_argument_comment(text, cfg, key, depth)

jsonargparse/_formatters.py

Lines changed: 5 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
supports_optionals_as_positionals,
3131
)
3232
from ._completions import ShtabAction
33-
from ._deprecated import deprecated
33+
from ._deprecated import HelpFormatterDeprecations
3434
from ._link_arguments import ActionLink
3535
from ._namespace import Namespace, NSKeyError
3636
from ._optionals import import_ruyaml
@@ -119,7 +119,7 @@ def set_comments(cfg, prefix="", depth=0):
119119
def set_yaml_start_comment(
120120
self,
121121
text: str,
122-
cfg: "ruyamlCommentedMap",
122+
cfg: ruyamlCommentedMap,
123123
):
124124
"""Sets the start comment to a ruyaml object.
125125
@@ -132,7 +132,7 @@ def set_yaml_start_comment(
132132
def set_yaml_group_comment(
133133
self,
134134
text: str,
135-
cfg: "ruyamlCommentedMap",
135+
cfg: ruyamlCommentedMap,
136136
key: str,
137137
depth: int,
138138
):
@@ -149,7 +149,7 @@ def set_yaml_group_comment(
149149
def set_yaml_argument_comment(
150150
self,
151151
text: str,
152-
cfg: "ruyamlCommentedMap",
152+
cfg: ruyamlCommentedMap,
153153
key: str,
154154
depth: int,
155155
):
@@ -164,7 +164,7 @@ def set_yaml_argument_comment(
164164
cfg.yaml_set_comment_before_after_key(key, before="\n" + text, indent=2 * depth)
165165

166166

167-
class DefaultHelpFormatter(HelpFormatter):
167+
class DefaultHelpFormatter(HelpFormatterDeprecations, HelpFormatter):
168168
"""Help message formatter that includes types, default values and env var names.
169169
170170
This class is an extension of `argparse.HelpFormatter
@@ -174,69 +174,6 @@ class DefaultHelpFormatter(HelpFormatter):
174174
the respective environment variable name is included preceded by 'ENV:'.
175175
"""
176176

177-
def __init__(self, *args, **kwargs):
178-
super().__init__(*args, **kwargs)
179-
self._yaml_formatter = YAMLCommentFormatter(self)
180-
181-
@deprecated(
182-
"""
183-
The add_yaml_comments method is deprecated and will be removed in a future version.
184-
Use :class:`YAMLCommentFormatter` instead.
185-
"""
186-
)
187-
def add_yaml_comments(self, cfg: str) -> str:
188-
"""Adds help text as yaml comments."""
189-
return self._yaml_formatter.add_yaml_comments(cfg)
190-
191-
@deprecated(
192-
"""
193-
The set_yaml_start_comment method is deprecated and will be removed in a future version.
194-
Use :class:`YAMLCommentFormatter` instead.
195-
"""
196-
)
197-
def set_yaml_start_comment(self, text: str, cfg: "ruyamlCommentedMap"):
198-
"""Sets the start comment to a ruyaml object.
199-
200-
Args:
201-
text: The content to use for the comment.
202-
cfg: The ruyaml object.
203-
"""
204-
self._yaml_formatter.set_yaml_start_comment(text, cfg)
205-
206-
@deprecated(
207-
"""
208-
The set_yaml_group_comment method is deprecated and will be removed in a future version.
209-
Use :class:`YAMLCommentFormatter` instead.
210-
"""
211-
)
212-
def set_yaml_group_comment(self, text: str, cfg: "ruyamlCommentedMap", key: str, depth: int):
213-
"""Sets the comment for a group to a ruyaml object.
214-
215-
Args:
216-
text: The content to use for the comment.
217-
cfg: The parent ruyaml object.
218-
key: The key of the group.
219-
depth: The nested level of the group.
220-
"""
221-
self._yaml_formatter.set_yaml_group_comment(text, cfg, key, depth)
222-
223-
@deprecated(
224-
"""
225-
The set_yaml_argument_comment method is deprecated and will be removed in a future version.
226-
Use :class:`YAMLCommentFormatter` instead.
227-
"""
228-
)
229-
def set_yaml_argument_comment(self, text: str, cfg: "ruyamlCommentedMap", key: str, depth: int):
230-
"""Sets the comment for an argument to a ruyaml object.
231-
232-
Args:
233-
text: The content to use for the comment.
234-
cfg: The parent ruyaml object.
235-
key: The key of the argument.
236-
depth: The nested level of the argument.
237-
"""
238-
self._yaml_formatter.set_yaml_argument_comment(text, cfg, key, depth)
239-
240177
def _get_help_string(self, action: Action) -> str:
241178
action_help = " " if action.help == empty_help else action.help
242179
assert isinstance(action_help, str)

jsonargparse/_loaders_dumpers.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,19 @@
22

33
import inspect
44
import re
5+
from argparse import HelpFormatter
56
from contextlib import suppress
67
from typing import Any, Callable, Dict, Optional, Set, Tuple, Type
78

89
from ._common import load_value_mode, parent_parser
9-
from ._optionals import import_jsonnet, import_toml_dumps, import_toml_loads, omegaconf_support, pyyaml_available
10+
from ._optionals import (
11+
import_jsonnet,
12+
import_toml_dumps,
13+
import_toml_loads,
14+
omegaconf_support,
15+
pyyaml_available,
16+
ruyaml_support,
17+
)
1018
from ._type_checking import ArgumentParser
1119

1220
__all__ = [
@@ -249,13 +257,14 @@ def toml_dump(data):
249257

250258
dumpers: Dict[str, Callable] = {
251259
"yaml": yaml_dump,
252-
"yaml_comments": yaml_comments_dump,
253260
"json": json_compact_dump,
254261
"json_compact": json_compact_dump,
255262
"json_indented": json_indented_dump,
256263
"toml": toml_dump,
257264
"jsonnet": json_indented_dump,
258265
}
266+
if ruyaml_support:
267+
dumpers["yaml_comments"] = yaml_comments_dump
259268

260269
comment_prefix: Dict[str, str] = {
261270
"yaml": "# ",
@@ -336,7 +345,7 @@ def set_omegaconf_loader():
336345
set_loader("jsonnet", jsonnet_load, get_loader_exceptions("jsonnet"))
337346

338347

339-
def create_help_formatter_with_comments(formatter_class: Type["HelpFormatter"]) -> Type["HelpFormatter"]:
348+
def create_help_formatter_with_comments(formatter_class: Type[HelpFormatter]) -> Type[HelpFormatter]:
340349
"""Creates a dynamic class that combines a formatter with YAML comment functionality.
341350
342351
Args:
@@ -347,7 +356,7 @@ def create_help_formatter_with_comments(formatter_class: Type["HelpFormatter"])
347356
"""
348357
from ._formatters import YAMLCommentFormatter
349358

350-
class DynamicHelpFormatter(formatter_class):
359+
class DynamicHelpFormatter(formatter_class): # type: ignore[valid-type,misc]
351360
def __init__(self, *args, **kwargs):
352361
super().__init__(*args, **kwargs)
353362
self._yaml_formatter = YAMLCommentFormatter(self)

jsonargparse_tests/test_core.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,12 +759,22 @@ def test_print_config_skip_null(print_parser):
759759
@pytest.mark.skipif(not ruyaml_support, reason="ruyaml package is required")
760760
@skip_if_docstring_parser_unavailable
761761
def test_print_config_comments(print_parser):
762+
help_str = get_parser_help(print_parser)
763+
assert "comments," in help_str
762764
out = get_parse_args_stdout(print_parser, ["--print_config=comments"])
763765
assert "# cli tool" in out
764766
assert "# Option v1. (default: 1)" in out
765767
assert "# Option v2. (default: 2)" in out
766768

767769

770+
@pytest.mark.skipif(ruyaml_support, reason="ruyaml package should not be installed")
771+
def test_print_config_comments_unavailable(print_parser):
772+
help_str = get_parser_help(print_parser)
773+
assert "comments," not in help_str
774+
with pytest.raises(ArgumentError, match='Invalid option "comments"'):
775+
get_parse_args_stdout(print_parser, ["--print_config=comments"])
776+
777+
768778
def test_print_config_invalid_flag(print_parser):
769779
with pytest.raises(ArgumentError) as ctx:
770780
print_parser.parse_args(["--print_config=invalid"])

jsonargparse_tests/test_deprecated.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import_ruyaml,
4545
jsonnet_support,
4646
pyyaml_available,
47+
ruyaml_support,
4748
url_support,
4849
)
4950
from jsonargparse._util import argument_error
@@ -730,8 +731,8 @@ def test_namespace_to_dict():
730731
)
731732

732733

733-
def test_DefaultHelpFormatter_yaml_comments():
734-
parser = ArgumentParser()
734+
@pytest.mark.skipif(not ruyaml_support, reason="ruyaml package is required")
735+
def test_DefaultHelpFormatter_yaml_comments(parser):
735736
parser.add_argument("--arg", type=int, help="Description")
736737
formatter = DefaultHelpFormatter(prog="test")
737738
from jsonargparse._common import parent_parser
@@ -743,32 +744,24 @@ def test_DefaultHelpFormatter_yaml_comments():
743744

744745
with catch_warnings(record=True) as w:
745746
formatter.add_yaml_comments("arg: 1")
746-
assert "The add_yaml_comments method is deprecated and will be removed in a future version. Use" in str(
747-
w[-1].message
748-
)
749-
assert ":class:`YAMLCommentFormatter` instead" in str(w[-1].message)
747+
assert "add_yaml_comments method is deprecated and will be removed in v5.0.0" in str(w[-1].message)
748+
assert ":class:`YAMLCommentFormatter`" in str(w[-1].message)
750749
assert "formatter.add_yaml_comments(" in source[w[-1].lineno - 1]
751750

752751
with catch_warnings(record=True) as w:
753752
formatter.set_yaml_start_comment("start", cfg)
754-
assert "The set_yaml_start_comment method is deprecated and will be removed in a future version. Use" in str(
755-
w[-1].message
756-
)
757-
assert ":class:`YAMLCommentFormatter` instead" in str(w[-1].message)
753+
assert "set_yaml_start_comment method is deprecated and will be removed in v5.0.0" in str(w[-1].message)
754+
assert ":class:`YAMLCommentFormatter`" in str(w[-1].message)
758755
assert "formatter.set_yaml_start_comment(" in source[w[-1].lineno - 1]
759756

760757
with catch_warnings(record=True) as w:
761758
formatter.set_yaml_group_comment("group", cfg, "arg", 0)
762-
assert "The set_yaml_group_comment method is deprecated and will be removed in a future version. Use" in str(
763-
w[-1].message
764-
)
765-
assert ":class:`YAMLCommentFormatter` instead" in str(w[-1].message)
759+
assert "set_yaml_group_comment method is deprecated and will be removed in v5.0.0" in str(w[-1].message)
760+
assert ":class:`YAMLCommentFormatter`" in str(w[-1].message)
766761
assert "formatter.set_yaml_group_comment(" in source[w[-1].lineno - 1]
767762

768763
with catch_warnings(record=True) as w:
769764
formatter.set_yaml_argument_comment("arg", cfg, "arg", 0)
770-
assert "The set_yaml_argument_comment method is deprecated and will be removed in a future version. Use" in str(
771-
w[-1].message
772-
)
773-
assert ":class:`YAMLCommentFormatter` instead" in str(w[-1].message)
765+
assert "set_yaml_argument_comment method is deprecated and will be removed in v5.0.0" in str(w[-1].message)
766+
assert ":class:`YAMLCommentFormatter`" in str(w[-1].message)
774767
assert "formatter.set_yaml_argument_comment(" in source[w[-1].lineno - 1]

0 commit comments

Comments
 (0)