Skip to content

Commit

Permalink
Restore v1 to_native behavior; simplify converter code (#412)
Browse files Browse the repository at this point in the history
  • Loading branch information
bintoro committed May 2, 2016
1 parent 3e9c6a3 commit 6c8b900
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 98 deletions.
5 changes: 1 addition & 4 deletions schematics/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from .exceptions import *
from .transforms import (
atoms, export_loop,
convert, to_native, to_dict, to_primitive,
convert, to_native, to_primitive,
)
from .validate import validate, prepare_validator
from .types import BaseType
Expand Down Expand Up @@ -298,9 +298,6 @@ def export(self, field_converter=None, role=None, app_data=None, **kwargs):
def to_native(self, role=None, app_data=None, **kwargs):
return to_native(self.__class__, self, role=role, app_data=app_data, **kwargs)

def to_dict(self, role=None, app_data=None, **kwargs):
return to_dict(self.__class__, self, role=role, app_data=app_data, **kwargs)

def to_primitive(self, role=None, app_data=None, **kwargs):
return to_primitive(self.__class__, self, role=role, app_data=app_data, **kwargs)

Expand Down
70 changes: 20 additions & 50 deletions schematics/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ def blacklist(*field_list):
###


class FieldConverter(object):
class Converter(object):

def __call__(self, field, value, context):
raise NotImplementedError
Expand All @@ -448,7 +448,7 @@ def post(self, model_class, data, context):
return data


class BasicConverter(FieldConverter):
class BasicConverter(Converter):

def __init__(self, func):
self.func = func
Expand All @@ -463,33 +463,14 @@ def __call__(self, *args):
###


class ExportConverter(FieldConverter):
@BasicConverter
def to_native_converter(field, value, context):
return field.export(value, NATIVE, context)

def __init__(self, format, exceptions=None):
self.primary = format
self.secondary = not format
self.exceptions = set(exceptions) if exceptions else None

def __call__(self, field, value, context):
format = self.primary
if self.exceptions:
if any((issubclass(field.typeclass, cls) for cls in self.exceptions)):
format = self.secondary
return field.export(value, format, context)


class NativeConverter(ExportConverter):

def __init__(self, exceptions=None):
ExportConverter.__init__(self, NATIVE, exceptions)

def post(self, model_class, data, context):
return model_class(data, init=False)


to_native_converter = NativeConverter()
to_dict_converter = ExportConverter(NATIVE)
to_primitive_converter = ExportConverter(PRIMITIVE)
@BasicConverter
def to_primitive_converter(field, value, context):
return field.export(value, PRIMITIVE, context)



Expand All @@ -498,27 +479,20 @@ def post(self, model_class, data, context):
###


class ImportConverter(FieldConverter):
@BasicConverter
def import_converter(field, value, context):
field.check_required(value, context)
if value in (None, Undefined):
return value
return field.convert(value, context)

def __init__(self, action):
self.action = action
self.method = operator.attrgetter(self.action)

def __call__(self, field, value, context):
field.check_required(value, context)
if value in (None, Undefined):
return value
return self.method(field)(value, context)

def pre(self, model_class, instance_or_dict, context):
return instance_or_dict

def post(self, model_class, data, context):
return data


import_converter = ImportConverter('convert')
validation_converter = ImportConverter('validate')
@BasicConverter
def validation_converter(field, value, context):
field.check_required(value, context)
if value in (None, Undefined):
return value
return field.validate(value, context)



Expand Down Expand Up @@ -564,10 +538,6 @@ def to_native(cls, instance_or_dict, **kwargs):
return export_loop(cls, instance_or_dict, to_native_converter, **kwargs)


def to_dict(cls, instance_or_dict, **kwargs):
return export_loop(cls, instance_or_dict, to_dict_converter, **kwargs)


def to_primitive(cls, instance_or_dict, **kwargs):
return export_loop(cls, instance_or_dict, to_primitive_converter, **kwargs)

Expand Down
6 changes: 1 addition & 5 deletions schematics/types/compound.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from ..transforms import (
export_loop,
get_import_context, get_export_context,
to_native_converter, to_dict_converter, to_primitive_converter)
to_native_converter, to_primitive_converter)

from .base import BaseType, get_value_in

Expand Down Expand Up @@ -51,10 +51,6 @@ def to_native(self, value, context=None):
context = context or get_export_context(to_native_converter)
return to_native_converter(self, value, context)

def to_dict(self, value, context=None):
context = context or get_export_context(to_dict_converter)
return to_dict_converter(self, value, context)

