diff --git a/.gitignore b/.gitignore deleted file mode 100644 index e01da55..0000000 --- a/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.cache/ -.venv/ -__pycache__ -*.pyc -index.html -REPORT.md diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index bb38d26..0000000 --- a/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: python -python: -- '3.6' -install: pip install -r requirements.txt -script: py.test -deploy: - provider: script - script: bash ./deploy.sh - on: - branch: master -env: - global: - - ENCRYPTION_LABEL: 1dbde6ec09a5 - - COMMIT_AUTHOR_EMAIL: voidfiles@gmail.com diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 9340b01..0000000 --- a/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM python:3 - - -ADD . /opt/code -WORKDIR /opt/code/ - -RUN pip install -r requirements.txt -CMD ["python", "benchmark.py"] diff --git a/README.md b/README.md deleted file mode 100644 index 34eefc2..0000000 --- a/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Python Serialization Benchmark - -This [repository](http://github.com/voidfiles/python-serialization-benchmark) maintains a set of benchmarks for python serialization frameworks. - -You can find the latest benchmarks on [this page](https://voidfiles.github.io/python-serialization-benchmark/). - -Currently the following projects are benchmarked. - -* [Django REST Framework](http://www.django-rest-framework.org/) -* [serpy](http://serpy.readthedocs.io/) -* [Marshmallow](https://marshmallow.readthedocs.io/en/latest/) -* [Strainer](https://github.com/voidfiles/strainer) -* [Lollipop](http://lollipop.readthedocs.io/en/latest/) -* [Kim](http://kim.readthedocs.io/en/latest/) -* [Toasted Marshmallow](https://github.com/lyft/toasted-marshmallow) -* [Colander](https://docs.pylonsproject.org/projects/colander/en/latest/) -* [Lima](https://github.com/b6d/lima/) -- [Serpyco](https://gitlab.com/sgrignard/serpyco) -* [Avro](https://avro.apache.org/) - -Along with a baseline custom function that doesn't use a framework. - - -## Running the test suite - -A Docker container is bundled with the repository which you can use to run the benchmarks. Firstly make sure you have Docker installed. - -1. Install Docker - -2. Build the container `$ docker-compose build` - -3. Run the tests. `$ docker-compose run --rm tests` diff --git a/benchmark.py b/benchmark.py deleted file mode 100755 index c757131..0000000 --- a/benchmark.py +++ /dev/null @@ -1,49 +0,0 @@ -import time -from tabulate import tabulate -from contextlib import contextmanager - -from subjects import (marsh, rf, serp, strain, col, hand, loli, k, lim, tmarsh, avro, pickle, serpy) -from data import ParentTestObject - -SUBJECTS = (marsh, rf, serp, strain, col, hand, loli, k, lim, tmarsh, avro, pickle, serpy) - -test_object = ParentTestObject() - - -@contextmanager -def timer(tracker): - start = time.time() - yield - end = time.time() - tracker += [end - start] - - -def test_many(func, limit=1000): - for i in range(0, limit): - subject.serialization_func([test_object, test_object], True) - - -def test_one(func, limit=1000): - for i in range(0, limit): - subject.serialization_func(test_object, False) - -table = [] -for subject in SUBJECTS: - row = [subject.name] - - test_many(subject.serialization_func, 2) # Warmup - with timer(row): - test_many(subject.serialization_func) - - test_one(subject.serialization_func, 2) # Warmup - with timer(row): - test_one(subject.serialization_func) - - table += [row] - -table = sorted(table, key=lambda x: x[1] + x[2]) -relative_base = min([x[1] + x[2] for x in table]) -for row in table: - result = (row[1] + row[2]) / relative_base - row.append(result) -print(tabulate(table, headers=['Library', 'Many Objects (seconds)', 'One Object (seconds)', 'Relative'])) diff --git a/create_report.sh b/create_report.sh deleted file mode 100755 index 320a75c..0000000 --- a/create_report.sh +++ /dev/null @@ -1,18 +0,0 @@ -#! /bin/bash - -cat README.md > REPORT.md -echo "\`\`\`" >> REPORT.md -python benchmark.py >> REPORT.md -echo "\`\`\`" >> REPORT.md -cat disscussion.md >> REPORT.md -mkdir -p out -echo '' > out/index.html -echo '' >> out/index.html -echo '' >> out/index.html -echo '' >> out/index.html -echo '' >> out/index.html -echo '
' >> out/index.html -python -m markdown -x markdown.extensions.fenced_code REPORT.md >> out/index.html -echo '
' >> out/index.html -echo '' >> out/index.html -echo '' >> out/index.html diff --git a/data.py b/data.py deleted file mode 100644 index ff11bab..0000000 --- a/data.py +++ /dev/null @@ -1,17 +0,0 @@ - -class ChildTestObject(object): - def __init__(self, multiplier=None): - self.w = 1000 * multiplier if multiplier else 100 - self.x = 20 * multiplier if multiplier else 20 - self.y = 'hello' * multiplier if multiplier else 'hello' - self.z = 10 * multiplier if multiplier else 10 - - -class ParentTestObject(object): - def __init__(self): - self.foo = 'bar' - self.sub = ChildTestObject() - self.subs = [ChildTestObject(i) for i in range(10)] - - def bar(self): - return 5 diff --git a/deploy-key.enc b/deploy-key.enc deleted file mode 100644 index 4c226d2..0000000 Binary files a/deploy-key.enc and /dev/null differ diff --git a/deploy.sh b/deploy.sh deleted file mode 100755 index 40dbb59..0000000 --- a/deploy.sh +++ /dev/null @@ -1,60 +0,0 @@ -#! /bin/bash -set -ex # Exit with nonzero exit code if anything fails - -SOURCE_BRANCH="master" -TARGET_BRANCH="gh-pages" - -function doCompile { - ./create_report.sh -} - -# Pull requests and commits to other branches shouldn't try to deploy, just build to verify -if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "$SOURCE_BRANCH" ]; then - echo "Skipping deploy; just doing a build." - doCompile - exit 0 -fi - -# Save some useful information -REPO=`git config remote.origin.url` -SSH_REPO=${REPO/https:\/\/github.com\//git@github.com:} -SHA=`git rev-parse --verify HEAD` - -# Clone the existing gh-pages for this repo into out/ -# Create a new empty branch if gh-pages doesn't exist yet (should only happen on first deply) -git clone $REPO out -cd out -git checkout $TARGET_BRANCH || git checkout --orphan $TARGET_BRANCH -cd .. - -# Clean out existing contents -rm -rf out/**/* || exit 0 - -# Run our compile script -doCompile - -# Now let's go have some fun with the cloned repo -cd out -git config user.name "Travis CI" -git config user.email "$COMMIT_AUTHOR_EMAIL" - -# Commit the "changes", i.e. the new version. -# The delta will show diffs between new and old versions. -git add . -git commit -m "Deploy to GitHub Pages: ${SHA}" - -# Get the deploy key by using Travis's stored variables to decrypt deploy_key.enc -ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_LABEL}_key" -ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_LABEL}_iv" -ENCRYPTED_KEY=${!ENCRYPTED_KEY_VAR} -ENCRYPTED_IV=${!ENCRYPTED_IV_VAR} -openssl aes-256-cbc -K $ENCRYPTED_KEY -iv $ENCRYPTED_IV -in ../deploy-key.enc -out deploy-key -d -chmod 600 deploy-key -eval `ssh-agent -s` -ssh-add deploy-key - -rm -fR __pycache__ -rm -fR subjects/__pycache__ - -# Now that we're all set up, we can push. -git push $SSH_REPO $TARGET_BRANCH diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 21ff9bc..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,6 +0,0 @@ -tests: - build: . - command: python benchmark.py - dockerfile: Dockerfile - volumes: - - .:/opt/code diff --git a/disscussion.md b/index.html similarity index 56% rename from disscussion.md rename to index.html index 1494574..ef32fb9 100644 --- a/disscussion.md +++ b/index.html @@ -1,11 +1,60 @@ -## The Benchmark - -Each framework is asked to serialize a list of 2 objects a 1000 times, and then 1 object a 1000 times. - -This is the current object that is being serialized. - -```python -class ChildTestObject(object): + + + + + +
+

