-
-
Save sloria/b84cd0118337bb3b6d001d959d95a922 to your computer and use it in GitHub Desktop.
Comparison between Marshmallow and Colander
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import timeit | |
import uuid | |
import colander | |
import marshmallow | |
class BarList(colander.SequenceSchema): | |
item = colander.SchemaNode( | |
colander.Integer(), validator=colander.Range(min=1)) | |
class SignupSchema(colander.MappingSchema): | |
@staticmethod | |
def schema_type(): | |
return colander.Mapping(unknown='preserve') | |
username = colander.SchemaNode(colander.String()) | |
foo = colander.SchemaNode( | |
colander.Integer(), validator=colander.Range(min=1)) | |
bar = BarList() | |
@colander.deferred | |
def def_uuid(node, kw): | |
return str(uuid.uuid4()) | |
@colander.deferred | |
def def_validator(node, kw): | |
return colander.Function(lambda v: kw['bound'] == v) | |
class SignupSchemaWithDeferred(SignupSchema): | |
uuid = colander.SchemaNode(colander.String(), missing=def_uuid) | |
bound = colander.SchemaNode(colander.String(), validator=def_validator) | |
class SignupSchemaM(marshmallow.Schema): | |
class Meta: | |
strict = True | |
ordered = True | |
preserve = True | |
username = marshmallow.fields.String(required=True) | |
foo = marshmallow.fields.Integer( | |
required=True, | |
validate=[marshmallow.validate.Range(min=1)]) | |
bar = marshmallow.fields.List(marshmallow.fields.Integer( | |
validate=[marshmallow.validate.Range(min=1)]), many=True) | |
@marshmallow.post_load(pass_original=True) | |
def _add_unknown(self, data, original): | |
"""Preserve unknown keys during deserialization.""" | |
for key, val in original.items(): | |
if key not in self.fields: | |
data[key] = val | |
return data | |
class SignupSchemaContextM(SignupSchemaM): | |
uuid = marshmallow.fields.String(missing=lambda: str(uuid.uuid4())) | |
bound = marshmallow.fields.String() | |
@marshmallow.validates('bound') | |
def validate_bound(self, value): | |
if self.context['bound'] != value: | |
raise marshmallow.ValidationError('WRONG!') | |
data = {'foo': 1, 'bar': [1, 2, 3], | |
'bound': 'YYYY', | |
'baz': {'a': 'test', | |
'b': ['a', 'b', 'c']}, | |
'username': 'ergo'} | |
colander_schema = SignupSchema() | |
def test_colander(): | |
return colander_schema.deserialize(data) | |
colander_bind_schema = SignupSchemaWithDeferred() | |
def test_colander_bind(): | |
schema = colander_bind_schema.bind(bound='YYYY') | |
return schema.deserialize(data) | |
ma_schema = SignupSchemaM() | |
def test_marshmallow(): | |
return ma_schema.load(data) | |
ma_context_schema = SignupSchemaContextM() | |
ma_context_schema.context.setdefault('bound', 'YYYY') | |
def test_marshmallow_context(): | |
return ma_context_schema.load(data) | |
print(test_colander_bind()) | |
print(test_marshmallow_context()) | |
c_result = timeit.timeit(test_colander, number=10000) | |
m_result = timeit.timeit(test_marshmallow, number=10000) | |
print(f'Colander took {c_result:.4f}') | |
print(f'Marshmallow took {m_result:.4f}') | |
print('-----------------------') | |
print(f'Marshmallow took {m_result/c_result:.2f}x of Colander execution time') | |
print('\nNow testing with binds/context\n') | |
c_result = timeit.timeit(test_colander_bind, number=10000) | |
m_result = timeit.timeit(test_marshmallow_context, number=10000) | |
print(f'Colander w/bind took {c_result:.4f}') | |
print(f'Marshmallow w/context took {m_result:.4f}') | |
print('-----------------------') | |
print(f'Marshmallow w/context took {m_result/c_result:.2f}x of Colander w/bind execution time') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Marshmallow 2
Marshmallow 3