data.py 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. # -*- coding: utf-8 -*-
  2. from __future__ import absolute_import
  3. import json
  4. from celery.utils.debug import humanbytes
  5. from celery.utils.imports import qualname
  6. type_registry = {}
  7. def json_reduce(obj, attrs):
  8. return {'py/obj': {'type': qualname(obj), 'attrs': attrs}}
  9. def jsonable(cls):
  10. type_registry[qualname(cls)] = cls.__from_json__
  11. return cls
  12. @jsonable
  13. class Data(object):
  14. def __init__(self, label, data):
  15. self.label = label
  16. self.data = data
  17. def __str__(self):
  18. return '<Data: {0} ({1})>'.format(
  19. self.label, humanbytes(len(self.data)),
  20. )
  21. def __to_json__(self):
  22. return json_reduce(self, {'label': self.label, 'data': self.data})
  23. @classmethod
  24. def __from_json__(cls, label=None, data=None, **kwargs):
  25. return cls(label, data)
  26. def __reduce__(self):
  27. return Data, (self.label, self.data)
  28. __unicode__ = __repr__ = __str__
  29. BIG = Data('BIG', 'x' * 2 ** 20 * 8)
  30. SMALL = Data('SMALL', 'e' * 1024)
  31. class JSONEncoder(json.JSONEncoder):
  32. def default(self, obj):
  33. try:
  34. return super(JSONEncoder, self).default(obj)
  35. except TypeError:
  36. reducer = getattr(obj, '__to_json__', None)
  37. if reducer:
  38. return reducer()
  39. raise
  40. def decode_hook(d):
  41. try:
  42. d = d['py/obj']
  43. except KeyError:
  44. return d
  45. type_registry[d['type']](**d['attrs'])
  46. def install_json():
  47. json._default_encoder = JSONEncoder()
  48. json._default_decoder.object_hook = decode_hook
  49. install_json() # ugh, ugly but it's a test suite after all