Python Serialization Benchmark

+

This repository maintains a set of benchmarks for python serialization frameworks.

+

You can find the latest benchmarks on this page.

+

Currently the following projects are benchmarked.

+ +

Along with a baseline custom function that doesn't use a framework.

+

Running the test suite

+

A Docker container is bundled with the repository which you can use to run the benchmarks. Firstly make sure you have Docker installed.

+
    +
  1. +

    Install Docker

    +
  2. +
  3. +

    Build the container $ docker-compose build

    +
  4. +
  5. +

    Run the tests. $ docker-compose run --rm tests

    +
  6. +
+
Library                  Many Objects (seconds)    One Object (seconds)    Relative
+---------------------  ------------------------  ----------------------  ----------
+serpyco                              0.00796103              0.00404453     1
+Custom                               0.009902                0.00483012     1.22711
+lima                                 0.012424                0.00625205     1.55562
+Pickle                               0.0180094               0.0179398      2.99438
+serpy                                0.0356748               0.0189779      4.55228
+Strainer                             0.0529356               0.0261641      6.58858
+Toasted Marshmallow                  0.0865085               0.0465157     11.0802
+Colander                             0.238111                0.116309      29.5214
+Lollipop                             0.32454                 0.156491      40.0673
+Avro                                 0.442609                0.220602      55.2419
+Marshmallow                          0.496984                0.242603      61.6036
+kim                                  0.616623                0.307922      77.0097
+Django REST Framework                0.761326                0.527056     107.315
+
+

