-
Notifications
You must be signed in to change notification settings - Fork 21
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
[WIP] Allow modification of data on [de]serialization #34
base: master
Are you sure you want to change the base?
Changes from 7 commits
47f5dc4
326f7cc
986bd43
a4fe15f
b0ab60d
2899415
70e5776
2c7d916
eb17a1e
f4b14b4
aebb098
08a5986
3b221f8
55e5157
c2dfa85
7d3a5e5
aa6c2a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
from collections import namedtuple | ||
from marshmallow import fields, Schema | ||
from marshmallow_polyfield.polyfield import PolyField | ||
from marshmallow import decorators, fields, Schema | ||
from marshmallow_polyfield.polyfield import PolyField, ExplicitPolyField | ||
import pytest | ||
from six import text_type | ||
from tests.shapes import ( | ||
Rectangle, | ||
Triangle, | ||
|
@@ -99,3 +100,259 @@ def test_serializing_polyfield_by_parent_type(field): | |
rect_dict = field.serialize('shape', marshmallow_sticker) | ||
|
||
assert rect_dict == {"length": 4, "width": 10, "color": "blue"} | ||
|
||
|
||
def test_serializing_with_modification(): | ||
import marshmallow | ||
|
||
def create_label_schema(schema): | ||
class LabelSchema(marshmallow.Schema): | ||
type = marshmallow.fields.String() | ||
value = schema() | ||
|
||
return LabelSchema | ||
|
||
class_to_schema = { | ||
text_type: marshmallow.fields.String, | ||
int: marshmallow.fields.Integer, | ||
} | ||
|
||
name_to_class = { | ||
u'str': text_type, | ||
u'int': int, | ||
} | ||
|
||
class_to_name = { | ||
cls: name | ||
for name, cls in name_to_class.items() | ||
} | ||
class_to_name[text_type] = u'str' | ||
|
||
def serialization_schema(base_object, parent_obj): | ||
cls = type(base_object) | ||
schema = class_to_schema[cls] | ||
|
||
label_schema = create_label_schema(schema=schema) | ||
|
||
return label_schema() | ||
|
||
def serialization_value(base_object, parent_obj): | ||
cls = type(base_object) | ||
name = class_to_name[cls] | ||
|
||
return {'type': name, 'value': base_object} | ||
|
||
def deserialization_schema(object_dict, parent_object_dict): | ||
name = object_dict['type'] | ||
cls = name_to_class[name] | ||
schema = class_to_schema[cls] | ||
|
||
return schema() | ||
|
||
def deserialization_value(object_dict, parent_object_dict): | ||
return object_dict['value'] | ||
|
||
class TopClass: | ||
def __init__(self, polyfield): | ||
self.polyfield = polyfield | ||
|
||
def __eq__(self, other): | ||
if type(self) != type(other): | ||
return False | ||
|
||
return self.polyfield == other.polyfield | ||
|
||
class TopSchema(marshmallow.Schema): | ||
polyfield = PolyField( | ||
serialization_schema_selector=serialization_schema, | ||
deserialization_schema_selector=deserialization_schema, | ||
serialization_value_modifier=serialization_value, | ||
deserialization_value_modifier=deserialization_value, | ||
) | ||
|
||
@marshmallow.decorators.post_load | ||
def make_object(self, data, many=None, partial=None): | ||
return TopClass(**data) | ||
|
||
top_schema = TopSchema() | ||
|
||
top_class_str_example = TopClass(polyfield=u'abc') | ||
top_class_str_example_dumped = top_schema.dump(top_class_str_example) | ||
print(top_class_str_example_dumped) | ||
top_class_str_example_loaded = top_schema.load(top_class_str_example_dumped) | ||
assert top_class_str_example_loaded == top_class_str_example | ||
|
||
print('---') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally id rather you pull out what you need so you can make these two different tests rather than one test separated by the output There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like above, to be removed. |
||
|
||
top_class_int_example = TopClass(polyfield=42) | ||
top_class_int_example_dumped = top_schema.dump(top_class_int_example) | ||
print(top_class_int_example_dumped) | ||
top_class_int_example_loaded = top_schema.load(top_class_int_example_dumped) | ||
assert top_class_int_example_loaded == top_class_int_example | ||
|
||
|
||
def test_serializing_with_modification_ExplicitPolyField(): | ||
class TopClass: | ||
def __init__(self, polyfield): | ||
self.polyfield = polyfield | ||
|
||
def __eq__(self, other): | ||
if type(self) != type(other): | ||
return False | ||
|
||
return self.polyfield == other.polyfield | ||
|
||
class TopSchema(Schema): | ||
polyfield = ExplicitPolyField( | ||
class_to_schema_mapping={ | ||
text_type: fields.String, | ||
int: fields.Integer, | ||
}, | ||
class_to_name_overrides={ | ||
text_type: u'str', | ||
}, | ||
) | ||
|
||
@decorators.post_load | ||
def make_object(self, data, many=None, partial=None): | ||
return TopClass(**data) | ||
|
||
top_schema = TopSchema() | ||
|
||
top_class_str_example = TopClass(polyfield=u'abc') | ||
top_class_str_example_dumped = top_schema.dump(top_class_str_example) | ||
print(top_class_str_example_dumped) | ||
top_class_str_example_loaded = top_schema.load(top_class_str_example_dumped) | ||
assert top_class_str_example_loaded == top_class_str_example | ||
|
||
print('---') | ||
|
||
top_class_int_example = TopClass(polyfield=42) | ||
top_class_int_example_dumped = top_schema.dump(top_class_int_example) | ||
print(top_class_int_example_dumped) | ||
top_class_int_example_loaded = top_schema.load(top_class_int_example_dumped) | ||
assert top_class_int_example_loaded == top_class_int_example | ||
|
||
|
||
explicit_poly_field_with_overrides = ExplicitPolyField( | ||
class_to_schema_mapping={ | ||
text_type: fields.String, | ||
int: fields.Integer, | ||
dict: fields.Dict, | ||
}, | ||
class_to_name_overrides={ | ||
text_type: 'str', | ||
}, | ||
) | ||
|
||
|
||
explicit_poly_field_without_overrides = ExplicitPolyField( | ||
class_to_schema_mapping={ | ||
int: fields.Integer, | ||
dict: fields.Dict, | ||
}, | ||
) | ||
|
||
|
||
ExplicitPolyFieldExample = namedtuple( | ||
'ExplicitPolyFieldExample', | ||
[ | ||
'type_name', | ||
'value', | ||
'layer', | ||
'field', | ||
'polyfield', | ||
], | ||
) | ||
|
||
|
||
def create_explicit_poly_field_example(type_name, value, field, polyfield): | ||
return ExplicitPolyFieldExample( | ||
type_name=type_name, | ||
value=value, | ||
layer={'type': type_name, 'value': value}, | ||
field=field, | ||
polyfield=polyfield, | ||
) | ||
|
||
|
||
parametrize_explicit_poly_field_type_name_and_value = pytest.mark.parametrize( | ||
['example'], | ||
[ | ||
[create_explicit_poly_field_example( | ||
type_name=u'str', | ||
value=u'red', | ||
field=fields.String, | ||
polyfield=explicit_poly_field_with_overrides, | ||
)], | ||
[create_explicit_poly_field_example( | ||
type_name=u'int', | ||
value=42, | ||
field=fields.Integer, | ||
polyfield=explicit_poly_field_with_overrides, | ||
)], | ||
[create_explicit_poly_field_example( | ||
type_name=u'dict', | ||
value={u'puppy': 3.9}, | ||
field=fields.Dict, | ||
polyfield=explicit_poly_field_with_overrides, | ||
)], | ||
[create_explicit_poly_field_example( | ||
type_name=u'int', | ||
value=42, | ||
field=fields.Integer, | ||
polyfield=explicit_poly_field_without_overrides, | ||
)], | ||
[create_explicit_poly_field_example( | ||
type_name=u'dict', | ||
value={u'puppy': 3.9}, | ||
field=fields.Dict, | ||
polyfield=explicit_poly_field_without_overrides, | ||
)], | ||
], | ||
) | ||
|
||
|
||
@parametrize_explicit_poly_field_type_name_and_value | ||
def test_serializing_explicit_poly_field(example): | ||
Point = namedtuple('Point', ['x', 'y']) | ||
p = Point(x=example.value, y=37) | ||
|
||
assert example.polyfield.serialize('x', p) == example.layer | ||
|
||
|
||
@parametrize_explicit_poly_field_type_name_and_value | ||
def test_serializing_explicit_poly_field_type_name(example): | ||
Point = namedtuple('Point', ['x', 'y']) | ||
p = Point(x=example.value, y=37) | ||
|
||
serialized = example.polyfield.serialize('x', p) | ||
assert serialized['type'] == example.type_name | ||
|
||
|
||
@parametrize_explicit_poly_field_type_name_and_value | ||
def test_serializing_explicit_poly_field_value(example): | ||
Point = namedtuple('Point', ['x', 'y']) | ||
p = Point(x=example.value, y=37) | ||
|
||
serialized = example.polyfield.serialize('x', p) | ||
assert serialized['value'] is example.value | ||
|
||
|
||
@parametrize_explicit_poly_field_type_name_and_value | ||
def test_deserializing_explicit_poly_field_value(example): | ||
assert example.polyfield.deserialize(example.layer) is example.value | ||
|
||
|
||
@parametrize_explicit_poly_field_type_name_and_value | ||
def test_deserializing_explicit_poly_field_field_type(example): | ||
# TODO: Checking the type only does so much, really want to compare | ||
# the fields but they don't implement == so we'll have to code | ||
# that up to check it. | ||
assert ( | ||
type(example.polyfield.deserialization_schema_selector( | ||
example.layer, | ||
{'x': example.layer}, | ||
)) | ||
is type(example.field()) | ||
) # noqa E721 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than printing I think you should validate the json that comes out with an assertion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just exploratory code and I think it's fully replaced at this point by 'real' tests. It's in the WIP list to be removed.