def to_primitive(self, value, context=None):
context = context or get_export_context(to_primitive_converter)
return to_primitive_converter(self, value, context)
Expand Down
55 changes: 24 additions & 31 deletions tests/test_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from schematics.common import *
from schematics.models import Model
from schematics.transforms import ExportConverter, to_native, to_dict, to_primitive
from schematics.transforms import Converter, to_native, to_primitive
from schematics.types import *
from schematics.types.compound import *
from schematics.types.serializable import serializable
Expand Down Expand Up @@ -47,34 +47,11 @@ class M(BaseModel):
def test_to_native():

m = M(primitives)
assert m.to_native() == m

assert to_native(M, natives) == m

m = M({'modelfield': {}})
result = m.to_native()
assert result.intfield is None
assert result.modelfield.floatfield is None

m = M({'modelfield': {}})
del m.intfield
del m.modelfield.floatfield
result = m.to_native()
assert 'intfield' not in result
assert 'floatfield' not in result.modelfield
result = m.to_native(export_level=ALL)
assert result.intfield is None
assert result.modelfield.floatfield is None


def test_to_dict():

m = M(primitives)
output = m.to_dict()
output = m.to_native()
assert type(output) is dict
assert output == natives

assert to_dict(M, natives) == natives
assert to_native(M, natives) == natives


def test_to_primitive():
Expand All @@ -91,8 +68,7 @@ def test_standalone_field():

converted = field.convert([primitives])
assert converted == [natives]
assert field.to_native(converted) == [M(primitives)]
assert field.to_dict(converted) == [natives]
assert field.to_native(converted) == [natives]
assert field.to_primitive(converted) == [primitives]


Expand Down Expand Up @@ -123,17 +99,34 @@ class X(Model):
'dt': '2015-11-26T07:00',
'foo': {'x': 1, 'y': 2} })

assert x.to_dict() == {
assert x.to_native() == {
'id': uuid.UUID('54020382-291e-4192-b370-4850493ac5bc'),
'dt': datetime.datetime(2015, 11, 26, 7),
'foo': Foo(1, 2) }

exporter = ExportConverter(PRIMITIVE, [UTCDateTimeType, UUIDType])
class MyExportConverter(Converter):

keep_as_native = (UTCDateTimeType, UUIDType)

def __call__(self, field, value, context):
if field.typeclass in self.keep_as_native:
format = NATIVE
else:
format = PRIMITIVE
return field.export(value, format, context)

def post(self, model_class, data, context):
data['n'] = 42
return data

exporter = MyExportConverter()

assert x.export(field_converter=exporter) == {
'id': uuid.UUID('54020382-291e-4192-b370-4850493ac5bc'),
'dt': datetime.datetime(2015, 11, 26, 7),
'foo': {'x': 1, 'y': 2} }
'foo': {'x': 1, 'y': 2},
'n': 42
}


def test_converter_function():
Expand Down
1 change: 0 additions & 1 deletion tests/test_export_level.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from schematics.common import *
from schematics.models import Model
from schematics.transforms import ExportConverter
from schematics.types import *
from schematics.types.compound import *
from schematics.types.serializable import serializable
Expand Down
1 change: 0 additions & 1 deletion tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from schematics.common import *
from schematics.models import Model
from schematics.transforms import ExportConverter
from schematics.types import *
from schematics.types.compound import *
from schematics.types.serializable import serializable
Expand Down
12 changes: 6 additions & 6 deletions tests/test_serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def country_name(self):
d = location_US.serialize()
assert d == {"country_code": "US", "country_name": "United States"}

d = location_US.to_dict()
d = location_US.to_native()
assert d == {"country_code": u"US", "country_name": "United States"}

location_IS = Location({"country_code": "IS"})
Expand All @@ -34,11 +34,11 @@ def country_name(self):
d = location_IS.serialize()
assert d == {"country_code": "IS", "country_name": "Unknown"}

d = location_IS.to_dict()
d = location_IS.to_native()
assert d == {"country_code": "IS", "country_name": "Unknown"}


def test_serializable_to_dict():
def test_serializable_to_native():
class Location(Model):
country_code = StringType()

Expand All @@ -48,7 +48,7 @@ def country_name(self):

loc = Location({'country_code': 'US'})

d = loc.to_dict()
d = loc.to_native()
assert d == {'country_code': 'US', 'country_name': 'United States'}


Expand Down Expand Up @@ -147,7 +147,7 @@ def xp_level(self):
assert d == {"total_points": 2, "xp_level": {"level": 4, "title": "Best"}}


def test_serializable_with_model_to_dict():
def test_serializable_with_model_to_native():
class ExperienceLevel(Model):
level = IntType()
title = StringType()
Expand All @@ -163,7 +163,7 @@ def xp_level(self):

assert player.xp_level.level == 4

d = player.to_dict()
d = player.to_native()
assert d == {"total_points": 2, "xp_level": {"level": 4, "title": "Best"}}


Expand Down

0 comments on commit 6c8b900

Please sign in to comment.