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
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,18 @@ Changed
- ``YAML`` comments feature is now implemented in a separate class to allow
better support for custom help formatters without breaking the comments (`#754
<https://github.com/omni-us/jsonargparse/pull/754>`__).
- Replaced unmaintained optional dependency ``ruyaml`` with ``ruamel.yaml``
(`#768 <https://github.com/omni-us/jsonargparse/pull/768>`__).

Deprecated
^^^^^^^^^^
- ``DefaultHelpFormatter.*_yaml*_comment*`` methods are deprecated and will be
removed in v5.0.0. This logic has been moved to a new private class
``YAMLCommentFormatter``. If deemed necessary, this class might be made public
in the future (`#754 <https://github.com/omni-us/jsonargparse/pull/754>`__).
- The ``ruyaml`` optional dependency is deprecated and will be removed in
v5.0.0. Instead use the ``ruamel`` optional dependency (`#768
<https://github.com/omni-us/jsonargparse/pull/768>`__).


v4.40.2 (2025-08-06)
Expand Down
6 changes: 3 additions & 3 deletions DOCUMENTATION.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1321,9 +1321,9 @@ Serialization
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 `ruyaml <https://ruyaml.readthedocs.io>`__ package is
installed, the config can be printed having the help descriptions content as
YAML comments by using ``--print_config=comments``. Another option is
default values. If the `ruamel.yaml <https://pypi.org/project/ruamel.yaml>`__
package is installed, the config can be printed having the help descriptions
content as YAML comments by using ``--print_config=comments``. Another option is
``--print_config=skip_null`` which skips entries whose value is ``null``.

From within Python it is also possible to serialize a config object by using
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ By default, the only dependency installed with ``jsonargparse`` is `PyYAML
<https://pypi.org/project/PyYAML/>`__. However, several optional features can be
enabled by specifying one or more of the following extras (optional
dependencies): ``signatures``, ``jsonschema``, ``jsonnet``, ``urls``,
``fsspec``, ``toml``, ``ruyaml``, ``omegaconf``, ``shtab``, and ``argcomplete``.
``fsspec``, ``toml``, ``ruamel``, ``omegaconf``, ``shtab``, and ``argcomplete``.
Additionally, the ``all`` extras can be used to enable all optional features
(excluding tab completion ones). To install ``jsonargparse`` with extras, use
the following syntax:
Expand Down
6 changes: 3 additions & 3 deletions jsonargparse/_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from ._common import Action, is_subclass, parser_context
from ._loaders_dumpers import get_loader_exceptions, load_value
from ._namespace import Namespace, NSKeyError, split_key, split_key_root
from ._optionals import _get_config_read_mode, ruyaml_support
from ._optionals import _get_config_read_mode, ruamel_support
from ._type_checking import ActionsContainer, ArgumentParser
from ._util import (
Path,
Expand Down Expand Up @@ -254,13 +254,13 @@ def __init__(
"flags customizes the output and are one or more keywords separated by comma. The "
"supported flags are:%s skip_default, skip_null."
)
% (" comments," if ruyaml_support else ""),
% (" comments," if ruamel_support else ""),
)

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 ruyaml_support:
if ruamel_support:
valid_flags["comments"] = "yaml_comments"
if value is not None:
flags = value[0].split(",")
Expand Down
20 changes: 10 additions & 10 deletions jsonargparse/_deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from ._common import Action, null_logger
from ._common import LoggerProperty as InternalLoggerProperty
from ._namespace import Namespace
from ._type_checking import ArgumentParser, ruyamlCommentedMap
from ._type_checking import ArgumentParser, ruamelCommentedMap

