904_pickle.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import pickle as pkl
  2. def assert_not_picklable(data):
  3. try:
  4. pkl.dumps(data)
  5. assert False, 'array2d must not be picklable'
  6. except TypeError as e:
  7. assert str(e) == "'array2d' object is not picklable"
  8. def test(data): # type: ignore
  9. print('-'*50)
  10. b = pkl.dumps(data)
  11. print(b)
  12. o = pkl.loads(b)
  13. print(o)
  14. assert data == o
  15. return o
  16. test(None) # PKL_NONE
  17. test(...) # PKL_ELLIPSIS
  18. test(1) # PKL_INT8
  19. test(277) # PKL_INT16
  20. test(-66666) # PKL_INT32
  21. test(0xffffffffffff) # PKL_INT64
  22. test(1.0) # PKL_FLOAT32
  23. test(1.12312434234) # PKL_FLOAT64
  24. test(True) # PKL_TRUE
  25. test(False) # PKL_FALSE
  26. test("hello") # PKL_STRING
  27. test(b"hello") # PKL_BYTES
  28. from vmath import vec2, vec3, vec2i, vec3i
  29. test(vec2(2/3, 1.0)) # PKL_VEC2
  30. test(vec3(2/3, 1.0, 3.0)) # PKL_VEC3
  31. test(vec2i(1, 2)) # PKL_VEC2I
  32. test(vec3i(1, 2, 3)) # PKL_VEC3I
  33. test(vec3i) # PKL_TYPE
  34. print('-'*50)
  35. from array2d import array2d
  36. a = array2d[int | bool | vec2i].fromlist([
  37. [1, 2, vec2i.LEFT],
  38. [4, True, 6]
  39. ])
  40. assert_not_picklable(a)
  41. assert_not_picklable([a])
  42. assert_not_picklable({'array': a})
  43. assert_not_picklable(array2d.fromlist([['hello', []]]))
  44. test([1, 2, 3]) # PKL_LIST
  45. test((1, 2, 3)) # PKL_TUPLE
  46. test({1: 2, 3: 4}) # PKL_DICT
  47. # test complex data
  48. test([1, '2', True])
  49. test([1, '2', 3.0, True])
  50. test([1, '2', True, {'key': 4}])
  51. test([1, '2', 3.0, True, {'k1': 4, 'k2': [b'xxxx']}])
  52. # test memo
  53. a = [1, 2, 3, 4, 5, 6, 745]
  54. b = [a] * 10
  55. c = test(b)
  56. assert b == c
  57. assert b is not c
  58. assert c[0] is c[1] and c[1] is c[2]
  59. s1 = 'hello'
  60. s2 = 'world'
  61. a = [s1, s2] * 10
  62. b = test(a)
  63. assert b == a
  64. assert b is not a
  65. assert b[0] is b[2]
  66. assert b[1] is b[3]
  67. from pkpy import TValue
  68. class Base(TValue[int]):
  69. def __eq__(self, other):
  70. return self.value == other.value
  71. def __ne__(self, other):
  72. return self.value != other.value
  73. class TVal(Base): pass # type: ignore
  74. test(TVal(1))
  75. old_bytes = pkl.dumps(TVal(1))
  76. print(old_bytes)
  77. # re-define the class so it will have a new type id
  78. class TVal(Base): pass
  79. # see if we can still load the old data
  80. decoded = pkl.loads(old_bytes)
  81. assert decoded == TVal(1)
  82. print(pkl.dumps(decoded))
  83. # test array2d with TValue
  84. a = array2d[TVal].fromlist([
  85. [TVal(1), TVal(2)],
  86. [TVal(3), 1]])
  87. assert_not_picklable(a)
  88. # test __reduce__
  89. class A:
  90. def __init__(self, seed):
  91. self.seed = seed
  92. self.x = seed
  93. self.y = seed + 1
  94. self.z = seed + 2
  95. def __eq__(self, other):
  96. return (self.x, self.y, self.z) == (other.x, other.y, other.z)
  97. def __ne__(self, other):
  98. return (self.x, self.y, self.z) != (other.x, other.y, other.z)
  99. def __repr__(self):
  100. return f"A({self.seed}, x={self.x}, y={self.y}, z={self.z})"
  101. def __reduce__(self):
  102. print('__reduce__() called')
  103. return A, (self.seed,)
  104. test([A(1)]*10)
  105. class Simple:
  106. def __init__(self, x):
  107. self.field1 = x
  108. self.field2 = [...]
  109. def __eq__(self, other): return self.field1 == other.field1
  110. def __ne__(self, other): return self.field1 != other.field1
  111. test(Simple(1))
  112. test([Simple(2)]*10)
  113. from dataclasses import dataclass
  114. @dataclass
  115. class Data:
  116. a: int
  117. b: str = '2'
  118. c: float = 3.0
  119. test(Data(1))
  120. exit()
  121. from pickle import dumps, loads, _wrap, _unwrap
  122. def test(x):
  123. y = dumps(x)
  124. # print(y.decode())
  125. ok = x == loads(y)
  126. if not ok:
  127. _0 = _wrap(x)
  128. _1 = _unwrap(_0)
  129. print('='*50)
  130. print(_0)
  131. print('-'*50)
  132. print(_1)
  133. print('='*50)
  134. assert False
  135. test(1)
  136. test(1.0)
  137. test("hello")
  138. test(True)
  139. test(False)
  140. test(None)
  141. test([1, 2, 3])
  142. test((1, 2, 3))
  143. test({1: 2, 3: 4})
  144. class Foo:
  145. def __init__(self, x, y):
  146. self.x = x
  147. self.y = y
  148. def __eq__(self, __value: object) -> bool:
  149. if not isinstance(__value, Foo):
  150. return False
  151. return self.x == __value.x and self.y == __value.y
  152. def __repr__(self) -> str:
  153. return f"Foo({self.x}, {self.y})"
  154. test(Foo(1, 2))
  155. test(Foo([1, True], 'c'))
  156. from vmath import vec2
  157. test(vec2(1, 2))
  158. a = {1, 2, 3, 4}
  159. test(a)
  160. a = bytes([1, 2, 3, 4])
  161. test(a)
  162. a = [1, 2]
  163. d = {'k': a, 'j': a}
  164. c = loads(dumps(d))
  165. assert c['k'] is c['j']
  166. assert c == d
  167. # test circular references
  168. from collections import deque
  169. a = deque([1, 2, 3])
  170. test(a)
  171. a = [int, float, Foo]
  172. test(a)
  173. # test function
  174. def f(x, y):
  175. return x + y
  176. test(f)
  177. # test @staticmethod
  178. class B:
  179. @staticmethod
  180. def f(x, y):
  181. return x * y
  182. @classmethod
  183. def g(cls):
  184. return cls
  185. class C(B):
  186. pass
  187. test(B.f)
  188. test(C.f)
  189. test(B.g)
  190. test(C.g)