Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mikeywaites/kim
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.0.0
Choose a base ref
...
head repository: mikeywaites/kim
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Loading
38 changes: 38 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
jobs:
test:
machine: true
environment:
CIRCLE_ARTIFACTS: /tmp/circleci-artifacts
steps:
- add_ssh_keys:
fingerprints:
- "57:f4:7f:50:32:a3:a2:76:20:69:02:06:3f:5a:2a:48"
- checkout
- run: mkdir -p $CIRCLE_ARTIFACTS
- run: docker-compose run py3
- run: docker-compose run py2
- run: docker-compose run py3 python benchmarks/perf.py | tee $CIRCLE_ARTIFACTS/py3_perf.txt
- run: docker-compose run py2 python benchmarks/perf.py | tee $CIRCLE_ARTIFACTS/py2_perf.txt
- store_artifacts:
path: /tmp/circleci-artifacts
deploy:
machine: true
steps:
- add_ssh_keys:
fingerprints:
- "57:f4:7f:50:32:a3:a2:76:20:69:02:06:3f:5a:2a:48"
- checkout
- run: docker-compose run -e PYPI_PASSWORD=$PYPI_PASSWORD -e PYPI_USERNAME=$PYPI_USERNAME py2 bash -c 'printf "[distutils]\nindex-servers = pypi \n[pypi]\nusername:$PYPI_USERNAME\npassword:$PYPI_PASSWORD" > ~/.pypirc && python setup.py sdist upload'
- run: curl -X POST http://readthedocs.org/build/kim

workflows:
version: 2
test_and_deploy:
jobs:
- test
- deploy:
requires:
- test
filters:
branches:
only: master
65 changes: 65 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,71 @@
Changelog
========================

v1.2.4
-----------------------
Fix issue with output of escaped fields

v1.2.3
-----------------------
Allow use of escape sequence in dot notation for name/source

v1.2.2
-----------------------
Fix issue where min/max would not work on Decimal fields when passed as string

v1.2.1
-----------------------

Fix issue where field.opts.attribute_name would always be None

v1.2.0
-----------------------

This release contains a number of improvements and changes to existing field options as
well as some new Field types

https://github.com/mikeywaites/kim/milestone/4?closed=1

* New Float field (Margaferrez)
* Min/Max options for Decimal field (Margaferrez)
* String Min/Max validation options (Margaferrez)
* Add blank option to String to disallow empty string
* make field default apply when serializing and marshaling
* Error now raise when trying to serialize None
* Default String field to unicode type

v1.1.1
-----------------------
Fix version of iso8601 dependency which was broken by the latest release of that project

v1.1.0
-----------------------

This release focussed solely on improving the peformance of Kim during serialization cycles. Overall Kim
is now around 75% faster.

* Deprecated `Pipe` class. This was causing a huge amount of overhead in `Pipelines`
* Reduced the foot print of `Pipeline` and `Session` with usage of __slots__
* removed marshal_extra_X and serialize_extra_X. Additional pipes are now added to the Pipeline at compile time.
* Avoid duplicate calls to the _MapperRegistry
* optimised the number of time get_mapper_session is called especially in field.Collection runs.
* Added benchmark suite to repo which is run during circle.ci builds

v1.0.3
-----------------------

Removal of Try/Except block from update_output_to_name. This yielded ~10% performance increase.

v1.0.2
-----------------------

Version bump to fix issues with documentation.

v1.0.1
-----------------------

Version bump to fix issues with documentation.

v1.0.0
-----------------------

2 changes: 1 addition & 1 deletion Dockerfile.py3
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3
FROM python:3.7


ADD . /opt/code
22 changes: 9 additions & 13 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
.. Kim documentation master file, created by
sphinx-quickstart on Fri May 15 15:12:15 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Kim: A JSON Serialization and Marshaling framework
=================================================
===================================================

.. image:: https://img.shields.io/pypi/v/py-kim.svg
:target: https://pypi.python.org/pypi/py-kim
@@ -15,11 +10,10 @@ Kim: A JSON Serialization and Marshaling framework
.. image:: https://circleci.com/gh/mikeywaites/kim.svg?style=shield&circle-token=d46954b5e66c2cc885f35c745baaea9a70e961af
:target: https://pypi.python.org/pypi/py-kim


-------------------

**Introducing Kim**::

