/usr/lib/python2.7/dist-packages/tg/jsonify.py is in python-turbogears2 2.3.7-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | """JSON encoding functions."""
import datetime
import decimal
import types
from json import JSONEncoder as _JSONEncoder
from tg.support.converters import asbool
from webob.multidict import MultiDict
from tg._compat import string_type
from tg.configuration.utils import GlobalConfigurable
from tg.util.sqlalchemy import dictify as dictify_sqla, is_saobject, is_query_result, is_query_row
from tg.util.ming import dictify as dictify_ming, is_mingobject, is_objectid
import logging
log = logging.getLogger(__name__)
class JsonEncodeError(Exception):
"""JSON Encode error"""
class JSONEncoder(_JSONEncoder, GlobalConfigurable):
"""TurboGears custom JSONEncoder.
Provides support for encoding objects commonly used in TurboGears apps, like:
- SQLAlchemy queries
- Ming queries
- Dates
- Decimals
- Generators
Support for additional types is provided through the ``__json__`` method
that will be called on the object by the JSONEncoder when provided and through
the ability to register custom encoder for specific types using
:meth:`.JSONEncoder.register_custom_encoder`.
"""
CONFIG_NAMESPACE = 'json.'
CONFIG_OPTIONS = {'isodates': asbool}
def __init__(self, **kwargs):
self._registered_types_map = {}
self._registered_types_list = tuple()
kwargs = self.configure(**kwargs)
super(JSONEncoder, self).__init__(**kwargs)
def configure(self, isodates=False, custom_encoders=None, **kwargs):
"""JSON encoder can be configured through :class:`.AppConfig` (``app_cfg.base_config``)
using the following options:
- ``json.isodates`` -> encode dates using ISO8601 format
- ``json.custom_encoders`` -> List of tuples ``(type, encode_func)`` to register
custom encoders for specific types.
"""
self._isodates = isodates
if custom_encoders is not None:
for type_, encoder in custom_encoders.items():
self.register_custom_encoder(type_, encoder)
return kwargs
def register_custom_encoder(self, objtype, encoder):
"""Register a custom encoder for the given type.
Instead of using standard behavior for encoding the given type to JSON, the
``encoder`` will used instead. ``encoder`` must be a callable that takes
the object as argument and returns an object that can be encoded in JSON (usually a dict).
"""
if objtype in self._registered_types_map:
log.warning('%s type already registered for a custom encoder, replacing it', objtype)
self._registered_types_map[objtype] = encoder
# Append to head, so we find first the last registered types
self._registered_types_list = (objtype, ) + self._registered_types_list
def default(self, obj):
if isinstance(obj, self._registered_types_list):
# Minor optimization, enter loop only when we are instance of a supported type.
for type_, encoder in self._registered_types_map.items():
if isinstance(obj, type_):
return encoder(obj)
elif hasattr(obj, '__json__') and callable(obj.__json__):
return obj.__json__()
elif isinstance(obj, (datetime.date, datetime.datetime)):
if self._isodates:
if isinstance(obj, datetime.datetime):
obj = obj.replace(microsecond=0)
return obj.isoformat()
else:
return str(obj)
elif isinstance(obj, decimal.Decimal):
return float(obj)
elif is_saobject(obj):
return dictify_sqla(obj)
elif is_mingobject(obj):
return dictify_ming(obj)
elif is_query_result(obj):
return dict(rows=list(obj), count=obj.rowcount)
elif is_query_row(obj):
return dict(rows=dict(obj), count=1)
elif is_objectid(obj):
return str(obj)
elif isinstance(obj, MultiDict):
return obj.mixed()
elif isinstance(obj, types.GeneratorType):
return list(obj)
else:
return _JSONEncoder.default(self, obj)
_default_encoder = JSONEncoder.create_global()
def encode(obj, encoder=None, iterencode=False):
"""Return a JSON string representation of a Python object."""
if encoder is None:
encoder = _default_encoder
encode_func = encoder.encode
if iterencode:
encode_func = encoder.iterencode
if isinstance(obj, string_type):
return encode_func(obj)
try:
value = obj['test']
except TypeError:
if not hasattr(obj, '__json__') and not is_saobject(obj) and not is_mingobject(obj):
raise JsonEncodeError('Your Encoded object must be dict-like.')
except:
pass
return encode_func(obj)
def encode_iter(obj, encoder=None):
"""Encode object, yielding each string representation as available."""
return encode(obj, encoder=encoder, iterencode=True)
|