1
0

pickle.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import json
  2. import builtins
  3. _BASIC_TYPES = [int, float, str, bool, type(None)]
  4. _MOD_T_SEP = "@"
  5. def _find_class(path: str):
  6. if _MOD_T_SEP not in path:
  7. return builtins.__dict__[path]
  8. modpath, name = path.split(_MOD_T_SEP)
  9. return __import__(modpath).__dict__[name]
  10. class _Pickler:
  11. def __init__(self, obj) -> None:
  12. self.obj = obj
  13. self.raw_memo = {} # id -> int
  14. self.memo = [] # int -> object
  15. @staticmethod
  16. def _type_id(t: type):
  17. assert type(t) is type
  18. name = t.__name__
  19. mod = t.__module__
  20. if mod is not None:
  21. name = mod + _MOD_T_SEP + name
  22. return name
  23. def wrap(self, o):
  24. o_t = type(o)
  25. if o_t in _BASIC_TYPES:
  26. return o
  27. if o_t is type:
  28. return ["type", self._type_id(o)]
  29. index = self.raw_memo.get(id(o), None)
  30. if index is not None:
  31. return [index]
  32. ret = []
  33. index = len(self.memo)
  34. self.memo.append(ret)
  35. self.raw_memo[id(o)] = index
  36. if o_t is tuple:
  37. ret.append("tuple")
  38. ret.append([self.wrap(i) for i in o])
  39. return [index]
  40. if o_t is bytes:
  41. ret.append("bytes")
  42. ret.append([o[j] for j in range(len(o))])
  43. return [index]
  44. if o_t is list:
  45. ret.append("list")
  46. ret.append([self.wrap(i) for i in o])
  47. return [index]
  48. if o_t is dict:
  49. ret.append("dict")
  50. ret.append([[self.wrap(k), self.wrap(v)] for k,v in o.items()])
  51. return [index]
  52. _0 = self._type_id(o_t)
  53. if getattr(o_t, '__struct__', False):
  54. ret.append(_0)
  55. ret.append(o.tostruct().hex())
  56. return [index]
  57. if hasattr(o, "__getnewargs__"):
  58. _1 = o.__getnewargs__() # an iterable
  59. _1 = [self.wrap(i) for i in _1]
  60. else:
  61. _1 = None
  62. if o.__dict__ is None:
  63. _2 = None
  64. else:
  65. _2 = {k: self.wrap(v) for k,v in o.__dict__.items()}
  66. ret.append(_0) # type id
  67. ret.append(_1) # newargs
  68. ret.append(_2) # state
  69. return [index]
  70. def run_pipe(self):
  71. o = self.wrap(self.obj)
  72. return [o, self.memo]
  73. class _Unpickler:
  74. def __init__(self, obj, memo: list) -> None:
  75. self.obj = obj
  76. self.memo = memo
  77. self._unwrapped = [None] * len(memo)
  78. def tag(self, index, o):
  79. assert self._unwrapped[index] is None
  80. self._unwrapped[index] = o
  81. def unwrap(self, o, index=None):
  82. if type(o) in _BASIC_TYPES:
  83. return o
  84. assert type(o) is list
  85. if o[0] == "type":
  86. return _find_class(o[1])
  87. # reference
  88. if type(o[0]) is int:
  89. assert index is None # index should be None
  90. index = o[0]
  91. if self._unwrapped[index] is None:
  92. o = self.memo[index]
  93. assert type(o) is list
  94. assert type(o[0]) is str
  95. self.unwrap(o, index)
  96. assert self._unwrapped[index] is not None
  97. return self._unwrapped[index]
  98. # concrete reference type
  99. if o[0] == "tuple":
  100. ret = tuple([self.unwrap(i) for i in o[1]])
  101. self.tag(index, ret)
  102. return ret
  103. if o[0] == "bytes":
  104. ret = bytes(o[1])
  105. self.tag(index, ret)
  106. return ret
  107. if o[0] == "list":
  108. ret = []
  109. self.tag(index, ret)
  110. for i in o[1]:
  111. ret.append(self.unwrap(i))
  112. return ret
  113. if o[0] == "dict":
  114. ret = {}
  115. self.tag(index, ret)
  116. for k,v in o[1]:
  117. ret[self.unwrap(k)] = self.unwrap(v)
  118. return ret
  119. # generic object
  120. cls = _find_class(o[0])
  121. # if getattr(cls, '__struct__', False):
  122. if False:
  123. inst = cls.fromstruct(struct.fromhex(o[1]))
  124. self.tag(index, inst)
  125. return inst
  126. else:
  127. _, newargs, state = o
  128. # create uninitialized instance
  129. new_f = getattr(cls, "__new__")
  130. if newargs is not None:
  131. newargs = [self.unwrap(i) for i in newargs]
  132. inst = new_f(cls, *newargs)
  133. else:
  134. inst = new_f(cls)
  135. self.tag(index, inst)
  136. # restore state
  137. if state is not None:
  138. for k,v in state.items():
  139. setattr(inst, k, self.unwrap(v))
  140. return inst
  141. def run_pipe(self):
  142. return self.unwrap(self.obj)
  143. def _wrap(o):
  144. return _Pickler(o).run_pipe()
  145. def _unwrap(packed: list):
  146. return _Unpickler(*packed).run_pipe()
  147. def dumps(o) -> bytes:
  148. o = _wrap(o)
  149. return json.dumps(o).encode()
  150. def loads(b) -> object:
  151. assert type(b) is bytes
  152. o = json.loads(b.decode())
  153. return _unwrap(o)