test_subclassinit.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. import types
  2. import unittest
  3. class Test(unittest.TestCase):
  4. def test_init_subclass(self):
  5. class A:
  6. initialized = False
  7. def __init_subclass__(cls):
  8. super().__init_subclass__()
  9. cls.initialized = True
  10. class B(A):
  11. pass
  12. self.assertFalse(A.initialized)
  13. self.assertTrue(B.initialized)
  14. def test_init_subclass_dict(self):
  15. class A(dict):
  16. initialized = False
  17. def __init_subclass__(cls):
  18. super().__init_subclass__()
  19. cls.initialized = True
  20. class B(A):
  21. pass
  22. self.assertFalse(A.initialized)
  23. self.assertTrue(B.initialized)
  24. def test_init_subclass_kwargs(self):
  25. class A:
  26. def __init_subclass__(cls, **kwargs):
  27. cls.kwargs = kwargs
  28. class B(A, x=3):
  29. pass
  30. self.assertEqual(B.kwargs, dict(x=3))
  31. def test_init_subclass_error(self):
  32. class A:
  33. def __init_subclass__(cls):
  34. raise RuntimeError
  35. with self.assertRaises(RuntimeError):
  36. class B(A):
  37. pass
  38. def test_init_subclass_wrong(self):
  39. class A:
  40. def __init_subclass__(cls, whatever):
  41. pass
  42. with self.assertRaises(TypeError):
  43. class B(A):
  44. pass
  45. def test_init_subclass_skipped(self):
  46. class BaseWithInit:
  47. def __init_subclass__(cls, **kwargs):
  48. super().__init_subclass__(**kwargs)
  49. cls.initialized = cls
  50. class BaseWithoutInit(BaseWithInit):
  51. pass
  52. class A(BaseWithoutInit):
  53. pass
  54. self.assertIs(A.initialized, A)
  55. self.assertIs(BaseWithoutInit.initialized, BaseWithoutInit)
  56. def test_init_subclass_diamond(self):
  57. class Base:
  58. def __init_subclass__(cls, **kwargs):
  59. super().__init_subclass__(**kwargs)
  60. cls.calls = []
  61. class Left(Base):
  62. pass
  63. class Middle:
  64. def __init_subclass__(cls, middle, **kwargs):
  65. super().__init_subclass__(**kwargs)
  66. cls.calls += [middle]
  67. class Right(Base):
  68. def __init_subclass__(cls, right="right", **kwargs):
  69. super().__init_subclass__(**kwargs)
  70. cls.calls += [right]
  71. class A(Left, Middle, Right, middle="middle"):
  72. pass
  73. self.assertEqual(A.calls, ["right", "middle"])
  74. self.assertEqual(Left.calls, [])
  75. self.assertEqual(Right.calls, [])
  76. def test_set_name(self):
  77. class Descriptor:
  78. def __set_name__(self, owner, name):
  79. self.owner = owner
  80. self.name = name
  81. class A:
  82. d = Descriptor()
  83. self.assertEqual(A.d.name, "d")
  84. self.assertIs(A.d.owner, A)
  85. def test_set_name_metaclass(self):
  86. class Meta(type):
  87. def __new__(cls, name, bases, ns):
  88. ret = super().__new__(cls, name, bases, ns)
  89. self.assertEqual(ret.d.name, "d")
  90. self.assertIs(ret.d.owner, ret)
  91. return 0
  92. class Descriptor:
  93. def __set_name__(self, owner, name):
  94. self.owner = owner
  95. self.name = name
  96. class A(metaclass=Meta):
  97. d = Descriptor()
  98. self.assertEqual(A, 0)
  99. def test_set_name_error(self):
  100. class Descriptor:
  101. def __set_name__(self, owner, name):
  102. 1/0
  103. with self.assertRaises(RuntimeError) as cm:
  104. class NotGoingToWork:
  105. attr = Descriptor()
  106. exc = cm.exception
  107. self.assertRegex(str(exc), r'\bNotGoingToWork\b')
  108. self.assertRegex(str(exc), r'\battr\b')
  109. self.assertRegex(str(exc), r'\bDescriptor\b')
  110. self.assertIsInstance(exc.__cause__, ZeroDivisionError)
  111. def test_set_name_wrong(self):
  112. class Descriptor:
  113. def __set_name__(self):
  114. pass
  115. with self.assertRaises(RuntimeError) as cm:
  116. class NotGoingToWork:
  117. attr = Descriptor()
  118. exc = cm.exception
  119. self.assertRegex(str(exc), r'\bNotGoingToWork\b')
  120. self.assertRegex(str(exc), r'\battr\b')
  121. self.assertRegex(str(exc), r'\bDescriptor\b')
  122. self.assertIsInstance(exc.__cause__, TypeError)
  123. def test_set_name_lookup(self):
  124. resolved = []
  125. class NonDescriptor:
  126. def __getattr__(self, name):
  127. resolved.append(name)
  128. class A:
  129. d = NonDescriptor()
  130. self.assertNotIn('__set_name__', resolved,
  131. '__set_name__ is looked up in instance dict')
  132. def test_set_name_init_subclass(self):
  133. class Descriptor:
  134. def __set_name__(self, owner, name):
  135. self.owner = owner
  136. self.name = name
  137. class Meta(type):
  138. def __new__(cls, name, bases, ns):
  139. self = super().__new__(cls, name, bases, ns)
  140. self.meta_owner = self.owner
  141. self.meta_name = self.name
  142. return self
  143. class A:
  144. def __init_subclass__(cls):
  145. cls.owner = cls.d.owner
  146. cls.name = cls.d.name
  147. class B(A, metaclass=Meta):
  148. d = Descriptor()
  149. self.assertIs(B.owner, B)
  150. self.assertEqual(B.name, 'd')
  151. self.assertIs(B.meta_owner, B)
  152. self.assertEqual(B.name, 'd')
  153. def test_set_name_modifying_dict(self):
  154. notified = []
  155. class Descriptor:
  156. def __set_name__(self, owner, name):
  157. setattr(owner, name + 'x', None)
  158. notified.append(name)
  159. class A:
  160. a = Descriptor()
  161. b = Descriptor()
  162. c = Descriptor()
  163. d = Descriptor()
  164. e = Descriptor()
  165. self.assertCountEqual(notified, ['a', 'b', 'c', 'd', 'e'])
  166. def test_errors(self):
  167. class MyMeta(type):
  168. pass
  169. with self.assertRaises(TypeError):
  170. class MyClass(metaclass=MyMeta, otherarg=1):
  171. pass
  172. with self.assertRaises(TypeError):
  173. types.new_class("MyClass", (object,),
  174. dict(metaclass=MyMeta, otherarg=1))
  175. types.prepare_class("MyClass", (object,),
  176. dict(metaclass=MyMeta, otherarg=1))
  177. class MyMeta(type):
  178. def __init__(self, name, bases, namespace, otherarg):
  179. super().__init__(name, bases, namespace)
  180. with self.assertRaises(TypeError):
  181. class MyClass(metaclass=MyMeta, otherarg=1):
  182. pass
  183. class MyMeta(type):
  184. def __new__(cls, name, bases, namespace, otherarg):
  185. return super().__new__(cls, name, bases, namespace)
  186. def __init__(self, name, bases, namespace, otherarg):
  187. super().__init__(name, bases, namespace)
  188. self.otherarg = otherarg
  189. class MyClass(metaclass=MyMeta, otherarg=1):
  190. pass
  191. self.assertEqual(MyClass.otherarg, 1)
  192. def test_errors_changed_pep487(self):
  193. # These tests failed before Python 3.6, PEP 487
  194. class MyMeta(type):
  195. def __new__(cls, name, bases, namespace):
  196. return super().__new__(cls, name=name, bases=bases,
  197. dict=namespace)
  198. with self.assertRaises(TypeError):
  199. class MyClass(metaclass=MyMeta):
  200. pass
  201. class MyMeta(type):
  202. def __new__(cls, name, bases, namespace, otherarg):
  203. self = super().__new__(cls, name, bases, namespace)
  204. self.otherarg = otherarg
  205. return self
  206. class MyClass(metaclass=MyMeta, otherarg=1):
  207. pass
  208. self.assertEqual(MyClass.otherarg, 1)
  209. def test_type(self):
  210. t = type('NewClass', (object,), {})
  211. self.assertIsInstance(t, type)
  212. self.assertEqual(t.__name__, 'NewClass')
  213. with self.assertRaises(TypeError):
  214. type(name='NewClass', bases=(object,), dict={})
  215. if __name__ == "__main__":
  216. unittest.main()