Skip to content

Commit 2f3cce5

Browse files
authored
Support for MappingProxyType as a type and as default for mapping types (#540)
1 parent 9feda6f commit 2f3cce5

File tree

4 files changed

+36
-4
lines changed

4 files changed

+36
-4
lines changed

CHANGELOG.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ 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.32.0 (2024-07-??)
16+
--------------------
17+
18+
Added
19+
^^^^^
20+
- Support for ``MappingProxyType`` as a type and as default for mapping types
21+
(`#540 <https://github.com/omni-us/jsonargparse/pull/540>`__).
22+
23+
1524
v4.31.0 (2024-06-27)
1625
--------------------
1726

DOCUMENTATION.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,8 +400,9 @@ Some notes about this support are:
400400
:ref:`restricted-strings` and paths and URLs as explained in sections
401401
:ref:`parsing-paths` and :ref:`parsing-urls`.
402402

403-
- ``Dict``, ``Mapping``, ``MutableMapping``, and ``TypedDict`` are supported but
404-
only with ``str`` or ``int`` keys. For more details see :ref:`dict-items`.
403+
- ``Dict``, ``Mapping``, ``MutableMapping``, ``MappingProxyType``, and
404+
``TypedDict`` are supported but only with ``str`` or ``int`` keys. For more
405+
details see :ref:`dict-items`.
405406

406407
- ``Tuple``, ``Set`` and ``MutableSet`` are supported even though they can't be
407408
represented in json distinguishable from a list. Each ``Tuple`` element

jsonargparse/_typehints.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from copy import deepcopy
1111
from enum import Enum
1212
from functools import partial
13-
from types import FunctionType
13+
from types import FunctionType, MappingProxyType
1414
from typing import (
1515
Any,
1616
Callable,
@@ -145,7 +145,7 @@
145145
abc.Sequence,
146146
abc.MutableSequence,
147147
}
148-
mapping_origin_types = {Dict, dict, Mapping, MutableMapping, abc.Mapping, abc.MutableMapping}
148+
mapping_origin_types = {Dict, dict, Mapping, MappingProxyType, MutableMapping, abc.Mapping, abc.MutableMapping}
149149
callable_origin_types = {Callable, abc.Callable}
150150

151151
literal_types = {Literal}
@@ -872,6 +872,8 @@ def adapt_typehints(
872872
val = {**prev_val, val.key: val.val}
873873
else:
874874
val = {val.key: val.val}
875+
elif isinstance(val, MappingProxyType):
876+
val = dict(val)
875877
elif not isinstance(val, dict):
876878
raise_unexpected_value(f"Expected a {typehint_origin}", val)
877879
if subtypehints is not None:
@@ -902,6 +904,8 @@ def adapt_typehints(
902904
raise_unexpected_value(f"Unexpected keys: {extra_keys}", val)
903905
for k, v in val.items():
904906
val[k] = adapt_typehints(v, typehint.__annotations__[k], **adapt_kwargs)
907+
if typehint_origin == MappingProxyType and not serialize:
908+
val = MappingProxyType(val)
905909

906910
# Callable
907911
elif typehint_origin in callable_origin_types or typehint in callable_origin_types:

jsonargparse_tests/test_typehints.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from calendar import Calendar, TextCalendar
99
from enum import Enum
1010
from pathlib import Path
11+
from types import MappingProxyType
1112
from typing import (
1213
Any,
1314
Callable,
@@ -545,6 +546,23 @@ def test_typeddict_with_args_ntotal(parser):
545546
ctx.match("Expected a <class 'dict'>")
546547

547548

549+
def test_mapping_proxy_type(parser):
550+
parser.add_argument("--mapping", type=MappingProxyType)
551+
cfg = parser.parse_args(['--mapping={"x":1}'])
552+
assert isinstance(cfg.mapping, MappingProxyType)
553+
assert cfg.mapping == {"x": 1}
554+
assert parser.dump(cfg, format="json") == '{"mapping":{"x":1}}'
555+
556+
557+
def test_mapping_default_mapping_proxy_type(parser):
558+
mapping_proxy = MappingProxyType({"x": 1})
559+
parser.add_argument("--mapping", type=Mapping[str, int], default=mapping_proxy)
560+
cfg = parser.parse_args([])
561+
assert isinstance(cfg.mapping, Mapping)
562+
assert mapping_proxy == cfg.mapping
563+
assert parser.dump(cfg, format="json") == '{"mapping":{"x":1}}'
564+
565+
548566
# union tests
549567

550568

0 commit comments

Comments
 (0)