Skip to content

Commit 5bfc380

Browse files
authored
dict_to_namespace is deprecated and will be removed in v5.0.0 (#797)
1 parent 6f9ea46 commit 5bfc380

File tree

5 files changed

+45
-30
lines changed

5 files changed

+45
-30
lines changed

CHANGELOG.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ Deprecated
4747
- ``compose_dataclasses`` is deprecated and will be removed in v5.0.0. There is
4848
no direct replacement, whoever is interested can copy the code (`#796
4949
<https://github.com/omni-us/jsonargparse/pull/796>`__).
50+
- ``dict_to_namespace`` is deprecated and will be removed in v5.0.0. No
51+
replacement is provided because blindly converting a dictionary to a namespace
52+
may not yield the same results as using a parser, which could lead to
53+
confusion. (`#797 <https://github.com/omni-us/jsonargparse/pull/797>`__).
5054

5155

5256
v4.42.0 (2025-10-14)

jsonargparse/_deprecated.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from importlib import import_module
1010
from pathlib import Path
1111
from types import ModuleType
12-
from typing import Any, Callable, Dict, Optional, Set, overload
12+
from typing import Any, Callable, Dict, Optional, Set, Union, overload
1313

1414
from ._common import Action, null_logger
1515
from ._common import LoggerProperty as InternalLoggerProperty
@@ -28,6 +28,7 @@
2828
"ParserError",
2929
"compose_dataclasses",
3030
"get_config_read_mode",
31+
"dict_to_namespace",
3132
"namespace_to_dict",
3233
"null_logger",
3334
"set_docstring_parse_options",
@@ -123,8 +124,6 @@ def patched_init(self, *args, parse_as_dict: bool = False, **kwargs):
123124
ArgumentParser._unpatched_init = ArgumentParser.__init__
124125
ArgumentParser.__init__ = patched_init
125126

126-
from typing import Union
127-
128127
# Patch parse methods
129128
def patch_parse_method(method_name):
130129
unpatched_method_name = "_unpatched_" + method_name
@@ -707,6 +706,21 @@ def namespace_to_dict(namespace: Namespace) -> Dict[str, Any]:
707706
return namespace.clone().as_dict()
708707

709708

709+
@deprecated(
710+
"""
711+
dict_to_namespace was deprecated in v4.43.0 and will be removed in v5.0.0.
712+
No replacement is provided because blindly converting a dictionary to a
713+
namespace may not yield the same results as using a parser, which could lead
714+
to confusion.
715+
"""
716+
)
717+
def dict_to_namespace(cfg_dict: dict[str, Any]) -> Namespace:
718+
"""Converts a nested dictionary into a nested namespace."""
719+
from ._namespace import dict_to_namespace as _dict_to_namespace
720+
721+
return _dict_to_namespace(cfg_dict)
722+
723+
710724
@overload
711725
def strip_meta(cfg: "Namespace") -> "Namespace": ... # pragma: no cover
712726

jsonargparse/_namespace.py

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@
1515
Union,
1616
)
1717

18-
__all__ = [
19-
"Namespace",
20-
"dict_to_namespace",
21-
]
18+
__all__ = ["Namespace"]
2219

2320

2421
meta_keys = {"__default_config__", "__path__", "__orig__"}
@@ -322,27 +319,20 @@ def del_clash_mark(key: str) -> str:
322319
return key
323320

324321

325-
def expand_dict(cfg):
326-
for k, v in cfg.items():
322+
def expand_dict(data: dict) -> Namespace:
323+
for k, v in data.items():
327324
if isinstance(v, dict) and all(isinstance(k, str) for k in v):
328-
cfg[k] = expand_dict(v)
325+
data[k] = expand_dict(v)
329326
elif isinstance(v, list):
330327
for nn, vv in enumerate(v):
331328
if isinstance(vv, dict) and all(isinstance(k, str) for k in vv):
332-
cfg[k][nn] = expand_dict(vv)
333-
return Namespace(**cfg)
329+
data[k][nn] = expand_dict(vv)
330+
return Namespace(**data)
334331

335332

336-
def dict_to_namespace(cfg_dict: Union[Dict[str, Any], Namespace]) -> Namespace:
337-
"""Converts a nested dictionary into a nested namespace.
338-
339-
Note: Using this function is generally discouraged because it may not
340-
produce the same results as a parser would. However, it remains part
341-
of the public API to support valid use cases and ensure backward
342-
compatibility.
343-
"""
344-
cfg_dict = recreate_branches(cfg_dict)
345-
return expand_dict(cfg_dict)
333+
def dict_to_namespace(data: dict[str, Any]) -> Namespace:
334+
data = recreate_branches(data)
335+
return expand_dict(data)
346336

347337

348338
# Temporal to provide backward compatibility in pytorch-lightning

jsonargparse_tests/test_deprecated.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
LoggerProperty,
3434
ParserError,
3535
deprecation_warning,
36+
dict_to_namespace,
3637
namespace_to_dict,
3738
shown_deprecation_warnings,
3839
strip_meta,
@@ -741,6 +742,19 @@ def test_add_dataclass_arguments(parser, subtests):
741742
assert "CustomA title:" in help_str
742743

743744

745+
def test_dict_to_namespace():
746+
ns1 = Namespace(a=1, b=Namespace(c=2), d=[Namespace(e=3)])
747+
dic = {"a": 1, "b": {"c": 2}, "d": [{"e": 3}]}
748+
with catch_warnings(record=True) as w:
749+
ns2 = dict_to_namespace(dic)
750+
assert ns1 == ns2
751+
assert_deprecation_warn(
752+
w,
753+
message="dict_to_namespace was deprecated",
754+
code="ns2 = dict_to_namespace(dic)",
755+
)
756+
757+
744758
def test_namespace_to_dict():
745759
ns = Namespace()
746760
ns["w"] = 1

jsonargparse_tests/test_namespace.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import pytest
77

8-
from jsonargparse import Namespace, dict_to_namespace
8+
from jsonargparse import Namespace
99
from jsonargparse._namespace import NSKeyError, meta_keys
1010

1111
skip_if_no_setattr_insertion_order = pytest.mark.skipif(
@@ -223,13 +223,6 @@ def test_init_invalid():
223223
Namespace(argparse.Namespace(), x=1)
224224

225225

226-
def test_dict_to_namespace():
227-
ns1 = Namespace(a=1, b=Namespace(c=2), d=[Namespace(e=3)])
228-
dic = {"a": 1, "b": {"c": 2}, "d": [{"e": 3}]}
229-
ns2 = dict_to_namespace(dic)
230-
assert ns1 == ns2
231-
232-
233226
def test_use_for_kwargs():
234227
def func(a=1, b=2, c=3):
235228
return a, b, c

0 commit comments

Comments
 (0)