1
0

pickle.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import json
  2. import builtins
  3. _BASIC_TYPES = [int, float, str, bool, type(None)]
  4. def _find_class(path: str):
  5. if "." not in path:
  6. g = globals()
  7. if path in g:
  8. return g[path]
  9. return builtins.__dict__[path]
  10. modname, name = path.split(".")
  11. return __import__(modname).__dict__[name]
  12. def _find__new__(cls):
  13. while cls is not None:
  14. d = cls.__dict__
  15. if "__new__" in d:
  16. return d["__new__"]
  17. cls = cls.__base__
  18. assert False
  19. class _Pickler:
  20. def __init__(self) -> None:
  21. self.raw_memo = {} # id -> int
  22. self.memo = [] # int -> object
  23. def wrap(self, o):
  24. if type(o) in _BASIC_TYPES:
  25. return o
  26. index = self.raw_memo.get(id(o), None)
  27. if index is not None:
  28. return ["$", index]
  29. ret = []
  30. index = len(self.memo)
  31. self.memo.append(ret)
  32. self.raw_memo[id(o)] = index
  33. if type(o) is list:
  34. ret.append("list")
  35. ret.append([self.wrap(i) for i in o])
  36. return ["$", index]
  37. if type(o) is tuple:
  38. ret.append("tuple")
  39. ret.append([self.wrap(i) for i in o])
  40. return ["$", index]
  41. if type(o) is dict:
  42. ret.append("dict")
  43. ret.append([[self.wrap(k), self.wrap(v)] for k,v in o.items()])
  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. _0 = o.__class__.__name__
  50. if hasattr(o, "__getnewargs__"):
  51. _1 = o.__getnewargs__() # an iterable
  52. _1 = [self.wrap(i) for i in _1]
  53. else:
  54. _1 = None
  55. if hasattr(o, "__getstate__"):
  56. _2 = o.__getstate__()
  57. else:
  58. if o.__dict__ is None:
  59. _2 = None
  60. else:
  61. _2 = {}
  62. for k,v in o.__dict__.items():
  63. _2[k] = self.wrap(v)
  64. ret.append(_0)
  65. ret.append(_1)
  66. ret.append(_2)
  67. return ["$", index]
  68. class _Unpickler:
  69. def __init__(self, memo: list) -> None:
  70. self.memo = memo
  71. self.unwrapped = [None] * len(memo)
  72. def unwrap_ref(self, i: int):
  73. if self.unwrapped[i] is None:
  74. o = self.memo[i]
  75. assert type(o) is list
  76. assert o[0] != '$'
  77. self.unwrapped[i] = self.unwrap(o)
  78. return self.unwrapped[i]
  79. def unwrap(self, o):
  80. if type(o) in _BASIC_TYPES:
  81. return o
  82. assert type(o) is list
  83. if o[0] == '$':
  84. index = o[1]
  85. return self.unwrap_ref(index)
  86. if o[0] == "list":
  87. return [self.unwrap(i) for i in o[1]]
  88. if o[0] == "tuple":
  89. return tuple([self.unwrap(i) for i in o[1]])
  90. if o[0] == "dict":
  91. return {self.unwrap(k): self.unwrap(v) for k,v in o[1]}
  92. if o[0] == "bytes":
  93. return bytes(o[1])
  94. # generic object
  95. cls, newargs, state = o
  96. cls = _find_class(o[0])
  97. # create uninitialized instance
  98. new_f = _find__new__(cls)
  99. if newargs is not None:
  100. newargs = [self.unwrap(i) for i in newargs]
  101. inst = new_f(cls, *newargs)
  102. else:
  103. inst = new_f(cls)
  104. # restore state
  105. if hasattr(inst, "__setstate__"):
  106. inst.__setstate__(state)
  107. else:
  108. if state is not None:
  109. for k,v in state.items():
  110. setattr(inst, k, self.unwrap(v))
  111. return inst
  112. def _wrap(o):
  113. p = _Pickler()
  114. o = p.wrap(o)
  115. return [o, p.memo]
  116. def _unwrap(packed: list):
  117. o, memo = packed
  118. return _Unpickler(memo).unwrap(o)
  119. def dumps(o) -> bytes:
  120. o = _wrap(o)
  121. return json.dumps(o).encode()
  122. def loads(b) -> object:
  123. assert type(b) is bytes
  124. o = json.loads(b.decode())
  125. return _unwrap(o)