You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

325 lines
11 KiB

8 years ago
  1. import pytest
  2. from pybind11_tests import ExampleMandA, ConstructorStats
  3. def test_methods_and_attributes():
  4. instance1 = ExampleMandA()
  5. instance2 = ExampleMandA(32)
  6. instance1.add1(instance2)
  7. instance1.add2(instance2)
  8. instance1.add3(instance2)
  9. instance1.add4(instance2)
  10. instance1.add5(instance2)
  11. instance1.add6(32)
  12. instance1.add7(32)
  13. instance1.add8(32)
  14. instance1.add9(32)
  15. instance1.add10(32)
  16. assert str(instance1) == "ExampleMandA[value=320]"
  17. assert str(instance2) == "ExampleMandA[value=32]"
  18. assert str(instance1.self1()) == "ExampleMandA[value=320]"
  19. assert str(instance1.self2()) == "ExampleMandA[value=320]"
  20. assert str(instance1.self3()) == "ExampleMandA[value=320]"
  21. assert str(instance1.self4()) == "ExampleMandA[value=320]"
  22. assert str(instance1.self5()) == "ExampleMandA[value=320]"
  23. assert instance1.internal1() == 320
  24. assert instance1.internal2() == 320
  25. assert instance1.internal3() == 320
  26. assert instance1.internal4() == 320
  27. assert instance1.internal5() == 320
  28. assert instance1.overloaded(1, 1.0) == "(int, float)"
  29. assert instance1.overloaded(2.0, 2) == "(float, int)"
  30. assert instance1.overloaded(3, 3) == "(int, int)"
  31. assert instance1.overloaded(4., 4.) == "(float, float)"
  32. assert instance1.overloaded_const(5, 5.0) == "(int, float) const"
  33. assert instance1.overloaded_const(6.0, 6) == "(float, int) const"
  34. assert instance1.overloaded_const(7, 7) == "(int, int) const"
  35. assert instance1.overloaded_const(8., 8.) == "(float, float) const"
  36. assert instance1.overloaded_float(1, 1) == "(float, float)"
  37. assert instance1.overloaded_float(1, 1.) == "(float, float)"
  38. assert instance1.overloaded_float(1., 1) == "(float, float)"
  39. assert instance1.overloaded_float(1., 1.) == "(float, float)"
  40. assert instance1.value == 320
  41. instance1.value = 100
  42. assert str(instance1) == "ExampleMandA[value=100]"
  43. cstats = ConstructorStats.get(ExampleMandA)
  44. assert cstats.alive() == 2
  45. del instance1, instance2
  46. assert cstats.alive() == 0
  47. assert cstats.values() == ["32"]
  48. assert cstats.default_constructions == 1
  49. assert cstats.copy_constructions == 3
  50. assert cstats.move_constructions >= 1
  51. assert cstats.copy_assignments == 0
  52. assert cstats.move_assignments == 0
  53. def test_properties():
  54. from pybind11_tests import TestProperties
  55. instance = TestProperties()
  56. assert instance.def_readonly == 1
  57. with pytest.raises(AttributeError):
  58. instance.def_readonly = 2
  59. instance.def_readwrite = 2
  60. assert instance.def_readwrite == 2
  61. assert instance.def_property_readonly == 2
  62. with pytest.raises(AttributeError):
  63. instance.def_property_readonly = 3
  64. instance.def_property = 3
  65. assert instance.def_property == 3
  66. def test_static_properties():
  67. from pybind11_tests import TestProperties as Type
  68. assert Type.def_readonly_static == 1
  69. with pytest.raises(AttributeError) as excinfo:
  70. Type.def_readonly_static = 2
  71. assert "can't set attribute" in str(excinfo)
  72. Type.def_readwrite_static = 2
  73. assert Type.def_readwrite_static == 2
  74. assert Type.def_property_readonly_static == 2
  75. with pytest.raises(AttributeError) as excinfo:
  76. Type.def_property_readonly_static = 3
  77. assert "can't set attribute" in str(excinfo)
  78. Type.def_property_static = 3
  79. assert Type.def_property_static == 3
  80. # Static property read and write via instance
  81. instance = Type()
  82. Type.def_readwrite_static = 0
  83. assert Type.def_readwrite_static == 0
  84. assert instance.def_readwrite_static == 0
  85. instance.def_readwrite_static = 2
  86. assert Type.def_readwrite_static == 2
  87. assert instance.def_readwrite_static == 2
  88. def test_static_cls():
  89. """Static property getter and setters expect the type object as the their only argument"""
  90. from pybind11_tests import TestProperties as Type
  91. instance = Type()
  92. assert Type.static_cls is Type
  93. assert instance.static_cls is Type
  94. def check_self(self):
  95. assert self is Type
  96. Type.static_cls = check_self
  97. instance.static_cls = check_self
  98. def test_metaclass_override():
  99. """Overriding pybind11's default metaclass changes the behavior of `static_property`"""
  100. from pybind11_tests import MetaclassOverride
  101. assert type(ExampleMandA).__name__ == "pybind11_type"
  102. assert type(MetaclassOverride).__name__ == "type"
  103. assert MetaclassOverride.readonly == 1
  104. assert type(MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property"
  105. # Regular `type` replaces the property instead of calling `__set__()`
  106. MetaclassOverride.readonly = 2
  107. assert MetaclassOverride.readonly == 2
  108. assert isinstance(MetaclassOverride.__dict__["readonly"], int)
  109. @pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
  110. def test_property_return_value_policies(access):
  111. from pybind11_tests import TestPropRVP
  112. if not access.startswith("static"):
  113. obj = TestPropRVP()
  114. else:
  115. obj = TestPropRVP
  116. ref = getattr(obj, access + "_ref")
  117. assert ref.value == 1
  118. ref.value = 2
  119. assert getattr(obj, access + "_ref").value == 2
  120. ref.value = 1 # restore original value for static properties
  121. copy = getattr(obj, access + "_copy")
  122. assert copy.value == 1
  123. copy.value = 2
  124. assert getattr(obj, access + "_copy").value == 1
  125. copy = getattr(obj, access + "_func")
  126. assert copy.value == 1
  127. copy.value = 2
  128. assert getattr(obj, access + "_func").value == 1
  129. def test_property_rvalue_policy():
  130. """When returning an rvalue, the return value policy is automatically changed from
  131. `reference(_internal)` to `move`. The following would not work otherwise.
  132. """
  133. from pybind11_tests import TestPropRVP
  134. instance = TestPropRVP()
  135. o = instance.rvalue
  136. assert o.value == 1
  137. def test_property_rvalue_policy_static():
  138. """When returning an rvalue, the return value policy is automatically changed from
  139. `reference(_internal)` to `move`. The following would not work otherwise.
  140. """
  141. from pybind11_tests import TestPropRVP
  142. o = TestPropRVP.static_rvalue
  143. assert o.value == 1
  144. # https://bitbucket.org/pypy/pypy/issues/2447
  145. @pytest.unsupported_on_pypy
  146. def test_dynamic_attributes():
  147. from pybind11_tests import DynamicClass, CppDerivedDynamicClass
  148. instance = DynamicClass()
  149. assert not hasattr(instance, "foo")
  150. assert "foo" not in dir(instance)
  151. # Dynamically add attribute
  152. instance.foo = 42
  153. assert hasattr(instance, "foo")
  154. assert instance.foo == 42
  155. assert "foo" in dir(instance)
  156. # __dict__ should be accessible and replaceable
  157. assert "foo" in instance.__dict__
  158. instance.__dict__ = {"bar": True}
  159. assert not hasattr(instance, "foo")
  160. assert hasattr(instance, "bar")
  161. with pytest.raises(TypeError) as excinfo:
  162. instance.__dict__ = []
  163. assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'"
  164. cstats = ConstructorStats.get(DynamicClass)
  165. assert cstats.alive() == 1
  166. del instance
  167. assert cstats.alive() == 0
  168. # Derived classes should work as well
  169. class PythonDerivedDynamicClass(DynamicClass):
  170. pass
  171. for cls in CppDerivedDynamicClass, PythonDerivedDynamicClass:
  172. derived = cls()
  173. derived.foobar = 100
  174. assert derived.foobar == 100
  175. assert cstats.alive() == 1
  176. del derived
  177. assert cstats.alive() == 0
  178. # https://bitbucket.org/pypy/pypy/issues/2447
  179. @pytest.unsupported_on_pypy
  180. def test_cyclic_gc():
  181. from pybind11_tests import DynamicClass
  182. # One object references itself
  183. instance = DynamicClass()
  184. instance.circular_reference = instance
  185. cstats = ConstructorStats.get(DynamicClass)
  186. assert cstats.alive() == 1
  187. del instance
  188. assert cstats.alive() == 0
  189. # Two object reference each other
  190. i1 = DynamicClass()
  191. i2 = DynamicClass()
  192. i1.cycle = i2
  193. i2.cycle = i1
  194. assert cstats.alive() == 2
  195. del i1, i2
  196. assert cstats.alive() == 0
  197. def test_noconvert_args(msg):
  198. from pybind11_tests import ArgInspector, arg_inspect_func, floats_only, floats_preferred
  199. a = ArgInspector()
  200. assert msg(a.f("hi")) == """
  201. loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
  202. """
  203. assert msg(a.g("this is a", "this is b")) == """
  204. loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
  205. loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
  206. 13
  207. loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
  208. """ # noqa: E501 line too long
  209. assert msg(a.g("this is a", "this is b", 42)) == """
  210. loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
  211. loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
  212. 42
  213. loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
  214. """ # noqa: E501 line too long
  215. assert msg(a.g("this is a", "this is b", 42, "this is d")) == """
  216. loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
  217. loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
  218. 42
  219. loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d
  220. """
  221. assert (a.h("arg 1") ==
  222. "loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1")
  223. assert msg(arg_inspect_func("A1", "A2")) == """
  224. loading ArgInspector2 argument WITH conversion allowed. Argument value = A1
  225. loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2
  226. """
  227. assert floats_preferred(4) == 2.0
  228. assert floats_only(4.0) == 2.0
  229. with pytest.raises(TypeError) as excinfo:
  230. floats_only(4)
  231. assert msg(excinfo.value) == """
  232. floats_only(): incompatible function arguments. The following argument types are supported:
  233. 1. (f: float) -> float
  234. Invoked with: 4
  235. """
  236. def test_bad_arg_default(msg):
  237. from pybind11_tests import debug_enabled, bad_arg_def_named, bad_arg_def_unnamed
  238. with pytest.raises(RuntimeError) as excinfo:
  239. bad_arg_def_named()
  240. assert msg(excinfo.value) == (
  241. "arg(): could not convert default argument 'a: NotRegistered' in function 'should_fail' "
  242. "into a Python object (type not registered yet?)"
  243. if debug_enabled else
  244. "arg(): could not convert default argument into a Python object (type not registered "
  245. "yet?). Compile in debug mode for more information."
  246. )
  247. with pytest.raises(RuntimeError) as excinfo:
  248. bad_arg_def_unnamed()
  249. assert msg(excinfo.value) == (
  250. "arg(): could not convert default argument 'NotRegistered' in function 'should_fail' "
  251. "into a Python object (type not registered yet?)"
  252. if debug_enabled else
  253. "arg(): could not convert default argument into a Python object (type not registered "
  254. "yet?). Compile in debug mode for more information."
  255. )