test_abc.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #!/usr/bin/env python
  2. #
  3. # Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
  4. # Copyright (c) 2023-2024 The Uncertainty Quantification Foundation.
  5. # License: 3-clause BSD. The full license text is available at:
  6. # - https://github.com/uqfoundation/dill/blob/master/LICENSE
  7. """
  8. test dill's ability to pickle abstract base class objects
  9. """
  10. import dill
  11. import abc
  12. from abc import ABC
  13. import warnings
  14. from types import FunctionType
  15. dill.settings['recurse'] = True
  16. class OneTwoThree(ABC):
  17. @abc.abstractmethod
  18. def foo(self):
  19. """A method"""
  20. pass
  21. @property
  22. @abc.abstractmethod
  23. def bar(self):
  24. """Property getter"""
  25. pass
  26. @bar.setter
  27. @abc.abstractmethod
  28. def bar(self, value):
  29. """Property setter"""
  30. pass
  31. @classmethod
  32. @abc.abstractmethod
  33. def cfoo(cls):
  34. """Class method"""
  35. pass
  36. @staticmethod
  37. @abc.abstractmethod
  38. def sfoo():
  39. """Static method"""
  40. pass
  41. class EasyAsAbc(OneTwoThree):
  42. def __init__(self):
  43. self._bar = None
  44. def foo(self):
  45. return "Instance Method FOO"
  46. @property
  47. def bar(self):
  48. return self._bar
  49. @bar.setter
  50. def bar(self, value):
  51. self._bar = value
  52. @classmethod
  53. def cfoo(cls):
  54. return "Class Method CFOO"
  55. @staticmethod
  56. def sfoo():
  57. return "Static Method SFOO"
  58. def test_abc_non_local():
  59. assert dill.copy(OneTwoThree) is not OneTwoThree
  60. assert dill.copy(EasyAsAbc) is not EasyAsAbc
  61. with warnings.catch_warnings():
  62. warnings.simplefilter("ignore", dill.PicklingWarning)
  63. assert dill.copy(OneTwoThree, byref=True) is OneTwoThree
  64. assert dill.copy(EasyAsAbc, byref=True) is EasyAsAbc
  65. instance = EasyAsAbc()
  66. # Set a property that StockPickle can't preserve
  67. instance.bar = lambda x: x**2
  68. depickled = dill.copy(instance)
  69. assert type(depickled) is type(instance) #NOTE: issue #612, test_abc_local
  70. #NOTE: dill.copy of local (or non-local) classes should (not) be the same?
  71. assert type(depickled.bar) is FunctionType
  72. assert depickled.bar(3) == 9
  73. assert depickled.sfoo() == "Static Method SFOO"
  74. assert depickled.cfoo() == "Class Method CFOO"
  75. assert depickled.foo() == "Instance Method FOO"
  76. def test_abc_local():
  77. """
  78. Test using locally scoped ABC class
  79. """
  80. class LocalABC(ABC):
  81. @abc.abstractmethod
  82. def foo(self):
  83. pass
  84. def baz(self):
  85. return repr(self)
  86. labc = dill.copy(LocalABC)
  87. assert labc is not LocalABC
  88. assert type(labc) is type(LocalABC)
  89. #NOTE: dill.copy of local (or non-local) classes should (not) be the same?
  90. # <class '__main__.LocalABC'>
  91. # <class '__main__.test_abc_local.<locals>.LocalABC'>
  92. class Real(labc):
  93. def foo(self):
  94. return "True!"
  95. def baz(self):
  96. return "My " + super(Real, self).baz()
  97. real = Real()
  98. assert real.foo() == "True!"
  99. try:
  100. labc()
  101. except TypeError as e:
  102. # Expected error
  103. pass
  104. else:
  105. print('Failed to raise type error')
  106. assert False
  107. labc2, pik = dill.copy((labc, Real()))
  108. assert 'Real' == type(pik).__name__
  109. assert '.Real' in type(pik).__qualname__
  110. assert type(pik) is not Real
  111. assert labc2 is not LocalABC
  112. assert labc2 is not labc
  113. assert isinstance(pik, labc2)
  114. assert not isinstance(pik, labc)
  115. assert not isinstance(pik, LocalABC)
  116. assert pik.baz() == "My " + repr(pik)
  117. def test_meta_local_no_cache():
  118. """
  119. Test calling metaclass and cache registration
  120. """
  121. LocalMetaABC = abc.ABCMeta('LocalMetaABC', (), {})
  122. class ClassyClass:
  123. pass
  124. class KlassyClass:
  125. pass
  126. LocalMetaABC.register(ClassyClass)
  127. assert not issubclass(KlassyClass, LocalMetaABC)
  128. assert issubclass(ClassyClass, LocalMetaABC)
  129. res = dill.dumps((LocalMetaABC, ClassyClass, KlassyClass))
  130. lmabc, cc, kc = dill.loads(res)
  131. assert type(lmabc) == type(LocalMetaABC)
  132. assert not issubclass(kc, lmabc)
  133. assert issubclass(cc, lmabc)
  134. if __name__ == '__main__':
  135. test_abc_non_local()
  136. test_abc_local()
  137. test_meta_local_no_cache()