import datetime import decimal import functools import json as stdlib_json try: # we keep simplejson for having dump functionality still # orjson doesn't support it import simplejson as sjson except ImportError: sjson = stdlib_json try: import orjson import orjson as json except ImportError: json = stdlib_json from rhodecode.lib.datelib import is_aware from rhodecode.lib.str_utils import safe_str try: import rhodecode.translation except ImportError: rhodecode = None __all__ = ['json'] def _obj_dump(obj): """ Custom function for dumping objects to JSON, if obj has __json__ attribute or method defined it will be used for serialization :param obj: """ if isinstance(obj, set): return list(obj) # See "Date Time String Format" in the ECMA-262 specification. # some code borrowed from django 1.4 elif isinstance(obj, datetime.datetime): r = obj.isoformat() if isinstance(obj.microsecond, int): r = r[:23] + r[26:] if r.endswith('+00:00'): r = r[:-6] + 'Z' return r elif isinstance(obj, datetime.date): return obj.isoformat() elif isinstance(obj, decimal.Decimal): return str(obj) elif isinstance(obj, datetime.time): if is_aware(obj): raise TypeError("Time-zone aware times are not JSON serializable") r = obj.isoformat() if isinstance(obj.microsecond, int): r = r[:12] return r elif hasattr(obj, '__json__'): if callable(obj.__json__): return obj.__json__() else: return obj.__json__ elif isinstance(obj, complex): return [obj.real, obj.imag] elif rhodecode and isinstance(obj, rhodecode.translation._LazyString): return obj.eval() else: raise TypeError(repr(obj) + " is not JSON serializable") sjson.dumps = functools.partial(sjson.dumps, default=_obj_dump) sjson.dump = functools.partial(sjson.dump, default=_obj_dump) json.dumps = functools.partial(json.dumps, default=_obj_dump, option=orjson.OPT_NON_STR_KEYS) json.dump = functools.partial(sjson.dump, default=_obj_dump) def formatted_json(*args, **kwargs): # alias for formatted json opts = orjson.OPT_NON_STR_KEYS | orjson.OPT_INDENT_2 | orjson.OPT_SORT_KEYS return functools.partial(json.dumps, option=opts)(*args, **kwargs) def formatted_str_json(*args, **kwargs): opts = orjson.OPT_NON_STR_KEYS | orjson.OPT_INDENT_2 | orjson.OPT_SORT_KEYS closure = functools.partial(json.dumps, option=opts) return safe_str(closure(*args, **kwargs)) def str_json(*args, **kwargs): closure = functools.partial(json.dumps) return safe_str(closure(*args, **kwargs))