pickle.py 4.7 KB

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