test_methods_and_attributes.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. import pytest
  2. from pybind11_tests import methods_and_attributes as m
  3. from pybind11_tests import ConstructorStats
  4. def test_methods_and_attributes():
  5. instance1 = m.ExampleMandA()
  6. instance2 = m.ExampleMandA(32)
  7. instance1.add1(instance2)
  8. instance1.add2(instance2)
  9. instance1.add3(instance2)
  10. instance1.add4(instance2)
  11. instance1.add5(instance2)
  12. instance1.add6(32)
  13. instance1.add7(32)
  14. instance1.add8(32)
  15. instance1.add9(32)
  16. instance1.add10(32)
  17. assert str(instance1) == "ExampleMandA[value=320]"
  18. assert str(instance2) == "ExampleMandA[value=32]"
  19. assert str(instance1.self1()) == "ExampleMandA[value=320]"
  20. assert str(instance1.self2()) == "ExampleMandA[value=320]"
  21. assert str(instance1.self3()) == "ExampleMandA[value=320]"
  22. assert str(instance1.self4()) == "ExampleMandA[value=320]"
  23. assert str(instance1.self5()) == "ExampleMandA[value=320]"
  24. assert instance1.internal1() == 320
  25. assert instance1.internal2() == 320
  26. assert instance1.internal3() == 320
  27. assert instance1.internal4() == 320
  28. assert instance1.internal5() == 320
  29. assert instance1.overloaded() == "()"
  30. assert instance1.overloaded(0) == "(int)"
  31. assert instance1.overloaded(1, 1.0) == "(int, float)"
  32. assert instance1.overloaded(2.0, 2) == "(float, int)"
  33. assert instance1.overloaded(3, 3) == "(int, int)"
  34. assert instance1.overloaded(4., 4.) == "(float, float)"
  35. assert instance1.overloaded_const(-3) == "(int) const"
  36. assert instance1.overloaded_const(5, 5.0) == "(int, float) const"
  37. assert instance1.overloaded_const(6.0, 6) == "(float, int) const"
  38. assert instance1.overloaded_const(7, 7) == "(int, int) const"
  39. assert instance1.overloaded_const(8., 8.) == "(float, float) const"
  40. assert instance1.overloaded_float(1, 1) == "(float, float)"
  41. assert instance1.overloaded_float(1, 1.) == "(float, float)"
  42. assert instance1.overloaded_float(1., 1) == "(float, float)"
  43. assert instance1.overloaded_float(1., 1.) == "(float, float)"
  44. assert instance1.value == 320
  45. instance1.value = 100
  46. assert str(instance1) == "ExampleMandA[value=100]"
  47. cstats = ConstructorStats.get(m.ExampleMandA)
  48. assert cstats.alive() == 2
  49. del instance1, instance2
  50. assert cstats.alive() == 0
  51. assert cstats.values() == ["32"]
  52. assert cstats.default_constructions == 1
  53. assert cstats.copy_constructions == 3
  54. assert cstats.move_constructions >= 1
  55. assert cstats.copy_assignments == 0
  56. assert cstats.move_assignments == 0
  57. def test_copy_method():
  58. """Issue #443: calling copied methods fails in Python 3"""
  59. m.ExampleMandA.add2c = m.ExampleMandA.add2
  60. m.ExampleMandA.add2d = m.ExampleMandA.add2b
  61. a = m.ExampleMandA(123)
  62. assert a.value == 123
  63. a.add2(m.ExampleMandA(-100))
  64. assert a.value == 23
  65. a.add2b(m.ExampleMandA(20))
  66. assert a.value == 43
  67. a.add2c(m.ExampleMandA(6))
  68. assert a.value == 49
  69. a.add2d(m.ExampleMandA(-7))
  70. assert a.value == 42
  71. def test_properties():
  72. instance = m.TestProperties()
  73. assert instance.def_readonly == 1
  74. with pytest.raises(AttributeError):
  75. instance.def_readonly = 2
  76. instance.def_readwrite = 2
  77. assert instance.def_readwrite == 2
  78. assert instance.def_property_readonly == 2
  79. with pytest.raises(AttributeError):
  80. instance.def_property_readonly = 3
  81. instance.def_property = 3
  82. assert instance.def_property == 3
  83. def test_static_properties():
  84. assert m.TestProperties.def_readonly_static == 1
  85. with pytest.raises(AttributeError) as excinfo:
  86. m.TestProperties.def_readonly_static = 2
  87. assert "can't set attribute" in str(excinfo)
  88. m.TestProperties.def_readwrite_static = 2
  89. assert m.TestProperties.def_readwrite_static == 2
  90. assert m.TestProperties.def_property_readonly_static == 2
  91. with pytest.raises(AttributeError) as excinfo:
  92. m.TestProperties.def_property_readonly_static = 3
  93. assert "can't set attribute" in str(excinfo)
  94. m.TestProperties.def_property_static = 3
  95. assert m.TestProperties.def_property_static == 3
  96. # Static property read and write via instance
  97. instance = m.TestProperties()
  98. m.TestProperties.def_readwrite_static = 0
  99. assert m.TestProperties.def_readwrite_static == 0
  100. assert instance.def_readwrite_static == 0
  101. instance.def_readwrite_static = 2
  102. assert m.TestProperties.def_readwrite_static == 2
  103. assert instance.def_readwrite_static == 2
  104. # It should be possible to override properties in derived classes
  105. assert m.TestPropertiesOverride().def_readonly == 99
  106. assert m.TestPropertiesOverride.def_readonly_static == 99
  107. def test_static_cls():
  108. """Static property getter and setters expect the type object as the their only argument"""
  109. instance = m.TestProperties()
  110. assert m.TestProperties.static_cls is m.TestProperties
  111. assert instance.static_cls is m.TestProperties
  112. def check_self(self):
  113. assert self is m.TestProperties
  114. m.TestProperties.static_cls = check_self
  115. instance.static_cls = check_self
  116. def test_metaclass_override():
  117. """Overriding pybind11's default metaclass changes the behavior of `static_property`"""
  118. assert type(m.ExampleMandA).__name__ == "pybind11_type"
  119. assert type(m.MetaclassOverride).__name__ == "type"
  120. assert m.MetaclassOverride.readonly == 1
  121. assert type(m.MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property"
  122. # Regular `type` replaces the property instead of calling `__set__()`
  123. m.MetaclassOverride.readonly = 2
  124. assert m.MetaclassOverride.readonly == 2
  125. assert isinstance(m.MetaclassOverride.__dict__["readonly"], int)
  126. def test_no_mixed_overloads():
  127. from pybind11_tests import debug_enabled
  128. with pytest.raises(RuntimeError) as excinfo:
  129. m.ExampleMandA.add_mixed_overloads1()
  130. assert (str(excinfo.value) ==
  131. "overloading a method with both static and instance methods is not supported; " +
  132. ("compile in debug mode for more details" if not debug_enabled else
  133. "error while attempting to bind static method ExampleMandA.overload_mixed1"
  134. "(arg0: float) -> str")
  135. )
  136. with pytest.raises(RuntimeError) as excinfo:
  137. m.ExampleMandA.add_mixed_overloads2()
  138. assert (str(excinfo.value) ==
  139. "overloading a method with both static and instance methods is not supported; " +
  140. ("compile in debug mode for more details" if not debug_enabled else
  141. "error while attempting to bind instance method ExampleMandA.overload_mixed2"
  142. "(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)"
  143. " -> str")
  144. )
  145. @pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
  146. def test_property_return_value_policies(access):
  147. if not access.startswith("static"):
  148. obj = m.TestPropRVP()
  149. else:
  150. obj = m.TestPropRVP
  151. ref = getattr(obj, access + "_ref")
  152. assert ref.value == 1
  153. ref.value = 2
  154. assert getattr(obj, access + "_ref").value == 2
  155. ref.value = 1 # restore original value for static properties
  156. copy = getattr(obj, access + "_copy")
  157. assert copy.value == 1
  158. copy.value = 2
  159. assert getattr(obj, access + "_copy").value == 1
  160. copy = getattr(obj, access + "_func")
  161. assert copy.value == 1
  162. copy.value = 2
  163. assert getattr(obj, access + "_func").value == 1
  164. def test_property_rvalue_policy():
  165. """When returning an rvalue, the return value policy is automatically changed from
  166. `reference(_internal)` to `move`. The following would not work otherwise."""
  167. instance = m.TestPropRVP()
  168. o = instance.rvalue
  169. assert o.value == 1
  170. os = m.TestPropRVP.static_rvalue
  171. assert os.value == 1
  172. # https://bitbucket.org/pypy/pypy/issues/2447
  173. @pytest.unsupported_on_pypy
  174. def test_dynamic_attributes():
  175. instance = m.DynamicClass()
  176. assert not hasattr(instance, "foo")
  177. assert "foo" not in dir(instance)
  178. # Dynamically add attribute
  179. instance.foo = 42
  180. assert hasattr(instance, "foo")
  181. assert instance.foo == 42
  182. assert "foo" in dir(instance)
  183. # __dict__ should be accessible and replaceable
  184. assert "foo" in instance.__dict__
  185. instance.__dict__ = {"bar": True}
  186. assert not hasattr(instance, "foo")
  187. assert hasattr(instance, "bar")
  188. with pytest.raises(TypeError) as excinfo:
  189. instance.__dict__ = []
  190. assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'"
  191. cstats = ConstructorStats.get(m.DynamicClass)
  192. assert cstats.alive() == 1
  193. del instance
  194. assert cstats.alive() == 0
  195. # Derived classes should work as well
  196. class PythonDerivedDynamicClass(m.DynamicClass):
  197. pass
  198. for cls in m.CppDerivedDynamicClass, PythonDerivedDynamicClass:
  199. derived = cls()
  200. derived.foobar = 100
  201. assert derived.foobar == 100
  202. assert cstats.alive() == 1
  203. del derived
  204. assert cstats.alive() == 0
  205. # https://bitbucket.org/pypy/pypy/issues/2447
  206. @pytest.unsupported_on_pypy
  207. def test_cyclic_gc():
  208. # One object references itself
  209. instance = m.DynamicClass()
  210. instance.circular_reference = instance
  211. cstats = ConstructorStats.get(m.DynamicClass)
  212. assert cstats.alive() == 1
  213. del instance
  214. assert cstats.alive() == 0
  215. # Two object reference each other
  216. i1 = m.DynamicClass()
  217. i2 = m.DynamicClass()
  218. i1.cycle = i2
  219. i2.cycle = i1
  220. assert cstats.alive() == 2
  221. del i1, i2
  222. assert cstats.alive() == 0
  223. def test_noconvert_args(msg):
  224. a = m.ArgInspector()
  225. assert msg(a.f("hi")) == """
  226. loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
  227. """
  228. assert msg(a.g("this is a", "this is b")) == """
  229. loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
  230. loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
  231. 13
  232. loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
  233. """ # noqa: E501 line too long
  234. assert msg(a.g("this is a", "this is b", 42)) == """
  235. loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
  236. loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
  237. 42
  238. loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
  239. """ # noqa: E501 line too long
  240. assert msg(a.g("this is a", "this is b", 42, "this is d")) == """
  241. loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
  242. loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
  243. 42
  244. loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d
  245. """
  246. assert (a.h("arg 1") ==
  247. "loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1")
  248. assert msg(m.arg_inspect_func("A1", "A2")) == """
  249. loading ArgInspector2 argument WITH conversion allowed. Argument value = A1
  250. loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2
  251. """
  252. assert m.floats_preferred(4) == 2.0
  253. assert m.floats_only(4.0) == 2.0
  254. with pytest.raises(TypeError) as excinfo:
  255. m.floats_only(4)
  256. assert msg(excinfo.value) == """
  257. floats_only(): incompatible function arguments. The following argument types are supported:
  258. 1. (f: float) -> float
  259. Invoked with: 4
  260. """
  261. assert m.ints_preferred(4) == 2
  262. assert m.ints_preferred(True) == 0
  263. with pytest.raises(TypeError) as excinfo:
  264. m.ints_preferred(4.0)
  265. assert msg(excinfo.value) == """
  266. ints_preferred(): incompatible function arguments. The following argument types are supported:
  267. 1. (i: int) -> int
  268. Invoked with: 4.0
  269. """ # noqa: E501 line too long
  270. assert m.ints_only(4) == 2
  271. with pytest.raises(TypeError) as excinfo:
  272. m.ints_only(4.0)
  273. assert msg(excinfo.value) == """
  274. ints_only(): incompatible function arguments. The following argument types are supported:
  275. 1. (i: int) -> int
  276. Invoked with: 4.0
  277. """
  278. def test_bad_arg_default(msg):
  279. from pybind11_tests import debug_enabled
  280. with pytest.raises(RuntimeError) as excinfo:
  281. m.bad_arg_def_named()
  282. assert msg(excinfo.value) == (
  283. "arg(): could not convert default argument 'a: UnregisteredType' in function "
  284. "'should_fail' into a Python object (type not registered yet?)"
  285. if debug_enabled else
  286. "arg(): could not convert default argument into a Python object (type not registered "
  287. "yet?). Compile in debug mode for more information."
  288. )
  289. with pytest.raises(RuntimeError) as excinfo:
  290. m.bad_arg_def_unnamed()
  291. assert msg(excinfo.value) == (
  292. "arg(): could not convert default argument 'UnregisteredType' in function "
  293. "'should_fail' into a Python object (type not registered yet?)"
  294. if debug_enabled else
  295. "arg(): could not convert default argument into a Python object (type not registered "
  296. "yet?). Compile in debug mode for more information."
  297. )
  298. def test_accepts_none(msg):
  299. a = m.NoneTester()
  300. assert m.no_none1(a) == 42
  301. assert m.no_none2(a) == 42
  302. assert m.no_none3(a) == 42
  303. assert m.no_none4(a) == 42
  304. assert m.no_none5(a) == 42
  305. assert m.ok_none1(a) == 42
  306. assert m.ok_none2(a) == 42
  307. assert m.ok_none3(a) == 42
  308. assert m.ok_none4(a) == 42
  309. assert m.ok_none5(a) == 42
  310. with pytest.raises(TypeError) as excinfo:
  311. m.no_none1(None)
  312. assert "incompatible function arguments" in str(excinfo.value)
  313. with pytest.raises(TypeError) as excinfo:
  314. m.no_none2(None)
  315. assert "incompatible function arguments" in str(excinfo.value)
  316. with pytest.raises(TypeError) as excinfo:
  317. m.no_none3(None)
  318. assert "incompatible function arguments" in str(excinfo.value)
  319. with pytest.raises(TypeError) as excinfo:
  320. m.no_none4(None)
  321. assert "incompatible function arguments" in str(excinfo.value)
  322. with pytest.raises(TypeError) as excinfo:
  323. m.no_none5(None)
  324. assert "incompatible function arguments" in str(excinfo.value)
  325. # The first one still raises because you can't pass None as a lvalue reference arg:
  326. with pytest.raises(TypeError) as excinfo:
  327. assert m.ok_none1(None) == -1
  328. assert msg(excinfo.value) == """
  329. ok_none1(): incompatible function arguments. The following argument types are supported:
  330. 1. (arg0: m.methods_and_attributes.NoneTester) -> int
  331. Invoked with: None
  332. """
  333. # The rest take the argument as pointer or holder, and accept None:
  334. assert m.ok_none2(None) == -1
  335. assert m.ok_none3(None) == -1
  336. assert m.ok_none4(None) == -1
  337. assert m.ok_none5(None) == -1
  338. def test_str_issue(msg):
  339. """#283: __str__ called on uninitialized instance when constructor arguments invalid"""
  340. assert str(m.StrIssue(3)) == "StrIssue[3]"
  341. with pytest.raises(TypeError) as excinfo:
  342. str(m.StrIssue("no", "such", "constructor"))
  343. assert msg(excinfo.value) == """
  344. __init__(): incompatible constructor arguments. The following argument types are supported:
  345. 1. m.methods_and_attributes.StrIssue(arg0: int)
  346. 2. m.methods_and_attributes.StrIssue()
  347. Invoked with: 'no', 'such', 'constructor'
  348. """
  349. def test_unregistered_base_implementations():
  350. a = m.RegisteredDerived()
  351. a.do_nothing()
  352. assert a.rw_value == 42
  353. assert a.ro_value == 1.25
  354. a.rw_value += 5
  355. assert a.sum() == 48.25
  356. a.increase_value()
  357. assert a.rw_value == 48
  358. assert a.ro_value == 1.5
  359. assert a.sum() == 49.5
  360. assert a.rw_value_prop == 48
  361. a.rw_value_prop += 1
  362. assert a.rw_value_prop == 49
  363. a.increase_value()
  364. assert a.ro_value_prop == 1.75
  365. def test_custom_caster_destruction():
  366. """Tests that returning a pointer to a type that gets converted with a custom type caster gets
  367. destroyed when the function has py::return_value_policy::take_ownership policy applied."""
  368. cstats = m.destruction_tester_cstats()
  369. # This one *doesn't* have take_ownership: the pointer should be used but not destroyed:
  370. z = m.custom_caster_no_destroy()
  371. assert cstats.alive() == 1 and cstats.default_constructions == 1
  372. assert z
  373. # take_ownership applied: this constructs a new object, casts it, then destroys it:
  374. z = m.custom_caster_destroy()
  375. assert z
  376. assert cstats.default_constructions == 2
  377. # Same, but with a const pointer return (which should *not* inhibit destruction):
  378. z = m.custom_caster_destroy_const()
  379. assert z
  380. assert cstats.default_constructions == 3
  381. # Make sure we still only have the original object (from ..._no_destroy()) alive:
  382. assert cstats.alive() == 1