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
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ Deprecated
- ``Path.__call__`` is deprecated and will be removed in v5.0.0. Use the
``absolute`` or ``relative`` properties instead (`#794
<https://github.com/omni-us/jsonargparse/pull/794>`__).
- ``strip_meta`` is deprecated and will be removed in v5.0.0. Instead use
``.clone(with_meta=False)`` (`#795
<https://github.com/omni-us/jsonargparse/pull/795>`__).


v4.42.0 (2025-10-14)
Expand Down
12 changes: 6 additions & 6 deletions jsonargparse/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@
is_meta_key,
patch_namespace,
recreate_branches,
remove_meta,
split_key,
split_key_leaf,
split_key_root,
strip_meta,
)
from ._optionals import (
_get_config_read_mode,
Expand Down Expand Up @@ -393,7 +393,7 @@ def _parse_common(
self.validate(cfg, skip_required=skip_required)

if not (with_meta or (with_meta is None and self._default_meta)):
cfg = strip_meta(cfg)
cfg = cfg.clone(with_meta=False)

return cfg

Expand Down Expand Up @@ -793,7 +793,7 @@ def dump(
skip_validation = deprecated_skip_check(ArgumentParser.dump, kwargs, skip_validation)
check_valid_dump_format(format)

cfg = strip_meta(cfg)
cfg = cfg.clone(with_meta=False)

with parser_context(load_value_mode=self.parser_mode):
if not skip_validation:
Expand Down Expand Up @@ -926,7 +926,7 @@ def check_overwrite(path):

if not skip_validation:
with parser_context(load_value_mode=self.parser_mode):
self.validate(strip_meta(cfg), branch=branch)
self.validate(cfg.clone(with_meta=False), branch=branch)

ActionLink.strip_link_target_keys(self, cfg)

Expand All @@ -937,7 +937,7 @@ def is_path_action(key):
def save_path(val):
val_path = Path(os.path.basename(val["__path__"].absolute), mode="fc")
check_overwrite(val_path)
val_out = strip_meta(val)
val_out = remove_meta(val)
if isinstance(val, Namespace):
val_out = val_out.as_dict()
if "__orig__" in val:
Expand Down Expand Up @@ -1258,7 +1258,7 @@ def instantiate_classes(
order = ActionLink.instantiation_order(self)
components = ActionLink.reorder(order, components)

cfg = strip_meta(cfg)
cfg = cfg.clone(with_meta=False)
for component in components:
ActionLink.apply_instantiation_links(self, cfg, target=component.dest)
if isinstance(component, ActionTypeHint):
Expand Down
24 changes: 23 additions & 1 deletion jsonargparse/_deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from importlib import import_module
from pathlib import Path
from types import ModuleType
from typing import Any, Callable, Dict, Optional, Set
from typing import Any, Callable, Dict, Optional, Set, overload

from ._common import Action, null_logger
from ._common import LoggerProperty as InternalLoggerProperty
Expand All @@ -32,6 +32,7 @@
"set_docstring_parse_options",
"set_config_read_mode",
"set_url_support",
"strip_meta",
"usage_and_exit_error_handler",
]

Expand Down Expand Up @@ -705,6 +706,27 @@
return namespace.clone().as_dict()


@overload
def strip_meta(cfg: "Namespace") -> "Namespace": ... # pragma: no cover
Comment thread Dismissed


@overload
def strip_meta(cfg: Dict[str, Any]) -> Dict[str, Any]: ... # pragma: no cover
Comment thread Dismissed


@deprecated(
"""
strip_meta was deprecated in v4.43.0 and will be removed in v5.0.0.
Instead use ``.clone(with_meta=False)``.
"""
)
def strip_meta(cfg):
"""Removes all metadata keys from a configuration object."""
from ._namespace import remove_meta

return remove_meta(cfg)


class HelpFormatterDeprecations:
"""Helper class for DefaultHelpFormatter deprecations. Will be removed in v5.0.0."""

Expand Down
4 changes: 2 additions & 2 deletions jsonargparse/_jsonschema.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from ._actions import _is_action_value_list
from ._common import Action, parser_context
from ._loaders_dumpers import get_loader_exceptions, load_value
from ._namespace import strip_meta
from ._namespace import remove_meta
from ._optionals import (
get_jsonschema_exceptions,
import_jsonschema,
Expand Down Expand Up @@ -73,7 +73,7 @@ def __call__(self, *args, **kwargs):
return class_type(**kwargs)
val = self._check_type(args[2])
if not self._with_meta:
val = strip_meta(val)
val = remove_meta(val)
setattr(args[1], self.dest, val)
return None

Expand Down
30 changes: 8 additions & 22 deletions jsonargparse/_namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@
Set,
Tuple,
Union,
overload,
)

__all__ = [
"Namespace",
"dict_to_namespace",
"strip_meta",
]


Expand Down Expand Up @@ -48,23 +46,7 @@ def is_meta_key(key: str) -> bool:
return leaf_key in meta_keys


@overload
def strip_meta(cfg: "Namespace") -> "Namespace": ... # pragma: no cover


@overload
def strip_meta(cfg: Dict[str, Any]) -> Dict[str, Any]: ... # pragma: no cover


def strip_meta(cfg):
"""Removes all metadata keys from a configuration object.

Args:
cfg: The configuration object to strip.

Returns:
A copy of the configuration object excluding all metadata keys.
"""
def remove_meta(cfg: Union["Namespace", dict]):
if cfg:
cfg = recreate_branches(cfg, skip_keys=meta_keys)
return cfg
Expand Down Expand Up @@ -275,9 +257,13 @@ def get_sorted_keys(self, branches: bool = True, key_filter: Callable = is_meta_
keys.sort(key=lambda x: -len(split_key(x)))
return keys

def clone(self) -> "Namespace":
"""Creates an new identical nested namespace."""
return recreate_branches(self)
def clone(self, with_meta: bool = True) -> "Namespace":
"""Creates an new copy of the nested namespace.

Args:
with_meta: Whether to include metadata keys in the copy.
"""
return recreate_branches(self, skip_keys=None if with_meta else meta_keys)

def update(
self, value: Union["Namespace", Any], key: Optional[str] = None, only_unset: bool = False
Expand Down
3 changes: 1 addition & 2 deletions jsonargparse_tests/test_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
ArgumentError,
ArgumentParser,
Namespace,
strip_meta,
)
from jsonargparse_tests.conftest import get_parser_help, json_or_yaml_dump

Expand Down Expand Up @@ -238,7 +237,7 @@ def test_action_parser_parse_path(composed_parsers):
cfg = parser.parse_path(yaml_main)
assert "inner2.yaml" == str(cfg.inner2.__path__)
assert "inner3.yaml" == str(cfg.inner2.inner3.__path__)
assert expected == strip_meta(cfg).as_dict()
assert expected == cfg.clone(with_meta=False).as_dict()

yaml_main2 = yaml_main.parent / "main2.yaml"
yaml_main2.write_text(parser.dump(cfg))
Expand Down
3 changes: 1 addition & 2 deletions jsonargparse_tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
ArgumentParser,
Namespace,
set_parsing_settings,
strip_meta,
)
from jsonargparse._formatters import get_env_var
from jsonargparse._namespace import NSKeyError
Expand Down Expand Up @@ -667,7 +666,7 @@ def rm_out_files():

with subtests.test("parse_path with metadata"):
cfg1 = parser.parse_path(main_file_in, with_meta=True)
assert expected == strip_meta(cfg1)
assert expected == cfg1.clone(with_meta=False)
assert str(cfg1.subparser["__path__"]) == "subparser.yaml"
if jsonschema_support:
assert str(cfg1.schema["__path__"]) == "schema.json"
Expand Down
15 changes: 15 additions & 0 deletions jsonargparse_tests/test_deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
deprecation_warning,
namespace_to_dict,
shown_deprecation_warnings,
strip_meta,
usage_and_exit_error_handler,
)
from jsonargparse._formatters import DefaultHelpFormatter
Expand Down Expand Up @@ -757,6 +758,20 @@ def test_namespace_to_dict():
)


def test_strip_meta():
ns = Namespace(x=1, __path__="path")
with catch_warnings(record=True) as w:
result = strip_meta(ns)
assert result == Namespace(x=1)
assert_deprecation_warn(
w,
message="strip_meta was deprecated",
code="result = strip_meta(ns)",
)
result = strip_meta(ns.as_dict())
assert result == {"x": 1}


@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")
Expand Down
7 changes: 3 additions & 4 deletions jsonargparse_tests/test_jsonnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
ActionJsonSchema,
ArgumentError,
ArgumentParser,
strip_meta,
)
from jsonargparse._optionals import jsonnet_support, pyyaml_available
from jsonargparse_tests.conftest import (
Expand Down Expand Up @@ -188,19 +187,19 @@ def test_action_jsonnet_save_config_metadata(parser, tmp_path):
# parse using saved config and verify result is the same
cfg2 = parser.parse_args([f"--cfg={output_config}"])
cfg2.cfg = None
assert strip_meta(cfg) == strip_meta(cfg2)
assert cfg.clone(with_meta=False) == cfg2.clone(with_meta=False)

# save the config without metadata and verify it is saved as a single file
output_config.unlink()
output_jsonnet.unlink()
parser.save(strip_meta(cfg), output_config)
parser.save(cfg.clone(with_meta=False), output_config)
assert output_config.is_file()
assert not output_jsonnet.is_file()

# parse using saved config and verify result is the same
cfg3 = parser.parse_args([f"--cfg={output_config}"])
cfg3.cfg = None
assert strip_meta(cfg) == strip_meta(cfg3)
assert cfg.clone(with_meta=False) == cfg3.clone(with_meta=False)


@skip_if_jsonschema_unavailable
Expand Down
3 changes: 1 addition & 2 deletions jsonargparse_tests/test_signatures.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
ArgumentError,
Namespace,
lazy_instance,
strip_meta,
)
from jsonargparse._actions import _find_action
from jsonargparse._optionals import docstring_parser_support
Expand Down Expand Up @@ -685,7 +684,7 @@ def test_add_function_group_config_within_config(parser, tmp_cwd):

cfg = parser.parse_args([f"--cfg={cfg_path}"])
assert str(cfg.func.__path__) == str(subcfg_path)
assert strip_meta(cfg.func) == Namespace(a1="one", a2=2.0, a3=True, a4=None)
assert cfg.func.clone(with_meta=False) == Namespace(a1="one", a2=2.0, a3=True, a4=None)


def func_param_conflict(p1: int, cfg: dict):
Expand Down
3 changes: 1 addition & 2 deletions jsonargparse_tests/test_subcommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
ArgumentError,
ArgumentParser,
Namespace,
strip_meta,
)
from jsonargparse_tests.conftest import (
get_parse_args_stderr,
Expand Down Expand Up @@ -258,7 +257,7 @@ def test_subcommand_required_arg_in_default_config(parser, subparser, tmp_cwd):
subcommands.add_subcommand("prepare", subparser)
cfg = parser.parse_args([])
assert str(cfg.__default_config__) == "config.yaml"
assert strip_meta(cfg) == Namespace(output="test", prepare=Namespace(media="test"), subcommand="prepare")
assert cfg.clone(with_meta=False) == Namespace(output="test", prepare=Namespace(media="test"), subcommand="prepare")


class SubModel:
Expand Down