Skip to content

Commit

Permalink
Merge branch 'feature-refactor' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
by46 committed Feb 3, 2016
2 parents e5c7ff2 + 08222aa commit 59feba5
Show file tree
Hide file tree
Showing 8 changed files with 326 additions and 6 deletions.
2 changes: 2 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
History
======
0.0.6

0.0.5
--------------
1. refactor objson module
Expand Down
2 changes: 1 addition & 1 deletion simplekit/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__author__ = 'benjamin.c.yan'
__version__ = "0.0.5"
__version__ = "0.0.6"

3 changes: 2 additions & 1 deletion simplekit/objson/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from .dolphin import load, loads, dump, dumps
from .dolphin import make_dynamic_class
from .dolphin2 import loads as loads2, load as load2, dump as dump2, dumps as dumps2

__author__ = 'benjamin.c.yan'
__all__ =["load", "loads", "dump", "dumps", "make_dynamic_class"]
__all__ = ["load", "loads", "dump", "dumps", "make_dynamic_class"]
6 changes: 3 additions & 3 deletions simplekit/objson/dolphin.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
__author__ = 'benjamin.c.yan'

import json
import itertools
import functools

from .dynamic_class import make_dynamic_class

__author__ = 'benjamin.c.yan'

_knapsack = {}

Expand Down Expand Up @@ -78,6 +78,7 @@ def dump(obj, fp, *args, **kwargs):


