Skip to content

Commit

Permalink
Fix exception when TypedDict is used
Browse files Browse the repository at this point in the history
  • Loading branch information
jacebrowning committed Jul 28, 2022
1 parent 06b123a commit 78d63ce
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 4 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Release Notes

## 1.4.1 (2022-07-28)

- Fixed exception when `TypedDict` is used, but schema is not yet supported.

## 1.4 (2022-06-03)

- Added support for accessing `Dict` keys as attributes.
Expand Down
6 changes: 5 additions & 1 deletion datafiles/converters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def map_type(cls, *, name: str = "", item_cls: Optional[type] = None):

elif isclass(cls.__origin__) and issubclass(cls.__origin__, Mapping):
if item_cls:
key = map_type(str)
key = String
value = map_type(item_cls)
else:
log.warn("Schema enforcement not possible with 'Dict' annotation")
Expand Down Expand Up @@ -164,4 +164,8 @@ def map_type(cls, *, name: str = "", item_cls: Optional[type] = None):
if issubclass(cls, Enum):
return Enumeration.of_type(cls)

if issubclass(cls, dict):
log.warn("Schema enforcement not possible with 'TypedDict' annotation")
return Dictionary.of_mapping(String, Any) # type: ignore

raise TypeError(f"Could not map type: {cls}")
2 changes: 1 addition & 1 deletion datafiles/converters/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def to_python_value(cls, deserialized_data, *, target_object):

@classmethod
def to_preserialization_data(cls, python_value, *, default_to_skip=None):
data = dict(python_value)
data = dict(python_value) if python_value else {}

if data == default_to_skip:
data.clear()
Expand Down
19 changes: 18 additions & 1 deletion datafiles/tests/test_converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from dataclasses import dataclass
from enum import Enum
from typing import ByteString, Dict, List, Mapping, Optional, Set
from typing import ByteString, Dict, List, Mapping, Optional, Set, TypedDict

import pytest
from ruamel.yaml.scalarstring import LiteralScalarString
Expand All @@ -24,6 +24,11 @@ class MyNestedDataclass:
dc: MyDataclass


class MyTypedDict(TypedDict):
title: str
salary: int


class MyNonDataclass:
pass

Expand All @@ -45,6 +50,7 @@ class Color(Enum):
StringSet = converters.Set.of_type(converters.String)
MyDataclassConverter = converters.map_type(MyDataclass)
MyDataclassConverterList = converters.map_type(List[MyDataclass])
MyTypedDictConverter = converters.map_type(MyTypedDict)


def describe_map_type():
Expand Down Expand Up @@ -88,6 +94,10 @@ def it_requires_dict_annotations_to_have_types(expect):
with expect.raises(TypeError, "Types are required with 'Dict' annotation"):
converters.map_type(Dict)

def it_handles_typed_dict_annotations(expect):
converter = converters.map_type(MyTypedDict)
expect(converter.__name__) == "StringAnyDict"

def it_handles_abstract_mapping_types(expect):
converter = converters.map_type(Mapping[str, int])
expect(converter.__name__) == "StringIntegerDict"
Expand Down Expand Up @@ -211,6 +221,9 @@ def when_immutable(expect, converter, data, value):
(MyDataclassConverter, MyDataclass(42), MyDataclass(foobar=42)),
(MyDataclassConverterList, None, []),
(MyDataclassConverterList, 42, [MyDataclass(foobar=0)]),
(MyTypedDictConverter, None, {}),
(MyTypedDictConverter, {}, {}),
(MyTypedDictConverter, {"a": 1}, {"a": 1}),
],
)
def when_mutable(expect, converter, data, value):
Expand Down Expand Up @@ -293,6 +306,10 @@ def describe_to_preserialization_data():
(StringList, [123, True, False], ["123", "True", "False"]),
(StringList, [], [None]),
(StringList, None, [None]),
# Dicts
(MyTypedDictConverter, None, {}),
(MyTypedDictConverter, {}, {}),
(MyTypedDictConverter, {"a": 1}, {"a": 1}),
# Sets
(StringSet, "ab", ["ab"]),
(StringSet, ("b", 1, "A"), ["b", "1", "A"]),
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tool.poetry]

name = "datafiles"
version = "1.4"
version = "1.4.1"
description = "File-based ORM for dataclasses."

license = "MIT"
Expand Down

0 comments on commit 78d63ce

Please sign in to comment.