__all__ = [
"ActionEnum",
Expand Down Expand Up @@ -711,34 +711,34 @@ def add_yaml_comments(self, cfg: str) -> str:
return self._yaml_formatter.add_yaml_comments(cfg)

@deprecated("The set_yaml_start_comment method is deprecated and will be removed in v5.0.0.")
def set_yaml_start_comment(self, text: str, cfg: ruyamlCommentedMap):
"""Sets the start comment to a ruyaml object.
def set_yaml_start_comment(self, text: str, cfg: ruamelCommentedMap):
"""Sets the start comment to a ruamel.yaml object.

Args:
text: The content to use for the comment.
cfg: The ruyaml object.
cfg: The ruamel.yaml object.
"""
self._yaml_formatter.set_yaml_start_comment(text, cfg)

@deprecated("The set_yaml_group_comment method is deprecated and will be removed in v5.0.0.")
def set_yaml_group_comment(self, text: str, cfg: ruyamlCommentedMap, key: str, depth: int):
"""Sets the comment for a group to a ruyaml object.
def set_yaml_group_comment(self, text: str, cfg: ruamelCommentedMap, key: str, depth: int):
"""Sets the comment for a group to a ruamel.yaml object.

Args:
text: The content to use for the comment.
cfg: The parent ruyaml object.
cfg: The parent ruamel.yaml object.
key: The key of the group.
depth: The nested level of the group.
"""
self._yaml_formatter.set_yaml_group_comment(text, cfg, key, depth)

@deprecated("The set_yaml_argument_comment method is deprecated and will be removed in v5.0.0.")
def set_yaml_argument_comment(self, text: str, cfg: ruyamlCommentedMap, key: str, depth: int):
"""Sets the comment for an argument to a ruyaml object.
def set_yaml_argument_comment(self, text: str, cfg: ruamelCommentedMap, key: str, depth: int):
"""Sets the comment for an argument to a ruamel.yaml object.

Args:
text: The content to use for the comment.
cfg: The parent ruyaml object.
cfg: The parent ruamel.yaml object.
key: The key of the argument.
depth: The nested level of the argument.
"""
Expand Down
24 changes: 12 additions & 12 deletions jsonargparse/_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
from ._deprecated import HelpFormatterDeprecations
from ._link_arguments import ActionLink
from ._namespace import Namespace, NSKeyError
from ._optionals import import_ruyaml
from ._type_checking import ArgumentParser, ruyamlCommentedMap
from ._optionals import import_ruamel
from ._type_checking import ArgumentParser, ruamelCommentedMap
from ._typehints import ActionTypeHint, type_to_str

__all__ = ["DefaultHelpFormatter"]
Expand Down Expand Up @@ -63,7 +63,7 @@ def __init__(self, help_formatter: HelpFormatter):

def add_yaml_comments(self, cfg: str) -> str:
"""Adds help text as yaml comments."""
ruyaml = import_ruyaml("add_yaml_comments")
ruyaml = import_ruamel("add_yaml_comments")
yaml = ruyaml.YAML()
cfg = yaml.load(cfg)

Expand Down Expand Up @@ -119,28 +119,28 @@ def set_comments(cfg, prefix="", depth=0):
def set_yaml_start_comment(
self,
text: str,
cfg: ruyamlCommentedMap,
cfg: ruamelCommentedMap,
):
"""Sets the start comment to a ruyaml object.
"""Sets the start comment to a ruamel.yaml object.

Args:
text: The content to use for the comment.
cfg: The ruyaml object.
cfg: The ruamel.yaml object.
"""
cfg.yaml_set_start_comment(text)

def set_yaml_group_comment(
self,
text: str,
cfg: ruyamlCommentedMap,
cfg: ruamelCommentedMap,
key: str,
depth: int,
):
"""Sets the comment for a group to a ruyaml object.
"""Sets the comment for a group to a ruamel.yaml object.

Args:
text: The content to use for the comment.
cfg: The parent ruyaml object.
cfg: The parent ruamel.yaml object.
key: The key of the group.
depth: The nested level of the group.
"""
Expand All @@ -149,15 +149,15 @@ def set_yaml_group_comment(
def set_yaml_argument_comment(
self,
text: str,
cfg: ruyamlCommentedMap,
cfg: ruamelCommentedMap,
key: str,
depth: int,
):
"""Sets the comment for an argument to a ruyaml object.
"""Sets the comment for an argument to a ruamel.yaml object.

Args:
text: The content to use for the comment.
cfg: The parent ruyaml object.
cfg: The parent ruamel.yaml object.
key: The key of the argument.
depth: The nested level of the argument.
"""
Expand Down
4 changes: 2 additions & 2 deletions jsonargparse/_loaders_dumpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import_toml_loads,
omegaconf_support,
pyyaml_available,
ruyaml_support,
ruamel_support,
)
from ._type_checking import ArgumentParser

