Skip to content

Commit

Permalink
Merge pull request #27 from fishtown-analytics/fix/union-tuple
Browse files Browse the repository at this point in the history
Fix union and some tuples
  • Loading branch information
beckjake authored Mar 23, 2020
2 parents 95ae656 + d812aca commit b786575
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 6 deletions.
9 changes: 6 additions & 3 deletions hologram/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,9 +793,12 @@ def _get_field_schema(
@classmethod
def _get_field_definitions(cls, field_type: Any, definitions: JsonDict):
field_type_name = cls._get_field_type_name(field_type)
if (
is_optional(field_type) and len(field_type.__args__) == 2
) or field_type_name in ("Sequence", "List", "Tuple",):
if field_type_name == "Tuple":
# tuples are either like Tuple[T, ...] or Tuple[T1, T2, T3].
for member in field_type.__args__:
if member is not ...:
cls._get_field_definitions(member, definitions)
elif field_type_name in ("Sequence", "List"):
cls._get_field_definitions(field_type.__args__[0], definitions)
elif field_type_name in ("Dict", "Mapping"):
cls._get_field_definitions(field_type.__args__[1], definitions)
Expand Down
17 changes: 14 additions & 3 deletions tests/test_multi_optional_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ class RestrictC(JsonSchemaMixin):
foo: MySelector = field(metadata={"restrict": [MySelector.C]})
baz: str


@dataclass
class A(JsonSchemaMixin):
baz: str


@dataclass
class B(JsonSchemaMixin):
baz: str
Expand Down Expand Up @@ -77,9 +79,18 @@ class IHaveExtremelyAnnoyingUnions(JsonSchemaMixin):

def test_evil_union():
pairs = [
(IHaveExtremelyAnnoyingUnions(my_field=True).to_dict(), {"my_field": True}),
(IHaveExtremelyAnnoyingUnions(my_field='1').to_dict(), {"my_field": '1'}),
(IHaveExtremelyAnnoyingUnions(my_field=1.0).to_dict(), {"my_field": 1.0}),
(
IHaveExtremelyAnnoyingUnions(my_field=True).to_dict(),
{"my_field": True},
),
(
IHaveExtremelyAnnoyingUnions(my_field="1").to_dict(),
{"my_field": "1"},
),
(
IHaveExtremelyAnnoyingUnions(my_field=1.0).to_dict(),
{"my_field": 1.0},
),
(IHaveExtremelyAnnoyingUnions().to_dict(), {}),
]
for a, b in pairs:
Expand Down
47 changes: 47 additions & 0 deletions tests/test_tuple.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from dataclasses import dataclass
from typing import Tuple

from hologram import JsonSchemaMixin


@dataclass
class TupleMember(JsonSchemaMixin):
a: int


@dataclass
class TupleEllipsisHolder(JsonSchemaMixin):
member: Tuple[TupleMember, ...]


@dataclass
class TupleMemberFirstHolder(JsonSchemaMixin):
member: Tuple[TupleMember, str]


@dataclass
class TupleMemberSecondHolder(JsonSchemaMixin):
member: Tuple[str, TupleMember]


def test_ellipsis_tuples():
dct = {"member": [{"a": 1}, {"a": 2}, {"a": 3}]}
value = TupleEllipsisHolder(
member=(TupleMember(1), TupleMember(2), TupleMember(3))
)
assert value.to_dict() == dct
assert TupleEllipsisHolder.from_dict(dct) == value


def test_member_first_tuple():
dct = {"member": [{"a": 1}, "a"]}
value = TupleMemberFirstHolder(member=(TupleMember(1), "a"))
TupleMemberFirstHolder.from_dict(dct) == value
value.to_dict() == dct


def test_member_second_tuple():
dct = {"member": ["a", {"a": 1}]}
value = TupleMemberSecondHolder(member=("a", TupleMember(1)))
TupleMemberSecondHolder.from_dict(dct) == value
value.to_dict() == dct
21 changes: 21 additions & 0 deletions tests/test_union.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,24 @@ def test_union_decode_error():

with pytest.raises(ValidationError):
IHaveAnnoyingUnions.from_dict({"my_field": {">=0.0.0"}})


@dataclass
class UnionMember(JsonSchemaMixin):
a: int


@dataclass
class LongOptionalUnion(JsonSchemaMixin):
# this devolves into Union[None, UnionMember]
member: Optional[Union[None, UnionMember]]


def test_long_union_decoding():
x = LongOptionalUnion(None)
x.to_dict() == {"member": None}
LongOptionalUnion.from_dict({"member": None})

x = LongOptionalUnion(UnionMember(1))
x.to_dict() == {"member": {"a": 1}}
LongOptionalUnion.from_dict({"member": {"a": 1}}) == x

0 comments on commit b786575

Please sign in to comment.