The Benchmark

+

Each framework is asked to serialize a list of 2 objects a 1000 times, and then 1 object a 1000 times.

+

This is the current object that is being serialized.

+
class ChildTestObject(object):
     def __init__(self, multiplier=None):
         self.w = 1000 * multiplier if multiplier else 100
         self.x = 20 * multiplier if multiplier else 20
@@ -23,12 +72,9 @@
         return 5
 
 benchmark_object = ParentTestObject()
-```
-
-## Discussion
-
-Serialization from python objects to JSON, XML, or other transmission formats is a common task for many web related projects. In order to fill that need a number of frameworks have arised. While their aims are similar, they don't all share the same attributes. Here are how some of the features comapre.
-
+
+

Discussion

+

Serialization from python objects to JSON, XML, or other transmission formats is a common task for many web related projects. In order to fill that need a number of frameworks have arised. While their aims are similar, they don't all share the same attributes. Here are how some of the features comapre.

@@ -120,8 +166,12 @@
-* **Serialization**: Does the framework provide a way of serializing python objects to simple datastructures -* **Encoding**: Does the framework provide a way of encoding data into a wire format -* **Deserialization**: Does the framework provide a way of deserializing simple data structures into complex data structures -* **Validation**: Does the framework provide a way of validating datastructures, and reprorting error conditions -* **Part of Framework**: Is serialization apart of a larger framework +
+ + diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 8d71761..0000000 --- a/requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -toastedmarshmallow==2.15.2.post1 -serpy==0.3.1 -colander==1.7.0 -djangorestframework==3.9.4 -django==2.2.13 -pytest -pystrainer==1.3.0 -tabulate==0.7.7 -lollipop==1.1.7 -py-kim==1.2.2 -lima==0.5 -markdown -avro-python3==1.8.2 -serpyco==1.1.0 \ No newline at end of file diff --git a/subjects/__init__.py b/subjects/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/subjects/avro.py b/subjects/avro.py deleted file mode 100644 index fe797b2..0000000 --- a/subjects/avro.py +++ /dev/null @@ -1,74 +0,0 @@ -import avro.schema -from avro.io import DatumWriter - -name = 'Avro' - -class NullWriter(object): - def write(self, *args, **kwargs): - pass - - def write_utf8(self, *args, **kwargs): - self.write(args, kwargs) - - def write_int(self, *args, **kwargs): - self.write(args, kwargs) - - def write_long(self, *args, **kwargs): - self.write(args, kwargs) - -schema_name_tracker = avro.schema.Names() - -child_test_object_schema = avro.schema.SchemaFromJSONData({ - "namespace": "benchmark.avro", - "type": "record", - "name": "childTestObject", - "fields": [ - {"name": "w", "type": "int"}, - {"name": "x", "type": "int"}, - {"name": "y", "type": "string"}, - {"name": "z", "type": "int"} - ] -}, names=schema_name_tracker) - -parent_test_object_schema = avro.schema.SchemaFromJSONData({ - "namespace": "benchmark.avro", - "type": "record", - "name": "parentTestObject", - "fields": [ - {"name": "foo", "type": "string"}, - {"name": "sub", "type": "childTestObject"}, - { - "name": "subs", - "type": { - "type": "array", - "items": "childTestObject" - } - } - ] -}, names=schema_name_tracker) - -datum_writer = DatumWriter(writer_schema=parent_test_object_schema) -null_binary_writer = NullWriter() - -# Avro for Python can't directly serialize a class, it must be a dictionary. -def nested_class_to_dict(obj): - if not hasattr(obj,"__dict__"): - return obj - result = {} - for key, val in obj.__dict__.items(): - if key.startswith("_"): - continue - element = [] - if isinstance(val, list): - for item in val: - element.append(nested_class_to_dict(item)) - else: - element = nested_class_to_dict(val) - result[key] = element - return result - -def serialization_func(to_serialize, many): - if many: - return [datum_writer.write(nested_class_to_dict(obj), null_binary_writer) for obj in to_serialize] - else: - return datum_writer.write(nested_class_to_dict(to_serialize), null_binary_writer) diff --git a/subjects/col.py b/subjects/col.py deleted file mode 100755 index fe2e3b5..0000000 --- a/subjects/col.py +++ /dev/null @@ -1,111 +0,0 @@ -import colander -from colander import null - -name = 'Colander' - - -class ObjectType(colander.Mapping): - """ - A colander type representing a generic python object - (uses colander mapping-based serialization). - """ - - def serialize(self, node, appstruct): - appstruct = appstruct.__dict__ - return super(ObjectType, self).serialize(node, appstruct) - - def deserialize(self, node, cstruct): - data = super(ObjectType, self).deserialize(node, cstruct) - appstruct = node.instance.__class__() - appstruct.__dict__.update(data) - return appstruct - - -class ObjectSchema(colander.SchemaNode): - schema_type = ObjectType - instance = None - - def serialize(self, appstruct): - if not self.instance: - # set the instance on all child schema nodes as they - # may need to access the instance environment - self.instance = appstruct - for subnode in self.children: - if isinstance(subnode, MethodSchema): - setattr(subnode, 'instance', appstruct) - return super(ObjectSchema, self).serialize(appstruct) - - def deserialize(self, cstruct): - appstruct = super(ObjectSchema, self).deserialize(cstruct) - if not self.instance: - self.instance = appstruct - return appstruct - - -class CallableSchema(colander.SchemaNode): - def serialize(self, appstruct): - if appstruct is null: - return null - appstruct = appstruct() - return super(CallableSchema, self).serialize(appstruct) - - def deserialize(self, cstruct): - if cstruct is null: - return null - appstruct = super(CallableSchema, self).deserialize(cstruct) - return lambda: appstruct - - -class MethodSchema(CallableSchema): - def serialize(self, appstruct): - if appstruct is null: - appstruct = getattr(self.instance, self.name) - return super(MethodSchema, self).serialize(appstruct) - - -class Differential(colander.SchemaNode): - def __init__(self, typ, differential=0): - self.differential = differential - super(Differential, self).__init__(typ) - - def serialize(self, appstruct): - # operator could be overloaded by the appstruct class if necessary - appstruct += self.differential - return super(Differential, self).serialize(appstruct) - - def deserialize(self, cstruct): - # operator could be overloaded by the appstruct class if necessary - appstruct = super(Differential, self).deserialize(cstruct) - appstruct -= self.differential - return appstruct - - -class ChildSchema(ObjectSchema): - w = colander.SchemaNode(colander.Int()) - y = colander.SchemaNode(colander.String()) - x = Differential(colander.Int(), 10) - z = colander.SchemaNode(colander.Int()) - - -class ChildListSchema(colander.SequenceSchema): - sub = ChildSchema() - - -class ParentSchema(ObjectSchema): - foo = colander.SchemaNode(colander.String()) - bar = MethodSchema(colander.Int()) - sub = ChildSchema() - subs = ChildListSchema() - - -class ParentListSchema(colander.SequenceSchema): - parents = ParentSchema() - - -unit_schema = ParentSchema() -seq_schema = ParentListSchema() - - -def serialization_func(obj, many): - schema = seq_schema if many else unit_schema - return schema.serialize(obj) diff --git a/subjects/hand.py b/subjects/hand.py deleted file mode 100644 index 8e29b8e..0000000 --- a/subjects/hand.py +++ /dev/null @@ -1,26 +0,0 @@ -name = 'Custom' - - -def sub_to_cstruct(obj): - return { - 'w': obj.w, - 'y': obj.y, - 'x': obj.x + 10, - 'z': obj.z - } - - -def obj_to_cstruct(obj): - return { - 'foo': obj.foo, - 'bar': obj.bar(), - 'sub': sub_to_cstruct(obj.sub), - 'subs': [sub_to_cstruct(x) for x in obj.subs], - } - - -def serialization_func(obj, many): - if many: - return [obj_to_cstruct(x) for x in obj] - else: - return obj_to_cstruct(obj) diff --git a/subjects/k.py b/subjects/k.py deleted file mode 100644 index 7e49c89..0000000 --- a/subjects/k.py +++ /dev/null @@ -1,42 +0,0 @@ -from kim import Mapper, field - -name = 'kim' - - -class Complex(object): - pass - - -class SubResource(object): - pass - - -def bar_pipe(session): - session.output['bar'] = session.data() - - -def x_pipe(session): - session.output['x'] = session.data + 10 - - -class SubMapper(Mapper): - __type__ = SubResource - w = field.String() - x = field.String(extra_serialize_pipes={'output': [x_pipe]}) - y = field.String() - z = field.String() - - -class ComplexMapper(Mapper): - __type__ = Complex - foo = field.String() - bar = field.String(extra_serialize_pipes={'output': [bar_pipe]}) - sub = field.Nested(SubMapper) - subs = field.Collection(field.Nested(SubMapper)) - - -def serialization_func(obj, many): - if many: - return ComplexMapper.many().serialize(obj) - else: - return ComplexMapper(obj=obj).serialize() diff --git a/subjects/lim.py b/subjects/lim.py deleted file mode 100644 index 4061d9f..0000000 --- a/subjects/lim.py +++ /dev/null @@ -1,28 +0,0 @@ -import lima - -name = 'lima' - - -class SubM(lima.Schema): - w = lima.fields.Integer() - x = lima.fields.Integer(get=lambda obj: obj.x + 10) - y = lima.fields.Integer() - z = lima.fields.Integer() - - -class ComplexM(lima.Schema): - foo = lima.fields.String() - bar = lima.fields.Integer(get=lambda obj: obj.bar()) - sub = lima.fields.Embed(schema=SubM) - subs = lima.fields.Embed(schema=SubM, many=True) - - -schema = ComplexM() -many_scheam = ComplexM(many=True) - - -def serialization_func(obj, many): - if many: - return many_scheam.dump(obj) - else: - return schema.dump(obj) diff --git a/subjects/loli.py b/subjects/loli.py deleted file mode 100644 index 1c2e247..0000000 --- a/subjects/loli.py +++ /dev/null @@ -1,33 +0,0 @@ -from collections import namedtuple -from lollipop.types import Object, String, Integer, List, FunctionField, MethodField - -name = 'Lollipop' - -SubS = namedtuple('SubS', ['w', 'x', 'y', 'z']) -ComplexS = namedtuple('ComplexS', ['foo', 'bar', 'sub', 'subs']) - - -def get_x(obj): - return obj.x + 10 - - -SubSType = Object({ - 'w': Integer(), - 'x': FunctionField(Integer(), get_x), - 'y': String(), - 'z': Integer(), -}, constructor=SubS) - -ComplexSType = Object({ - 'foo': String(), - 'bar': MethodField(Integer(), 'bar'), - 'sub': SubSType, - 'subs': List(SubSType), -}, constructor=ComplexS) - - -def serialization_func(obj, many): - if many: - return List(ComplexSType).dump(obj) - else: - return ComplexSType.dump(obj) diff --git a/subjects/marsh.py b/subjects/marsh.py deleted file mode 100644 index 34112ff..0000000 --- a/subjects/marsh.py +++ /dev/null @@ -1,27 +0,0 @@ -import marshmallow - -name = 'Marshmallow' - - -class SubM(marshmallow.Schema): - w = marshmallow.fields.Int() - x = marshmallow.fields.Method('get_x') - y = marshmallow.fields.Str() - z = marshmallow.fields.Int() - - def get_x(self, obj): - return obj.x + 10 - - -class ComplexM(marshmallow.Schema): - bar = marshmallow.fields.Int() - foo = marshmallow.fields.Str() - sub = marshmallow.fields.Nested(SubM) - subs = marshmallow.fields.Nested(SubM, many=True) - - -schema = ComplexM() - - -def serialization_func(obj, many): - return schema.dump(obj, many=many).data diff --git a/subjects/pickle.py b/subjects/pickle.py deleted file mode 100644 index b67a780..0000000 --- a/subjects/pickle.py +++ /dev/null @@ -1,7 +0,0 @@ -import pickle - -name = 'Pickle' - - -def serialization_func(obj, many): - return pickle.dumps(obj) diff --git a/subjects/rf.py b/subjects/rf.py deleted file mode 100644 index 5c36cbc..0000000 --- a/subjects/rf.py +++ /dev/null @@ -1,30 +0,0 @@ -from django.conf import settings -settings.configure() - -import django -django.setup() - -from rest_framework import serializers as rf_serializers - -name = 'Django REST Framework' - - -class SubRF(rf_serializers.Serializer): - w = rf_serializers.IntegerField() - x = rf_serializers.SerializerMethodField() - y = rf_serializers.CharField() - z = rf_serializers.IntegerField() - - def get_x(self, obj): - return obj.x + 10 - - -class ComplexRF(rf_serializers.Serializer): - foo = rf_serializers.CharField() - bar = rf_serializers.IntegerField() - sub = SubRF() - subs = SubRF(many=True) - - -def serialization_func(obj, many): - return ComplexRF(obj, many=many).data diff --git a/subjects/serp.py b/subjects/serp.py deleted file mode 100644 index 28f5668..0000000 --- a/subjects/serp.py +++ /dev/null @@ -1,24 +0,0 @@ -import serpy - -name = 'serpy' - - -class SubS(serpy.Serializer): - w = serpy.IntField() - x = serpy.MethodField() - y = serpy.StrField() - z = serpy.IntField() - - def get_x(self, obj): - return obj.x + 10 - - -class ComplexS(serpy.Serializer): - foo = serpy.StrField() - bar = serpy.IntField(call=True) - sub = SubS() - subs = SubS(many=True) - - -def serialization_func(obj, many): - return ComplexS(obj, many=many).data diff --git a/subjects/serpy.py b/subjects/serpy.py deleted file mode 100644 index 66511f9..0000000 --- a/subjects/serpy.py +++ /dev/null @@ -1,35 +0,0 @@ -import dataclasses -import typing - -import serpyco - -from data import ParentTestObject - -name = "serpyco" - - -def get_x(obj): - return obj.x + 10 - - -@dataclasses.dataclass -class SubM: - w: int - y: str - z: int - x: int = serpyco.field(getter=get_x) - - -@dataclasses.dataclass -class ComplexM: - foo: str - sub: SubM - subs: typing.List[SubM] - bar: int = serpyco.field(getter=ParentTestObject.bar) - - -serializer = serpyco.Serializer(ComplexM) - - -def serialization_func(obj, many): - return serializer.dump(obj, many=many) diff --git a/subjects/strain.py b/subjects/strain.py deleted file mode 100644 index 922799a..0000000 --- a/subjects/strain.py +++ /dev/null @@ -1,24 +0,0 @@ -import strainer - -name = 'Strainer' - -sub_strainer_serializer = strainer.serializer( - strainer.field('w'), - strainer.field('x', attr_getter=lambda obj: obj.x + 10), - strainer.field('y'), - strainer.field('z'), -) - -complex_strainer_serializer = strainer.serializer( - strainer.field('foo'), - strainer.field('bar', attr_getter=lambda obj: obj.bar()), - strainer.child('sub', serializer=sub_strainer_serializer), - strainer.many('subs', serializer=sub_strainer_serializer), -) - - -def serialization_func(obj, many): - if many: - return [complex_strainer_serializer.serialize(x) for x in obj] - else: - return complex_strainer_serializer.serialize(obj) diff --git a/subjects/tmarsh.py b/subjects/tmarsh.py deleted file mode 100644 index 39d44cd..0000000 --- a/subjects/tmarsh.py +++ /dev/null @@ -1,29 +0,0 @@ -import toastedmarshmallow -import marshmallow - -name = 'Toasted Marshmallow' - - -class SubM(marshmallow.Schema): - w = marshmallow.fields.Int() - x = marshmallow.fields.Method('get_x') - y = marshmallow.fields.Str() - z = marshmallow.fields.Int() - - def get_x(self, obj): - return obj.x + 10 - - -class ComplexM(marshmallow.Schema): - foo = marshmallow.fields.Str() - bar = marshmallow.fields.Int() - sub = marshmallow.fields.Nested(SubM) - subs = marshmallow.fields.Nested(SubM, many=True) - - -schema = ComplexM() -schema.jit = toastedmarshmallow.Jit - - -def serialization_func(obj, many): - return schema.dump(obj, many=many).data diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/test_serializers.py b/tests/test_serializers.py deleted file mode 100644 index 1b8016a..0000000 --- a/tests/test_serializers.py +++ /dev/null @@ -1,53 +0,0 @@ -from subjects import rf, serp, strain, col, hand, loli, k, lim, tmarsh -from data import ParentTestObject -import pprint -TARGET = { - 'foo': 'bar', - 'bar': 5, - 'sub': {'w': 100, 'y': 'hello', 'z': 10, 'x': 30}, - 'subs': [ - {'w': 100, 'y': 'hello', 'z': 10, 'x': 30}, - {'w': 1000, 'y': 'hello', 'z': 10, 'x': 30}, - {'w': 2000, 'y': 'hellohello', 'z': 20, 'x': 50}, - {'w': 3000, 'y': 'hellohellohello', 'z': 30, 'x': 70}, - {'w': 4000, 'y': 'hellohellohellohello', 'z': 40, 'x': 90}, - {'w': 5000, 'y': 'hellohellohellohellohello', 'z': 50, 'x': 110}, - {'w': 6000, 'y': 'hellohellohellohellohellohello', 'z': 60, 'x': 130}, - {'w': 7000, 'y': 'hellohellohellohellohellohellohello', 'z': 70, 'x': 150}, - { - 'w': 8000, - 'y': 'hellohellohellohellohellohellohellohello', - 'z': 80, - 'x': 170, - }, { - 'w': 9000, - 'y': 'hellohellohellohellohellohellohellohellohello', - 'z': 90, - 'x': 190, - } - ] -} - - -def test_serializers(): - test_object = ParentTestObject() - - for subject in (rf, tmarsh, serp, strain, col, hand, loli, k, lim): - print(subject.__name__) - data = subject.serialization_func(test_object, False) - pprint.pprint(data) - assert str(data['foo']) == str(TARGET['foo']) - assert str(data['bar']) == str(TARGET['bar']) - assert str(data['sub']['w']) == str(TARGET['sub']['w']) - assert str(data['subs'][3]['y']) == str(TARGET['subs'][3]['y']) - assert str(data['subs'][3]['x']) == str(TARGET['subs'][3]['x']) - - datas = subject.serialization_func([test_object, test_object], True) - for data in datas: - assert str(data['foo']) == str(TARGET['foo']) - assert str(data['sub']['w']) == str(TARGET['sub']['w']) - assert str(data['subs'][3]['y']) == str(TARGET['subs'][3]['y']) - assert str(data['subs'][3]['x']) == str(TARGET['subs'][3]['x']) - -if __name__ == '__main__': - test_serializers()