def _load(fn):
@functools.wraps(fn)
def tmp(src, *args, **kwargs):
"""Deserialize json string to a object
Expand Down Expand Up @@ -107,4 +108,3 @@ def tmp(src, *args, **kwargs):

load = _load(json.load)
loads = _load(json.loads)

133 changes: 133 additions & 0 deletions simplekit/objson/dolphin2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import json
import functools
import re
from keyword import iskeyword

__author__ = 'benjamin.c.yan'

_re_encode = re.compile('[^a-zA-Z0-9]', re.MULTILINE)


def object2dict(obj):
d = {}
for key in obj:
d[key] = obj[key]
return d


def object_hook(obj):
return Dolphin(obj)


class Dolphin(object):
def __init__(self, other=None):
if isinstance(other, (dict, Dolphin)):
for key in other:
self[key] = other[key]

def __iter__(self):
return iter(self.__dict__)

def __getitem__(self, key):
if not key.startswith('_'):
return self.__dict__.get(key)

def __setitem__(self, key, value):
if not key.startswith('_'):
self.__dict__[key] = value

def __getattr__(self, name):
if not name.startswith('_'):
if name in self:
return self[name]
elif name.startswith('m') and (iskeyword(name[1:]) or len(name) > 1 and name[1].isdigit()):
return self[name[1:]]
elif '_' in name:
return self[_re_encode.sub('-', name)]


def __str__(self):
return '%s (%s)' % (self.__class__.__name__, repr(self))


def __repr__(self):
keys = sorted(self.__dict__.keys())
text = ', '.join('%s=%r' % (key, self[key]) for key in keys)
return '{%s}' % text


def dumps(obj, *args, **kwargs):
"""Serialize a object to string
Basic Usage:
>>> import simplekit.objson
>>> obj = {'name':'wendy'}
>>> print simplekit.objson.dumps(obj)
:param obj: a object which need to dump
:param args: Optional arguments that :func:`json.dumps` takes.
:param kwargs: Keys arguments that :py:func:`json.dumps` takes.
:return: string
"""
kwargs['default'] = object2dict

return json.dumps(obj, *args, **kwargs)


def dump(obj, fp, *args, **kwargs):
"""Serialize a object to a file object.
Basic Usage:
>>> import simplekit.objson
>>> from cStringIO import StringIO
>>> obj = {'name': 'wendy'}
>>> io = StringIO()
>>> simplekit.objson.dump(obj, io)
>>> print io.getvalue()
:param obj: a object which need to dump
:param fp: a instance of file object
:param args: Optional arguments that :func:`json.dump` takes.
:param kwargs: Keys arguments that :func:`json.dump` takes.
:return: None
"""
kwargs['default'] = object2dict

json.dump(obj, fp, *args, **kwargs)



def _load(fn):
@functools.wraps(fn)
def tmp(src, *args, **kwargs):
"""Deserialize json string to a object
Provide a brief way to represent a object, Can use ``.`` operate access
Json object property
Basic Usage:
>>> from simplekit import objson
>>> text = r'{"Name":"wendy"}'
>>> obj = objson.loads(text)
>>> assert obj.Name == 'wendy'
:param src: string or file object
:param args: Optional arguments that :func:`json.load` takes.
:param kwargs: Keys arguments that :func:`json.loads` takes.
:return: :class:`object` or :class:`list`
"""
try:
kwargs['object_hook'] = object_hook
return fn(src, *args, **kwargs)
except ValueError:
return None

return tmp


load = _load(json.load)
loads = _load(json.loads)
99 changes: 99 additions & 0 deletions tests/benchmark_objson.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import time
import json
from simplekit import objson

__author__ = 'benjamin.c.yan'


def benchmark(fn):
def mark(*args, **kwargs):
now = time.time()
result = fn(*args, **kwargs)
print 'time, ', time.time() - now
return result

return mark


@benchmark
def benchmark_objson(text, times=100000):
for _ in xrange(times):
objson.loads2(text)


@benchmark
def benchmark_json(text, times=100000):
for _ in xrange(times):
json.loads(text)


@benchmark
def benchmark_objson_get(text, times=1000000):
obj = objson.loads2(text)
for _ in xrange(times):
x = obj.name


@benchmark
def benchmark_json_get(text, times=1000000):
obj = json.loads(text)
for _ in xrange(times):
x = obj['name']


@benchmark
def benchmark_objson_set(text, times=1000000):
obj = objson.loads2(text)
for _ in xrange(times):
obj.name = 'benjamin2'


@benchmark
def benchmark_json_set(text, times=1000000):
obj = json.loads(text)
for _ in xrange(times):
obj['name'] = 'benjamin2'


@benchmark
def benchmark_objson_set(text, times=1000000):
obj = objson.loads2(text)
for _ in xrange(times):
obj.name = 'benjamin2'


@benchmark
def benchmark_json_set(text, times=1000000):
obj = json.loads(text)
for _ in xrange(times):
obj['name'] = 'benjamin2'


@benchmark
def benchmark_objson_dumps(text, times=100000):
obj = objson.loads2(text)
for _ in xrange(times):
objson.dumps2(obj)


@benchmark
def benchmark_json_dumps(text, times=100000):
obj = json.loads(text)
for _ in xrange(times):
json.dumps(obj)


if __name__ == '__main__':
text = '{"name": "benjamin.c.yan", "name2": "benjamin.c.yan",' \
'"name3": "benjamin.c.yan", "name4": "benjamin.c.yan", ' \
'"name5": "benjamin.c.yan", "name6": "benjamin.c.yan", ' \
'"name7": "benjamin.c.yan", "name8": "benjamin.c.yan", ' \
'"name9": "benjamin.c.yan", "name0": "benjamin.c.yan"}'
benchmark_objson(text)
benchmark_json(text)
benchmark_objson_get(text)
benchmark_json_get(text)
benchmark_objson_set(text)
benchmark_json_set(text)
benchmark_objson_dumps(text)
benchmark_json_dumps(text)
2 changes: 2 additions & 0 deletions tests/objson2_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ def test_multi_object(self):
persons = sorted(persons, lambda x, y: x.name < y.name)
self.assertEqual(u"benjamin", persons[0].name)
self.assertEqual(u"wendy", persons[1].name)


85 changes: 84 additions & 1 deletion tests/objson_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ def test_dump_normal2(self):
expected = objson.dumps([dict(name='benjamin', age=21)])
self.assertEqual(json.loads(text), json.loads(expected))


def test_dump_change_value(self):
text = r'{"name":"benjamin", "age":21}'
obj = objson.loads(text)
Expand All @@ -123,3 +122,87 @@ def test_dynamic_class(self):
t = team({'name': 'neweggtech', 'age': 5, 'members': []})
self.assertEqual('neweggtech', t.name)
self.assertEqual(5, t.age)


class Dolphin2TestCase(unittest.TestCase):
def test_loads_basic(self):
tests = [(r'"ben"', "ben"),
('1', 1),
('3.1415', 3.1415),
('true', True),
('false', False),
('[]', [])]
for text, expected in tests:
actual = objson.loads2(text)
self.assertEqual(expected, actual)

def test_loads_normal(self):
text = r'{"sort":true, "name":{"first":"benjamin", "last": "yan"}}'
obj = objson.loads2(text)
self.assertIsNotNone(obj)
self.assertTrue(obj.sort)
self.assertEqual("benjamin", obj.name.first)
self.assertEqual("yan", obj.name.last)

def test_loads_exceptions(self):
tests = ["{"]
for text in tests:
self.assertIsNone(objson.loads(text))

def test_loads_exceptions2(self):
text = r'{"class":true, "def":true, "case":true}'
obj = objson.loads2(text)
self.assertTrue(obj.mclass)
self.assertTrue(obj.mdef)
self.assertTrue(obj.case)

self.assertTrue(obj['class'])
self.assertTrue(obj['def'])

text = r'{"class":true, "mclass":false, "from-cookie": true, "0file":true}'
obj = objson.loads2(text)
self.assertFalse(obj.mclass)
self.assertTrue(obj['class'])
self.assertTrue(obj.from_cookie)
self.assertTrue(obj['from-cookie'])
self.assertTrue(obj.m0file)
self.assertTrue(obj['0file'])

def test_dumps(self):
text = r'{"sort":true, "name":{"first":"benjamin", "last": "yan"}}'
obj = objson.loads2(text)
actual = objson.dumps(obj)
self.assertDictEqual(json.loads(text), json.loads(actual))

def test_load_normal(self):
fp = StringIO(r'{"name":"benjamin", "age":21}')
obj = objson.load2(fp)
self.assertIsNotNone(obj)
self.assertEqual("benjamin", obj.name)
self.assertEqual(21, obj.age)

def test_dump_normal(self):
text = r'{"name":"benjamin", "age":21}'
obj = objson.loads2(text)
fp = StringIO()
objson.dump(obj, fp)
self.assertEqual(json.loads(text), json.loads(fp.getvalue()))

def test_dump_normal2(self):
text = r'[{"name":"benjamin", "age":21}]'
obj = objson.loads2(text)
expected = objson.dumps(obj)
self.assertEqual(json.loads(text), json.loads(expected))

expected = objson.dumps([dict(name='benjamin', age=21)])
self.assertEqual(json.loads(text), json.loads(expected))

def test_dump_change_value(self):
text = r'{"name":"benjamin", "age":21}'
obj = objson.loads2(text)
obj.age = 30
fp = StringIO()
objson.dump(obj, fp)
expected = json.loads(text)
expected['age'] = 30
self.assertEqual(expected, json.loads(fp.getvalue()))

0 comments on commit 59feba5

Please sign in to comment.