Skip to content

Commit

Permalink
Add support for enhanced builtin instantiation (#375)
Browse files Browse the repository at this point in the history
  • Loading branch information
rpmcginty authored Jun 14, 2023
1 parent d779294 commit e5cf202
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 2 deletions.
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

0 comments on commit e5cf202

Please sign in to comment.