Expand Down Expand Up @@ -263,7 +263,7 @@ def toml_dump(data):
"toml": toml_dump,
"jsonnet": json_indented_dump,
}
if ruyaml_support:
if ruamel_support:
dumpers["yaml_comments"] = yaml_comments_dump

comment_prefix: Dict[str, str] = {
Expand Down
10 changes: 5 additions & 5 deletions jsonargparse/_optionals.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
url_support = find_spec("requests") is not None
docstring_parser_support = find_spec("docstring_parser") is not None
fsspec_support = find_spec("fsspec") is not None
ruyaml_support = find_spec("ruyaml") is not None
ruamel_support = bool(find_spec("ruamel") and find_spec("ruamel.yaml"))
omegaconf_support = find_spec("omegaconf") is not None
reconplogger_support = find_spec("reconplogger") is not None
attrs_support = find_spec("attrs") is not None
Expand Down Expand Up @@ -152,10 +152,10 @@
return fsspec


def import_ruyaml(importer):
with missing_package_raise("ruyaml", importer):
import ruyaml
return ruyaml
def import_ruamel(importer):
with missing_package_raise("ruamel.yaml", importer):
import ruamel.yaml
return ruamel.yaml


def import_reconplogger(importer):
Expand Down
4 changes: 2 additions & 2 deletions jsonargparse/_type_checking.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
"ActionsContainer",
"ArgumentParser",
"docstring_parser",
"ruyamlCommentedMap",
"ruamelCommentedMap",
]

if TYPE_CHECKING: # pragma: no cover
import docstring_parser
from ruyaml.comments import CommentedMap as ruyamlCommentedMap
from ruamel.yaml.comments import CommentedMap as ruamelCommentedMap

from ._core import ActionsContainer, ArgumentGroup, ArgumentParser
else:
Expand Down
4 changes: 2 additions & 2 deletions jsonargparse_tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from jsonargparse import CLI, auto_cli, auto_parser, capture_parser, lazy_instance
from jsonargparse._namespace import Namespace
from jsonargparse._optionals import docstring_parser_support, ruyaml_support
from jsonargparse._optionals import docstring_parser_support, ruamel_support
from jsonargparse.typing import final
from jsonargparse_tests.conftest import json_or_yaml_dump, json_or_yaml_load, skip_if_docstring_parser_unavailable

Expand Down Expand Up @@ -351,7 +351,7 @@ def test_function_and_class_print_config_before_subcommands():


@skip_if_docstring_parser_unavailable
@pytest.mark.skipif(not ruyaml_support, reason="ruyaml not installed")
@pytest.mark.skipif(not ruamel_support, reason="ruamel.yaml package is required")
def test_function_and_class_print_config_comments():
out = get_cli_stdout([cmd1, Cmd2, cmd3], args=["--print_config=comments", "Cmd2", "method2"])
assert "# Description of Cmd2" in out
Expand Down
6 changes: 3 additions & 3 deletions jsonargparse_tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
)
from jsonargparse._formatters import get_env_var
from jsonargparse._namespace import NSKeyError
from jsonargparse._optionals import jsonnet_support, jsonschema_support, pyyaml_available, ruyaml_support
from jsonargparse._optionals import jsonnet_support, jsonschema_support, pyyaml_available, ruamel_support
from jsonargparse.typing import Path_fc, Path_fr, path_type
from jsonargparse_tests.conftest import (
capture_logs,
Expand Down Expand Up @@ -779,7 +779,7 @@ def test_print_config_skip_null(print_parser):
assert json_or_yaml_load(out) == {"g1": {"v2": "2"}, "g2": {}, "v1": 1}


@pytest.mark.skipif(not ruyaml_support, reason="ruyaml package is required")
@pytest.mark.skipif(not ruamel_support, reason="ruamel.yaml package is required")
@skip_if_docstring_parser_unavailable
def test_print_config_comments(print_parser):
help_str = get_parser_help(print_parser)
Expand All @@ -790,7 +790,7 @@ def test_print_config_comments(print_parser):
assert "# Option v2. (default: 2)" in out


@pytest.mark.skipif(ruyaml_support, reason="ruyaml package should not be installed")
@pytest.mark.skipif(ruamel_support, reason="ruamel.yaml package should not be installed")
def test_print_config_comments_unavailable(print_parser):
help_str = get_parser_help(print_parser)
assert "comments," not in help_str
Expand Down
8 changes: 4 additions & 4 deletions jsonargparse_tests/test_deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@
from jsonargparse._optionals import (
docstring_parser_support,
get_docstring_parse_options,
import_ruyaml,
import_ruamel,
jsonnet_support,
pyyaml_available,
ruyaml_support,
ruamel_support,
url_support,
)
from jsonargparse._util import argument_error
Expand Down Expand Up @@ -743,14 +743,14 @@ def test_namespace_to_dict():
)


