pickle.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import json
  2. import builtins
  3. def _find_class(path: str):
  4. if "." not in path:
  5. g = globals()
  6. if path in g:
  7. return g[path]
  8. return builtins.__dict__[path]
  9. modname, name = path.split(".")
  10. return __import__(modname).__dict__[name]
  11. def _find__new__(cls):
  12. while cls is not None:
  13. d = cls.__dict__
  14. if "__new__" in d:
  15. return d["__new__"]
  16. cls = cls.__base__
  17. raise PickleError(f"cannot find __new__ for {cls.__name__}")
  18. def _wrap(o):
  19. if type(o) in (int, float, str, bool, type(None)):
  20. return o
  21. if type(o) is list:
  22. return ["list", [_wrap(i) for i in o]]
  23. if type(o) is tuple:
  24. return ["tuple", [_wrap(i) for i in o]]
  25. if type(o) is dict:
  26. return ["dict", [[_wrap(k), _wrap(v)] for k,v in o.items()]]
  27. if type(o) is bytes:
  28. return ["bytes", [o[j] for j in range(len(o))]]
  29. _0 = o.__class__.__name__
  30. if hasattr(o, "__getnewargs__"):
  31. _1 = o.__getnewargs__() # an iterable
  32. _1 = [_wrap(i) for i in _1]
  33. else:
  34. _1 = None
  35. if hasattr(o, "__getstate__"):
  36. _2 = o.__getstate__()
  37. else:
  38. if o.__dict__ is None:
  39. _2 = None
  40. else:
  41. _2 = {}
  42. for k,v in o.__dict__.items():
  43. _2[k] = _wrap(v)
  44. return [_0, _1, _2]
  45. def _unwrap(o):
  46. if type(o) in (int, float, str, bool, type(None)):
  47. return o
  48. if isinstance(o, list):
  49. if o[0] == "list":
  50. return [_unwrap(i) for i in o[1]]
  51. if o[0] == "tuple":
  52. return tuple([_unwrap(i) for i in o[1]])
  53. if o[0] == "dict":
  54. return {_unwrap(k): _unwrap(v) for k,v in o[1]}
  55. if o[0] == "bytes":
  56. return bytes(o[1])
  57. # generic object
  58. cls, newargs, state = o
  59. cls = _find_class(o[0])
  60. # create uninitialized instance
  61. new_f = _find__new__(cls)
  62. if newargs is not None:
  63. newargs = [_unwrap(i) for i in newargs]
  64. inst = new_f(cls, *newargs)
  65. else:
  66. inst = new_f(cls)
  67. # restore state
  68. if hasattr(inst, "__setstate__"):
  69. inst.__setstate__(state)
  70. else:
  71. if state is not None:
  72. for k,v in state.items():
  73. setattr(inst, k, _unwrap(v))
  74. return inst
  75. raise PickleError(f"cannot unpickle {type(o).__name__} object")
  76. def dumps(o) -> bytes:
  77. return json.dumps(_wrap(o)).encode()
  78. def loads(b) -> object:
  79. assert type(b) is bytes
  80. o = json.loads(b.decode())
  81. return _unwrap(o)