"""
raven.utils.json
~~~~~~~~~~~~~~~~~~~~~~~~

:copyright: (c) 2010-2012 by the Sentry Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""

from __future__ import absolute_import

import datetime
import uuid

try:
    import simplejson as json
except ImportError:
    import json

try:
    JSONDecodeError = json.JSONDecodeError
except AttributeError:
    JSONDecodeError = ValueError


class BetterJSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, uuid.UUID):
            return obj.hex
        elif isinstance(obj, datetime.datetime):
            return obj.strftime('%Y-%m-%dT%H:%M:%SZ')
        elif isinstance(obj, (set, frozenset)):
            return list(obj)
        elif isinstance(obj, bytes):
            return obj.decode('utf-8', errors='replace')
        return super(BetterJSONEncoder, self).default(obj)


def better_decoder(data):
    return data


def dumps(value, **kwargs):
    return json.dumps(value, cls=BetterJSONEncoder, **kwargs)


def loads(value, **kwargs):
    return json.loads(value, object_hook=better_decoder)

@@ -206,16 +206,30 @@
 import%0A%0A
+import codecs%0A
 import d
@@ -963,32 +963,45 @@
 lue, **kwargs):%0A
+    try:%0A    
     return json.
@@ -1050,91 +1050,1571 @@
 gs)%0A
-%0A%0Adef loads(value, **kwargs):%0A    return json.loads(value, object_hook=better_decoder
+    except:%0A        try:%0A            kwargs%5B'encoding'%5D='safe-utf-8'%0A            return json.dumps(value, cls=BetterJSONEncoder, **kwargs)%0A        except:%0A            return %22could not json encode: %25s%22 %25 str(value)%0A%0Adef loads(value, **kwargs):%0A    return json.loads(value, object_hook=better_decoder)%0A%0A%0A_utf8_encoder = codecs.getencoder('utf-8')%0Adef safe_encode(input, errors='backslashreplace'):%0A    return _utf8_encoder(input, errors)%0A%0A_utf8_decoder = codecs.getdecoder('utf-8')%0Adef safe_decode(input, errors='replace'):%0A    return _utf8_decoder(input, errors)%0A%0Aclass Codec(codecs.Codec):%0A%0A    def encode(self,input, errors='backslashreplace'):%0A        return safe_encode(input,errors)%0A%0A    def decode(self,input, errors='replace'):%0A        return safe_decode(input,errors)%0A%0Aclass IncrementalEncoder(codecs.IncrementalEncoder):%0A    def encode(self, input, final=False):%0A        return safe_encode(input, self.errors)%5B0%5D%0A%0Aclass IncrementalDecoder(codecs.IncrementalDecoder):%0A    def decode(self, input, final=False):%0A        return safe_decode(input, self.errors)%5B0%5D%0A%0Aclass StreamWriter(Codec,codecs.StreamWriter):%0A    pass%0A%0Aclass StreamReader(Codec,codecs.StreamReader):%0A    pass%0A%0Adef getregentry(name):%0A    if name != 'safe-utf-8':%0A        return None%0A    return codecs.CodecInfo(%0A        name='safe-utf-8',%0A        encode=safe_encode,%0A        decode=safe_decode,%0A        incrementalencoder=IncrementalEncoder,%0A        incrementaldecoder=IncrementalDecoder,%0A        streamreader=StreamReader,%0A        streamwriter=StreamWriter,%0A    )%0A%0Acodecs.register(getregentry
 )%0A

make json encoding more robust in the face of binary data