Skip to content

Commit

Permalink
Merge pull request #5 from admire93/bugfix/issue-4-boxed-type
Browse files Browse the repository at this point in the history
Validate/Serialize boxed type properly if boxed more than once #4
  • Loading branch information
kanghyojun authored Jul 2, 2016
2 parents f50d36f + 19aaaec commit 60cad1c
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 4 deletions.
6 changes: 5 additions & 1 deletion nirum/serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@


def serialize_boxed_type(data):
return data.value
value = data.value
serialize = getattr(value, '__nirum_serialize__', None)
if callable(serialize):
return serialize()
return value


def serialize_type_with_names(data, names):
Expand Down
15 changes: 13 additions & 2 deletions nirum/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,19 @@
__all__ = 'validate_boxed_type', 'validate_record_type', 'validate_union_type',


def validate_boxed_type(boxed, type_hint):
if not isinstance(boxed, type_hint):
def validate_boxed_type(boxed, type_hint) -> bool:
actual_boxed_val_type = type(boxed)
while True:
try:
actual_boxed_val_type = actual_boxed_val_type.__nirum_boxed_type__
except AttributeError:
break
while True:
try:
type_hint = type_hint.__nirum_boxed_type__
except AttributeError:
break
if actual_boxed_val_type != type_hint:
raise TypeError('{0} expected, found: {1}'.format(type_hint,
type(boxed)))
return boxed
Expand Down
100 changes: 99 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@

from nirum.serialize import serialize_record_type, serialize_boxed_type
from nirum.deserialize import deserialize_record_type, deserialize_boxed_type
from nirum.validate import validate_record_type, validate_union_type
from nirum.validate import (validate_boxed_type, validate_record_type,
validate_union_type)
from nirum.constructs import NameDict


class Offset:

__nirum_boxed_type__ = float

def __init__(self, value: float) -> None:
self.value = value

Expand Down Expand Up @@ -195,3 +198,98 @@ def fx_rectangle_type():
@fixture
def fx_rectangle(fx_rectangle_type, fx_point):
return fx_rectangle_type(fx_point, fx_point)


class A:

__nirum_boxed_type__ = str

def __init__(self, value: str) -> None:
validate_boxed_type(value, str)
self.value = value # type: Text

def __eq__(self, other) -> bool:
return (isinstance(other, A) and
self.value == other.value)

def __hash__(self) -> int:
return hash(self.value)

def __nirum_serialize__(self) -> str:
return serialize_boxed_type(self)

@classmethod
def __nirum_deserialize__(
cls: type, value: typing.Mapping[str, typing.Any]
) -> 'A':
return deserialize_boxed_type(cls, value)

def __repr__(self) -> str:
return '{0.__module__}.{0.__qualname__}({1!r})'.format(
type(self), self.value
)


class B:

__nirum_boxed_type__ = A

def __init__(self, value: A) -> None:
validate_boxed_type(value, A)
self.value = value # type: A

def __eq__(self, other) -> bool:
return (isinstance(other, B) and
self.value == other.value)

def __hash__(self) -> int:
return hash(self.value)

def __nirum_serialize__(self) -> str:
return serialize_boxed_type(self)

@classmethod
def __nirum_deserialize__(
cls: type, value: typing.Mapping[str, typing.Any]
) -> 'B':
return deserialize_boxed_type(cls, value)

def __repr__(self) -> str:
return '{0.__module__}.{0.__qualname__}({1!r})'.format(
type(self), self.value
)


class C:

__nirum_boxed_type__ = A

def __init__(self, value: B) -> None:
validate_boxed_type(value, B)
self.value = value # type: B

def __eq__(self, other) -> bool:
return (isinstance(other, C) and
self.value == other.value)

def __hash__(self) -> int:
return hash(self.value)

def __nirum_serialize__(self) -> str:
return serialize_boxed_type(self)

@classmethod
def __nirum_deserialize__(
cls: type, value: typing.Mapping[str, typing.Any]
) -> 'C':
return deserialize_boxed_type(cls, value)

def __repr__(self) -> str:
return '{0.__module__}.{0.__qualname__}({1!r})'.format(
type(self), self.value
)


@fixture
def fx_layered_boxed_types():
return A, B, C
5 changes: 5 additions & 0 deletions tests/serialize_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ def test_serialize_boxed_type(fx_offset):
assert serialize_boxed_type(fx_offset) == fx_offset.value


def test_serialize_layered_boxed_type(fx_layered_boxed_types):
actual = fx_layered_boxed_types[1](fx_layered_boxed_types[0]('test'))
assert actual.__nirum_serialize__() == 'test'


def test_serialize_record_type(fx_point):
assert serialize_record_type(fx_point) == {'_type': 'point', 'x': 3.14,
'top': 1.592}
Expand Down
4 changes: 4 additions & 0 deletions tests/validate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ def test_validate_union_type(fx_rectangle, fx_rectangle_type, fx_point):

with raises(TypeError):
validate_union_type(fx_rectangle_type(1, 1))


def test_validate_layered_boxed_types(fx_layered_boxed_types):
assert validate_boxed_type('test', fx_layered_boxed_types[1])

0 comments on commit 60cad1c

Please sign in to comment.