@pytest.mark.skipif(not ruyaml_support, reason="ruyaml package is required")
@pytest.mark.skipif(not ruamel_support, reason="ruamel.yaml package is required")
def test_DefaultHelpFormatter_yaml_comments(parser):
parser.add_argument("--arg", type=int, help="Description")
formatter = DefaultHelpFormatter(prog="test")
from jsonargparse._common import parent_parser

parent_parser.set(parser)
ruyaml = import_ruyaml("test_DefaultHelpFormatter_yaml_comments")
ruyaml = import_ruamel("test_DefaultHelpFormatter_yaml_comments")
yaml = ruyaml.YAML()
cfg = yaml.load("arg: 1")

Expand Down
20 changes: 10 additions & 10 deletions jsonargparse_tests/test_optionals.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
import_jsonnet,
import_jsonschema,
import_requests,
import_ruyaml,
import_ruamel,
jsonnet_support,
jsonschema_support,
ruyaml_support,
ruamel_support,
url_support,
)
from jsonargparse.typing import is_final_class
Expand Down Expand Up @@ -126,19 +126,19 @@ def test_fsspec_support_false():
ctx.match("test_fsspec_support_false")


# ruyaml support
# ruamel.yaml support


@pytest.mark.skipif(not ruyaml_support, reason="ruyaml package is required")
def test_ruyaml_support_true():
import_ruyaml("test_ruyaml_support_true")
@pytest.mark.skipif(not ruamel_support, reason="ruamel.yaml package is required")
def test_ruamel_support_true():
import_ruamel("test_ruamel_support_true")


@pytest.mark.skipif(ruyaml_support, reason="ruyaml package should not be installed")
def test_ruyaml_support_false():
@pytest.mark.skipif(ruamel_support, reason="ruamel.yaml package should not be installed")
def test_ruamel_support_false():
with pytest.raises(ImportError) as ctx:
import_ruyaml("test_ruyaml_support_false")
ctx.match("test_ruyaml_support_false")
import_ruamel("test_ruamel_support_false")
ctx.match("test_ruamel_support_false")


# config read mode tests
Expand Down
9 changes: 6 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ all = [
"jsonargparse[toml]",
"jsonargparse[urls]",
"jsonargparse[fsspec]",
"jsonargparse[ruyaml]",
"jsonargparse[ruamel]",
"jsonargparse[omegaconf]",
"jsonargparse[typing-extensions]",
"jsonargparse[reconplogger]",
Expand Down Expand Up @@ -75,8 +75,11 @@ shtab = [
argcomplete = [
"argcomplete>=3.5.1",
]
ruamel = [
"ruamel.yaml>=0.18.15",
]
ruyaml = [
"ruyaml>=0.20.0",
"jsonargparse[ruamel]",
]
omegaconf = [
"omegaconf>=2.1.1",
Expand Down Expand Up @@ -235,7 +238,7 @@ commands =
[testenv:without-pyyaml]
extras = test,coverage,all
commands =
pip uninstall -y argcomplete omegaconf pyyaml reconplogger responses ruyaml types-PyYAML
pip uninstall -y argcomplete omegaconf pyyaml reconplogger responses ruamel.yaml ruamel.yaml.clib types-PyYAML
python -m pytest {posargs}

[testenv:without-future-annotations]
Expand Down