Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for enhanced builtin instantiation #375

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions dataclasses_json/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ def _support_extended_types(field_type, field_value):
res = (field_value
if isinstance(field_value, UUID)
else UUID(field_value))
elif _issubclass_safe(field_type, (int, float, str, bool)):
res = (field_value
if isinstance(field_value, field_type)
else field_type(field_value))
else:
res = field_value
return res
Expand Down
34 changes: 34 additions & 0 deletions tests/test_builtins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from dataclasses import dataclass
from decimal import Decimal
from typing import Optional

from pytest import mark, param


from dataclasses_json import DataClassJsonMixin


@dataclass(frozen=True)
class DataClassWithBuiltins(DataClassJsonMixin):
actually_a_str: str
actually_an_int: int
actually_a_float: float


@mark.parametrize(
"model_dict, expected_model",
[
param(
{"actually_a_str": "str", "actually_an_int": 42, "actually_a_float": 42.1},
DataClassWithBuiltins(actually_a_str="str", actually_an_int=42, actually_a_float=42.1),
id="Happy case"
),
param(
{"actually_a_str": "str", "actually_an_int": Decimal("42.1"), "actually_a_float": Decimal("42.1")},
DataClassWithBuiltins(actually_a_str="str", actually_an_int=42, actually_a_float=42.1),
id="Decimal as int and float"
),
]
)
def test__DataClassWithBuiltins__from_dict(model_dict, expected_model):
assert DataClassWithBuiltins.from_dict(model_dict) == expected_model
2 changes: 1 addition & 1 deletion tests/test_invariants.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
(DataClassWithTuple, tuples, tuple),
(DataClassWithFrozenSet, frozensets, frozenset),
(DataClassWithDeque, deques, deque),
(DataClassWithOptional, optionals, lambda x: x)]
(DataClassWithOptional, optionals, lambda x: x[0])]
example_input = [1]


Expand Down
2 changes: 1 addition & 1 deletion tests/test_letter_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class FieldNamePerson:
@dataclass
class CamelCasePersonWithOverride:
given_name: str
years_on_earth: str = field(metadata=config(field_name='age'))
years_on_earth: int = field(metadata=config(field_name='age'))


class TestLetterCase:
Expand Down
32 changes: 32 additions & 0 deletions tests/test_str_subclass.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from dataclasses import dataclass

from dataclasses_json import DataClassJsonMixin


class MyStr(str):

def is_even_length(self) -> bool:
return len(self) % 2 == 0


@dataclass(frozen=True)
class DataClassWithStrSubclass(DataClassJsonMixin):
any_str: str
my_str: MyStr


class TestDataClassWithStrSubclass:

def test_encode__no_instantiation_required(self):
model_dict = {"any_str": "str", "my_str": MyStr("str")}
expected = DataClassWithStrSubclass(any_str="str", my_str=MyStr("str"))
actual = DataClassWithStrSubclass.from_dict(model_dict)
assert expected == actual
assert model_dict["my_str"] is actual.my_str

def test_encode__subclass_str_instantiated(self):
model_dict = {"any_str": "str", "my_str": "str"}
expected = DataClassWithStrSubclass(any_str="str", my_str=MyStr("str"))
actual = DataClassWithStrSubclass.from_dict(model_dict)
assert expected == actual
assert model_dict["my_str"] is not actual.my_str