diff --git a/README.md b/README.md index 4b094c49..91b93450 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,7 @@ for special primitives from the [`typing`](https://docs.python.org/3/library/typ for standard interpreter types from [`types`](https://docs.python.org/3/library/types.html#standard-interpreter-types) module: * [`NoneType`](https://docs.python.org/3/library/types.html#types.NoneType) * [`UnionType`](https://docs.python.org/3/library/types.html#types.UnionType) +* [`MappingProxyType`](https://docs.python.org/3/library/types.html#types.MappingProxyType) for enumerations based on classes from the standard [`enum`](https://docs.python.org/3/library/enum.html) module: * [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum) diff --git a/mashumaro/core/meta/types/unpack.py b/mashumaro/core/meta/types/unpack.py index 986cfd11..62c11829 100644 --- a/mashumaro/core/meta/types/unpack.py +++ b/mashumaro/core/meta/types/unpack.py @@ -1230,6 +1230,12 @@ def inner_expr( ) elif is_typed_dict(spec.origin_type): return unpack_typed_dict(spec) + elif issubclass(spec.origin_type, types.MappingProxyType): + spec.builder.ensure_module_imported(types) + return ( + f'types.MappingProxyType({{{inner_expr(0, "key")}: {inner_expr(1)}' + f" for key, value in {spec.expression}.items()}})" + ) elif ensure_generic_mapping(spec, args, typing.Mapping): return ( f'{{{inner_expr(0, "key")}: {inner_expr(1)} ' diff --git a/tests/test_data_types.py b/tests/test_data_types.py index ea5f0e68..05f3b129 100644 --- a/tests/test_data_types.py +++ b/tests/test_data_types.py @@ -16,6 +16,7 @@ WindowsPath, ) from queue import Queue +from types import MappingProxyType from typing import ( Any, AnyStr, @@ -123,6 +124,7 @@ class Fixture: DICT = {"a": 1, "b": 2} ORDERED_DICT = collections.OrderedDict(a=1, b=2) DEFAULT_DICT = collections.defaultdict(int, a=1, b=2) + MAPPING_PROXY = MappingProxyType(DICT) DEFAULT_NONE_DICT = collections.defaultdict(None, a=1, b=2) COUNTER: Counter[str] = collections.Counter(a=1, b=2) BYTES = b"123" @@ -204,6 +206,8 @@ class Fixture: (OrderedDict, Fixture.ORDERED_DICT, Fixture.DICT), (DefaultDict[str, int], Fixture.DEFAULT_DICT, Fixture.DICT), (DefaultDict, Fixture.DEFAULT_NONE_DICT, Fixture.DICT), + (MappingProxyType[str, int], Fixture.MAPPING_PROXY, Fixture.DICT), + (MappingProxyType, Fixture.MAPPING_PROXY, Fixture.DICT), (Counter[str], Fixture.COUNTER, Fixture.DICT), (Counter, Fixture.COUNTER, Fixture.DICT), (MutableMapping[str, int], Fixture.DICT, Fixture.DICT), diff --git a/tests/test_meta.py b/tests/test_meta.py index 798a5ec8..05c0f66a 100644 --- a/tests/test_meta.py +++ b/tests/test_meta.py @@ -1,5 +1,6 @@ import collections import collections.abc +import types import typing from dataclasses import InitVar, dataclass from datetime import datetime @@ -216,6 +217,9 @@ def test_type_name(): type_name(typing.DefaultDict[int, int]) == "typing.DefaultDict[int, int]" ) + assert ( + type_name(types.MappingProxyType[int, int]) == "mappingproxy[int, int]" + ) assert type_name(typing.Optional[int]) == "typing.Optional[int]" assert type_name(typing.Union[None, int]) == "typing.Optional[int]" assert type_name(typing.Union[int, None]) == "typing.Optional[int]" @@ -308,6 +312,10 @@ def test_type_name_short(): type_name(typing.MutableMapping[int, int], short=True) == "MutableMapping[int, int]" ) + assert ( + type_name(types.MappingProxyType[int, int], short=True) + == "mappingproxy[int, int]" + ) assert type_name(typing.Counter[int], short=True) == "Counter[int]" assert ( type_name(typing.ChainMap[int, int], short=True)