jsonutil.py 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. import base64
  2. import json
  3. from collections import Sequence, Mapping
  4. import terroroftinytown.six
  5. class NativeStringJSONDecoder(json.JSONDecoder):
  6. '''JSON decoder that channels unicode strings.'''
  7. def decode(self, s, **kwargs):
  8. result = json.JSONDecoder.decode(self, s, **kwargs)
  9. return self.channel_unicode(result)
  10. @classmethod
  11. def channel_unicode(cls, o):
  12. # http://stackoverflow.com/a/6415359/1524507
  13. if isinstance(o, terroroftinytown.six.string_types):
  14. if isinstance(o, terroroftinytown.six.text_type):
  15. o = o.encode('ascii')
  16. return base64.b16decode(o).decode('unicode_escape')
  17. elif isinstance(o, Sequence):
  18. return [cls.channel_unicode(item) for item in o]
  19. elif isinstance(o, Mapping):
  20. return dict((key, cls.channel_unicode(value))
  21. for key, value in o.items())
  22. else:
  23. return o
  24. class NativeStringJSONEncoder(json.JSONEncoder):
  25. '''JSON encoder that channels unicode strings.'''
  26. def encode(self, o):
  27. o = self.channel_unicode(o)
  28. return json.JSONEncoder.encode(self, o)
  29. @classmethod
  30. def channel_unicode(cls, o):
  31. # http://stackoverflow.com/a/6415359/1524507
  32. if isinstance(o, (terroroftinytown.six.binary_type,
  33. terroroftinytown.six.string_types)):
  34. if isinstance(o, terroroftinytown.six.binary_type):
  35. o = o.decode('latin1')
  36. o = base64.b16encode(o.encode('unicode_escape')).decode('ascii')
  37. return o
  38. elif isinstance(o, Sequence):
  39. return [cls.channel_unicode(item) for item in o]
  40. elif isinstance(o, Mapping):
  41. return dict((key, cls.channel_unicode(value))
  42. for key, value in o.items())
  43. else:
  44. return o