.. code-block:: python
>>> mapper = UserMapper(data=response.json())
>>> mapper.marshal()
User(id='one', name='Bruce Wayne', 'title'='CEO/Super Hero')
@@ -29,7 +23,7 @@ Kim: A JSON Serialization and Marshaling framework
{u'id': 'two', u'name': 'Martha Wayne', 'title': 'Mother of Batman'}
Kim Features
----------------
------------

Kim is a feature packed framework for handling even the most complex
marshaling and serialization requirements.
@@ -45,17 +39,19 @@ Kim officially supports Python 2.7 & 3.3–3.5


Installation
--------------
------------

Install Kim using pip::

.. code-block:: bash
$ pip install py-kim
Documentation
--------------
-------------

Learn all of Kim's features with these simple step-by-step instructions or check out the
quickstart guide for a rapid overview to get going quickly.

`Kim Documentation <http://kim.readthedocs.io/en/latest/>`_.
http://kim.readthedocs.io/en/latest/
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.0
1.2.4
62 changes: 62 additions & 0 deletions benchmarks/data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from kim import Mapper, field


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


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 serialize(data, many=False):

if many:
return ComplexMapper.many().serialize(data)
else:
ComplexMapper(obj=data).serialize()


test_object = ParentTestObject()
113 changes: 113 additions & 0 deletions benchmarks/perf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import time
from timeit import default_timer as timer
from data import serialize, test_object
from tabulate import tabulate


class timer():
def __init__(self, name=''):
self.name = name

def __enter__(self):
self.start = time.time()
return self

def __exit__(self, type, value, traceback):
self.elapsed = time.time() - self.start


def test_many(limit=1000):
for i in range(0, limit):
serialize([test_object, test_object], many=True)


def test_one(limit=1000):
for i in range(0, limit):
serialize(test_object)


def run():

results = []
with timer('many') as result:
test_many()
results.append(result)

with timer('one') as result:
test_one()
results.append(result)

return results


def report():
"""This function will run our performance benchmarking suite. The Test will serialize
1000 objects once using the many() API and also 1000 objects one at a time using
serialize().
We run the test three times to produce the avg, min and max of each test. The
data and mapper for the test can be found in benchmarks/data.py and represent a
fairly typical set of requirements from a mapper.
Usage::
$ docker-compose run --rm py3 python benchmarks/perf.py
Type Avg Min Max
-------------- -------- -------- --------
Serialize many 1.36577 1.3606 1.36849
Serialize one 0.665721 0.659155 0.671596
$ docker-compose run --rm py2 python benchmarks/perf.py
Type Avg Min Max
-------------- -------- -------- --------
Serialize many 1.22495 1.20991 1.24298
Serialize one 0.599094 0.589109 0.605523
"""

results1 = run()
results2 = run()
results3 = run()

many_results = [results1[0].elapsed, results2[0].elapsed, results3[0].elapsed]
one_results = [results1[1].elapsed, results2[1].elapsed, results3[1].elapsed]

many_avg = (many_results[0] + many_results[1] + many_results[2]) / 3
one_avg = (one_results[0] + one_results[1] + one_results[2]) / 3

def find_min(results):

min_result = None
for result in results:
if min_result is None:
min_result = result
elif result < min_result:
min_result = result

return min_result

def find_max(results):

max_result = None
for result in results:
if max_result is None:
max_result = result
elif result > max_result:
max_result = result

return max_result

many_min = find_min(many_results)
one_min = find_min(one_results)
many_max = find_max(many_results)
one_max = find_max(one_results)

table = []
table.append(['Serialize Many', many_avg, many_min, many_max])
table.append(['Serialize One', one_avg, one_min, one_max])

print(tabulate(table, headers=['Test', 'Avg', 'Min', 'Max']))


if __name__ == "__main__":

report()
39 changes: 39 additions & 0 deletions benchmarks/prof.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import cProfile

from data import serialize, test_object


def do_cprofile(func):
def profiled_func(*args, **kwargs):
profile = cProfile.Profile()
try:
profile.enable()
result = func(*args, **kwargs)
profile.disable()
return result
finally:
profile.print_stats('cumulative')
return profiled_func


@do_cprofile
def test_many(limit=1000):
for i in range(0, limit):
serialize([test_object, test_object], many=True)


@do_cprofile
def test_one(limit=1000):
for i in range(0, limit):
serialize(test_object)


def run():

test_many()
test_one()


if __name__ == '__main__':

run()
Loading