test_classdef.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. #!/usr/bin/env python
  2. #
  3. # Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
  4. # Copyright (c) 2008-2016 California Institute of Technology.
  5. # Copyright (c) 2016-2024 The Uncertainty Quantification Foundation.
  6. # License: 3-clause BSD. The full license text is available at:
  7. # - https://github.com/uqfoundation/dill/blob/master/LICENSE
  8. import dill
  9. from enum import EnumMeta
  10. import sys
  11. dill.settings['recurse'] = True
  12. # test classdefs
  13. class _class:
  14. def _method(self):
  15. pass
  16. def ok(self):
  17. return True
  18. class _class2:
  19. def __call__(self):
  20. pass
  21. def ok(self):
  22. return True
  23. class _newclass(object):
  24. def _method(self):
  25. pass
  26. def ok(self):
  27. return True
  28. class _newclass2(object):
  29. def __call__(self):
  30. pass
  31. def ok(self):
  32. return True
  33. class _meta(type):
  34. pass
  35. def __call__(self):
  36. pass
  37. def ok(self):
  38. return True
  39. _mclass = _meta("_mclass", (object,), {"__call__": __call__, "ok": ok})
  40. del __call__
  41. del ok
  42. o = _class()
  43. oc = _class2()
  44. n = _newclass()
  45. nc = _newclass2()
  46. m = _mclass()
  47. if sys.hexversion < 0x03090000:
  48. import typing
  49. class customIntList(typing.List[int]):
  50. pass
  51. else:
  52. class customIntList(list[int]):
  53. pass
  54. # test pickles for class instances
  55. def test_class_instances():
  56. assert dill.pickles(o)
  57. assert dill.pickles(oc)
  58. assert dill.pickles(n)
  59. assert dill.pickles(nc)
  60. assert dill.pickles(m)
  61. def test_class_objects():
  62. clslist = [_class,_class2,_newclass,_newclass2,_mclass]
  63. objlist = [o,oc,n,nc,m]
  64. _clslist = [dill.dumps(obj) for obj in clslist]
  65. _objlist = [dill.dumps(obj) for obj in objlist]
  66. for obj in clslist:
  67. globals().pop(obj.__name__)
  68. del clslist
  69. for obj in ['o','oc','n','nc']:
  70. globals().pop(obj)
  71. del objlist
  72. del obj
  73. for obj,cls in zip(_objlist,_clslist):
  74. _cls = dill.loads(cls)
  75. _obj = dill.loads(obj)
  76. assert _obj.ok()
  77. assert _cls.ok(_cls())
  78. if _cls.__name__ == "_mclass":
  79. assert type(_cls).__name__ == "_meta"
  80. # test NoneType
  81. def test_specialtypes():
  82. assert dill.pickles(type(None))
  83. assert dill.pickles(type(NotImplemented))
  84. assert dill.pickles(type(Ellipsis))
  85. assert dill.pickles(type(EnumMeta))
  86. from collections import namedtuple
  87. Z = namedtuple("Z", ['a','b'])
  88. Zi = Z(0,1)
  89. X = namedtuple("Y", ['a','b'])
  90. X.__name__ = "X"
  91. X.__qualname__ = "X" #XXX: name must 'match' or fails to pickle
  92. Xi = X(0,1)
  93. Bad = namedtuple("FakeName", ['a','b'])
  94. Badi = Bad(0,1)
  95. Defaults = namedtuple('Defaults', ['x', 'y'], defaults=[1])
  96. Defaultsi = Defaults(2)
  97. # test namedtuple
  98. def test_namedtuple():
  99. assert Z is dill.loads(dill.dumps(Z))
  100. assert Zi == dill.loads(dill.dumps(Zi))
  101. assert X is dill.loads(dill.dumps(X))
  102. assert Xi == dill.loads(dill.dumps(Xi))
  103. assert Defaults is dill.loads(dill.dumps(Defaults))
  104. assert Defaultsi == dill.loads(dill.dumps(Defaultsi))
  105. assert Bad is not dill.loads(dill.dumps(Bad))
  106. assert Bad._fields == dill.loads(dill.dumps(Bad))._fields
  107. assert tuple(Badi) == tuple(dill.loads(dill.dumps(Badi)))
  108. class A:
  109. class B(namedtuple("C", ["one", "two"])):
  110. '''docstring'''
  111. B.__module__ = 'testing'
  112. a = A()
  113. assert dill.copy(a)
  114. assert dill.copy(A.B).__name__ == 'B'
  115. assert dill.copy(A.B).__qualname__.endswith('.<locals>.A.B')
  116. assert dill.copy(A.B).__doc__ == 'docstring'
  117. assert dill.copy(A.B).__module__ == 'testing'
  118. from typing import NamedTuple
  119. def A():
  120. class B(NamedTuple):
  121. x: int
  122. return B
  123. assert type(dill.copy(A()(8))).__qualname__ == type(A()(8)).__qualname__
  124. def test_dtype():
  125. try:
  126. import numpy as np
  127. dti = np.dtype('int')
  128. assert np.dtype == dill.copy(np.dtype)
  129. assert dti == dill.copy(dti)
  130. except ImportError: pass
  131. def test_array_nested():
  132. try:
  133. import numpy as np
  134. x = np.array([1])
  135. y = (x,)
  136. assert y == dill.copy(y)
  137. except ImportError: pass
  138. def test_array_subclass():
  139. try:
  140. import numpy as np
  141. class TestArray(np.ndarray):
  142. def __new__(cls, input_array, color):
  143. obj = np.asarray(input_array).view(cls)
  144. obj.color = color
  145. return obj
  146. def __array_finalize__(self, obj):
  147. if obj is None:
  148. return
  149. if isinstance(obj, type(self)):
  150. self.color = obj.color
  151. def __getnewargs__(self):
  152. return np.asarray(self), self.color
  153. a1 = TestArray(np.zeros(100), color='green')
  154. if not dill._dill.IS_PYPY:
  155. assert dill.pickles(a1)
  156. assert a1.__dict__ == dill.copy(a1).__dict__
  157. a2 = a1[0:9]
  158. if not dill._dill.IS_PYPY:
  159. assert dill.pickles(a2)
  160. assert a2.__dict__ == dill.copy(a2).__dict__
  161. class TestArray2(np.ndarray):
  162. color = 'blue'
  163. a3 = TestArray2([1,2,3,4,5])
  164. a3.color = 'green'
  165. if not dill._dill.IS_PYPY:
  166. assert dill.pickles(a3)
  167. assert a3.__dict__ == dill.copy(a3).__dict__
  168. except ImportError: pass
  169. def test_method_decorator():
  170. class A(object):
  171. @classmethod
  172. def test(cls):
  173. pass
  174. a = A()
  175. res = dill.dumps(a)
  176. new_obj = dill.loads(res)
  177. new_obj.__class__.test()
  178. # test slots
  179. class Y(object):
  180. __slots__ = ('y', '__weakref__')
  181. def __init__(self, y):
  182. self.y = y
  183. value = 123
  184. y = Y(value)
  185. class Y2(object):
  186. __slots__ = 'y'
  187. def __init__(self, y):
  188. self.y = y
  189. def test_slots():
  190. assert dill.pickles(Y)
  191. assert dill.pickles(y)
  192. assert dill.pickles(Y.y)
  193. assert dill.copy(y).y == value
  194. assert dill.copy(Y2(value)).y == value
  195. def test_origbases():
  196. assert dill.copy(customIntList).__orig_bases__ == customIntList.__orig_bases__
  197. def test_attr():
  198. import attr
  199. @attr.s
  200. class A:
  201. a = attr.ib()
  202. v = A(1)
  203. assert dill.copy(v) == v
  204. def test_metaclass():
  205. class metaclass_with_new(type):
  206. def __new__(mcls, name, bases, ns, **kwds):
  207. cls = super().__new__(mcls, name, bases, ns, **kwds)
  208. assert mcls is not None
  209. assert cls.method(mcls)
  210. return cls
  211. def method(cls, mcls):
  212. return isinstance(cls, mcls)
  213. l = locals()
  214. exec("""class subclass_with_new(metaclass=metaclass_with_new):
  215. def __new__(cls):
  216. self = super().__new__(cls)
  217. return self""", None, l)
  218. subclass_with_new = l['subclass_with_new']
  219. assert dill.copy(subclass_with_new())
  220. def test_enummeta():
  221. from http import HTTPStatus
  222. import enum
  223. assert dill.copy(HTTPStatus.OK) is HTTPStatus.OK
  224. assert dill.copy(enum.EnumMeta) is enum.EnumMeta
  225. def test_inherit(): #NOTE: see issue #612
  226. class Foo:
  227. w = 0
  228. x = 1
  229. y = 1.1
  230. a = ()
  231. b = (1,)
  232. n = None
  233. class Bar(Foo):
  234. w = 2
  235. x = 1
  236. y = 1.1
  237. z = 0.2
  238. a = ()
  239. b = (1,)
  240. c = (2,)
  241. n = None
  242. Baz = dill.copy(Bar)
  243. import platform
  244. is_pypy = platform.python_implementation() == 'PyPy'
  245. assert Bar.__dict__ == Baz.__dict__
  246. # ints
  247. assert 'w' in Bar.__dict__ and 'w' in Baz.__dict__
  248. assert Bar.__dict__['w'] is Baz.__dict__['w']
  249. assert 'x' in Bar.__dict__ and 'x' in Baz.__dict__
  250. assert Bar.__dict__['x'] is Baz.__dict__['x']
  251. # floats
  252. assert 'y' in Bar.__dict__ and 'y' in Baz.__dict__
  253. same = Bar.__dict__['y'] is Baz.__dict__['y']
  254. assert same if is_pypy else not same
  255. assert 'z' in Bar.__dict__ and 'z' in Baz.__dict__
  256. same = Bar.__dict__['z'] is Baz.__dict__['z']
  257. assert same if is_pypy else not same
  258. # tuples
  259. assert 'a' in Bar.__dict__ and 'a' in Baz.__dict__
  260. assert Bar.__dict__['a'] is Baz.__dict__['a']
  261. assert 'b' in Bar.__dict__ and 'b' in Baz.__dict__
  262. assert Bar.__dict__['b'] is not Baz.__dict__['b']
  263. assert 'c' in Bar.__dict__ and 'c' in Baz.__dict__
  264. assert Bar.__dict__['c'] is not Baz.__dict__['c']
  265. # None
  266. assert 'n' in Bar.__dict__ and 'n' in Baz.__dict__
  267. assert Bar.__dict__['n'] is Baz.__dict__['n']
  268. if __name__ == '__main__':
  269. test_class_instances()
  270. test_class_objects()
  271. test_specialtypes()
  272. test_namedtuple()
  273. test_dtype()
  274. test_array_nested()
  275. test_array_subclass()
  276. test_method_decorator()
  277. test_slots()
  278. test_origbases()
  279. test_metaclass()
  280. test_enummeta()
  281. test_inherit()