diff --git a/src/desert/_make.py b/src/desert/_make.py index ca37d21..433fd21 100644 --- a/src/desert/_make.py +++ b/src/desert/_make.py @@ -305,11 +305,19 @@ def field_for_schema( field = field_for_schema(newtype_supertype, default=default) # enumerations - if type(typ) is enum.EnumMeta: + elif type(typ) is enum.EnumMeta: import marshmallow_enum field = marshmallow_enum.EnumField(typ, metadata=metadata) + # TypedDict + # TODO(python3.10) use t.is_typeddict + elif isinstance(typ, t._TypedDictMeta): + field = marshmallow.fields.Dict( + keys=marshmallow.fields.String, + values=marshmallow.fields.Raw, + ) + # Nested dataclasses forward_reference = getattr(typ, "__forward_arg__", None) diff --git a/tests/test_make.py b/tests/test_make.py index 9a2991c..3db7ab2 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -437,6 +437,26 @@ class A: assert_dump_load(schema=schema, loaded=loaded, dumped=dumped) +def test_typed_dict( + module: DataclassModule, + assert_dump_load: AssertLoadDumpProtocol, +) -> None: + """Test dataclasses with basic TypedDict support""" + + class B(t.TypedDict): + x: int + + @module.dataclass + class A: + x: B + + schema = desert.schema_class(A)() + dumped = {"x": {"x": 1}} + loaded = A(x={"x": 1}) + + assert_dump_load(schema=schema, loaded=loaded, dumped=dumped) + + @pytest.mark.xfail( strict=True, reason=( @@ -568,7 +588,6 @@ class A: assert schema.loads(schema.dumps(loaded)) == loaded assert schema.dump(schema.load(actually_dumped)) == actually_dumped - def test_only() -> None: """only() extracts the only item in an iterable.""" assert desert._make.only([1]) == 1