96 lines
2.4 KiB
Python
96 lines
2.4 KiB
Python
try:
|
|
from simplejson import JSONEncoder
|
|
except ImportError: # pragma: no cover
|
|
from json import JSONEncoder # noqa
|
|
|
|
from datetime import datetime, date
|
|
from decimal import Decimal
|
|
|
|
# depending on the version WebOb might have 2 types of dicts
|
|
try:
|
|
# WebOb <= 1.1.1
|
|
from webob.multidict import MultiDict, UnicodeMultiDict
|
|
webob_dicts = (MultiDict, UnicodeMultiDict) # pragma: no cover
|
|
except ImportError: # pragma no cover
|
|
# WebOb >= 1.2
|
|
from webob.multidict import MultiDict
|
|
webob_dicts = (MultiDict,)
|
|
|
|
from simplegeneric import generic
|
|
|
|
try:
|
|
from sqlalchemy.engine.base import ResultProxy, RowProxy
|
|
except ImportError: # pragma no cover
|
|
# dummy classes since we don't have SQLAlchemy installed
|
|
|
|
class ResultProxy:
|
|
pass
|
|
|
|
class RowProxy:
|
|
pass
|
|
|
|
#
|
|
# exceptions
|
|
#
|
|
|
|
|
|
class JsonEncodeError(Exception):
|
|
pass
|
|
|
|
|
|
#
|
|
# encoders
|
|
#
|
|
|
|
def is_saobject(obj):
|
|
return hasattr(obj, '_sa_class_manager')
|
|
|
|
|
|
class GenericJSON(JSONEncoder):
|
|
def default(self, obj):
|
|
if hasattr(obj, '__json__') and callable(obj.__json__):
|
|
return obj.__json__()
|
|
elif isinstance(obj, (date, datetime)):
|
|
return str(obj)
|
|
elif isinstance(obj, Decimal):
|
|
# XXX What to do about JSONEncoder crappy handling of Decimals?
|
|
# SimpleJSON has better Decimal encoding than the std lib
|
|
# but only in recent versions
|
|
return float(obj)
|
|
elif is_saobject(obj):
|
|
props = {}
|
|
for key in obj.__dict__:
|
|
if not key.startswith('_sa_'):
|
|
props[key] = getattr(obj, key)
|
|
return props
|
|
elif isinstance(obj, ResultProxy):
|
|
props = dict(rows=list(obj), count=obj.rowcount)
|
|
if props['count'] < 0:
|
|
props['count'] = len(props['rows'])
|
|
return props
|
|
elif isinstance(obj, RowProxy):
|
|
return dict(obj)
|
|
elif isinstance(obj, webob_dicts):
|
|
return obj.mixed()
|
|
else:
|
|
return JSONEncoder.default(self, obj)
|
|
|
|
|
|
_default = GenericJSON()
|
|
|
|
|
|
@generic
|
|
def jsonify(obj):
|
|
return _default.default(obj)
|
|
|
|
|
|
class GenericFunctionJSON(GenericJSON):
|
|
def default(self, obj):
|
|
return jsonify(obj)
|
|
|
|
_instance = GenericFunctionJSON()
|
|
|
|
|
|
def encode(obj):
|
|
return _instance.encode(obj)
|