test_call_policies.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import pytest
  2. from pybind11_tests import call_policies as m
  3. from pybind11_tests import ConstructorStats, UserType
  4. def test_keep_alive_argument(capture):
  5. n_inst = ConstructorStats.detail_reg_inst()
  6. with capture:
  7. p = m.Parent()
  8. assert capture == "Allocating parent."
  9. with capture:
  10. p.addChild(m.Child())
  11. assert ConstructorStats.detail_reg_inst() == n_inst + 1
  12. assert capture == """
  13. Allocating child.
  14. Releasing child.
  15. """
  16. with capture:
  17. del p
  18. assert ConstructorStats.detail_reg_inst() == n_inst
  19. assert capture == "Releasing parent."
  20. with capture:
  21. p = m.Parent()
  22. assert capture == "Allocating parent."
  23. with capture:
  24. p.addChildKeepAlive(m.Child())
  25. assert ConstructorStats.detail_reg_inst() == n_inst + 2
  26. assert capture == "Allocating child."
  27. with capture:
  28. del p
  29. assert ConstructorStats.detail_reg_inst() == n_inst
  30. assert capture == """
  31. Releasing parent.
  32. Releasing child.
  33. """
  34. def test_keep_alive_return_value(capture):
  35. n_inst = ConstructorStats.detail_reg_inst()
  36. with capture:
  37. p = m.Parent()
  38. assert capture == "Allocating parent."
  39. with capture:
  40. p.returnChild()
  41. assert ConstructorStats.detail_reg_inst() == n_inst + 1
  42. assert capture == """
  43. Allocating child.
  44. Releasing child.
  45. """
  46. with capture:
  47. del p
  48. assert ConstructorStats.detail_reg_inst() == n_inst
  49. assert capture == "Releasing parent."
  50. with capture:
  51. p = m.Parent()
  52. assert capture == "Allocating parent."
  53. with capture:
  54. p.returnChildKeepAlive()
  55. assert ConstructorStats.detail_reg_inst() == n_inst + 2
  56. assert capture == "Allocating child."
  57. with capture:
  58. del p
  59. assert ConstructorStats.detail_reg_inst() == n_inst
  60. assert capture == """
  61. Releasing parent.
  62. Releasing child.
  63. """
  64. def test_keep_alive_single():
  65. """Issue #1251 - patients are stored multiple times when given to the same nurse"""
  66. nurse, p1, p2 = UserType(), UserType(), UserType()
  67. b = m.refcount(nurse)
  68. assert [m.refcount(nurse), m.refcount(p1), m.refcount(p2)] == [b, b, b]
  69. m.add_patient(nurse, p1)
  70. assert m.get_patients(nurse) == [p1, ]
  71. assert [m.refcount(nurse), m.refcount(p1), m.refcount(p2)] == [b, b + 1, b]
  72. m.add_patient(nurse, p1)
  73. assert m.get_patients(nurse) == [p1, ]
  74. assert [m.refcount(nurse), m.refcount(p1), m.refcount(p2)] == [b, b + 1, b]
  75. m.add_patient(nurse, p1)
  76. assert m.get_patients(nurse) == [p1, ]
  77. assert [m.refcount(nurse), m.refcount(p1), m.refcount(p2)] == [b, b + 1, b]
  78. m.add_patient(nurse, p2)
  79. assert m.get_patients(nurse) == [p1, p2]
  80. assert [m.refcount(nurse), m.refcount(p1), m.refcount(p2)] == [b, b + 1, b + 1]
  81. m.add_patient(nurse, p2)
  82. assert m.get_patients(nurse) == [p1, p2]
  83. assert [m.refcount(nurse), m.refcount(p1), m.refcount(p2)] == [b, b + 1, b + 1]
  84. m.add_patient(nurse, p2)
  85. m.add_patient(nurse, p1)
  86. assert m.get_patients(nurse) == [p1, p2]
  87. assert [m.refcount(nurse), m.refcount(p1), m.refcount(p2)] == [b, b + 1, b + 1]
  88. del nurse
  89. assert [m.refcount(p1), m.refcount(p2)] == [b, b]
  90. # https://bitbucket.org/pypy/pypy/issues/2447
  91. @pytest.unsupported_on_pypy
  92. def test_alive_gc(capture):
  93. n_inst = ConstructorStats.detail_reg_inst()
  94. p = m.ParentGC()
  95. p.addChildKeepAlive(m.Child())
  96. assert ConstructorStats.detail_reg_inst() == n_inst + 2
  97. lst = [p]
  98. lst.append(lst) # creates a circular reference
  99. with capture:
  100. del p, lst
  101. assert ConstructorStats.detail_reg_inst() == n_inst
  102. assert capture == """
  103. Releasing parent.
  104. Releasing child.
  105. """
  106. def test_alive_gc_derived(capture):
  107. class Derived(m.Parent):
  108. pass
  109. n_inst = ConstructorStats.detail_reg_inst()
  110. p = Derived()
  111. p.addChildKeepAlive(m.Child())
  112. assert ConstructorStats.detail_reg_inst() == n_inst + 2
  113. lst = [p]
  114. lst.append(lst) # creates a circular reference
  115. with capture:
  116. del p, lst
  117. assert ConstructorStats.detail_reg_inst() == n_inst
  118. assert capture == """
  119. Releasing parent.
  120. Releasing child.
  121. """
  122. def test_alive_gc_multi_derived(capture):
  123. class Derived(m.Parent, m.Child):
  124. def __init__(self):
  125. m.Parent.__init__(self)
  126. m.Child.__init__(self)
  127. n_inst = ConstructorStats.detail_reg_inst()
  128. p = Derived()
  129. p.addChildKeepAlive(m.Child())
  130. # +3 rather than +2 because Derived corresponds to two registered instances
  131. assert ConstructorStats.detail_reg_inst() == n_inst + 3
  132. lst = [p]
  133. lst.append(lst) # creates a circular reference
  134. with capture:
  135. del p, lst
  136. assert ConstructorStats.detail_reg_inst() == n_inst
  137. assert capture == """
  138. Releasing parent.
  139. Releasing child.
  140. Releasing child.
  141. """
  142. def test_return_none(capture):
  143. n_inst = ConstructorStats.detail_reg_inst()
  144. with capture:
  145. p = m.Parent()
  146. assert capture == "Allocating parent."
  147. with capture:
  148. p.returnNullChildKeepAliveChild()
  149. assert ConstructorStats.detail_reg_inst() == n_inst + 1
  150. assert capture == ""
  151. with capture:
  152. del p
  153. assert ConstructorStats.detail_reg_inst() == n_inst
  154. assert capture == "Releasing parent."
  155. with capture:
  156. p = m.Parent()
  157. assert capture == "Allocating parent."
  158. with capture:
  159. p.returnNullChildKeepAliveParent()
  160. assert ConstructorStats.detail_reg_inst() == n_inst + 1
  161. assert capture == ""
  162. with capture:
  163. del p
  164. assert ConstructorStats.detail_reg_inst() == n_inst
  165. assert capture == "Releasing parent."
  166. def test_keep_alive_constructor(capture):
  167. n_inst = ConstructorStats.detail_reg_inst()
  168. with capture:
  169. p = m.Parent(m.Child())
  170. assert ConstructorStats.detail_reg_inst() == n_inst + 2
  171. assert capture == """
  172. Allocating child.
  173. Allocating parent.
  174. """
  175. with capture:
  176. del p
  177. assert ConstructorStats.detail_reg_inst() == n_inst
  178. assert capture == """
  179. Releasing parent.
  180. Releasing child.
  181. """
  182. def test_call_guard():
  183. assert m.unguarded_call() == "unguarded"
  184. assert m.guarded_call() == "guarded"
  185. assert m.multiple_guards_correct_order() == "guarded & guarded"
  186. assert m.multiple_guards_wrong_order() == "unguarded & guarded"
  187. if hasattr(m, "with_gil"):
  188. assert m.with_gil() == "GIL held"
  189. assert m.without_gil() == "GIL released"