cppyabm  1.0.17
An agent-based library to integrate C++ and Python
test_pytypes.py
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 from __future__ import division
3 import pytest
4 import sys
5 
6 import env # noqa: F401
7 
8 from pybind11_tests import pytypes as m
9 from pybind11_tests import debug_enabled
10 
11 
12 def test_int(doc):
13  assert doc(m.get_int) == "get_int() -> int"
14 
15 
16 def test_iterator(doc):
17  assert doc(m.get_iterator) == "get_iterator() -> Iterator"
18 
19 
20 def test_iterable(doc):
21  assert doc(m.get_iterable) == "get_iterable() -> Iterable"
22 
23 
24 def test_list(capture, doc):
25  with capture:
26  lst = m.get_list()
27  assert lst == ["inserted-0", "overwritten", "inserted-2"]
28 
29  lst.append("value2")
30  m.print_list(lst)
31  assert (
32  capture.unordered
33  == """
34  Entry at position 0: value
35  list item 0: inserted-0
36  list item 1: overwritten
37  list item 2: inserted-2
38  list item 3: value2
39  """
40  )
41 
42  assert doc(m.get_list) == "get_list() -> list"
43  assert doc(m.print_list) == "print_list(arg0: list) -> None"
44 
45 
46 def test_none(capture, doc):
47  assert doc(m.get_none) == "get_none() -> None"
48  assert doc(m.print_none) == "print_none(arg0: None) -> None"
49 
50 
51 def test_set(capture, doc):
52  s = m.get_set()
53  assert s == {"key1", "key2", "key3"}
54 
55  with capture:
56  s.add("key4")
57  m.print_set(s)
58  assert (
59  capture.unordered
60  == """
61  key: key1
62  key: key2
63  key: key3
64  key: key4
65  """
66  )
67 
68  assert not m.set_contains(set([]), 42)
69  assert m.set_contains({42}, 42)
70  assert m.set_contains({"foo"}, "foo")
71 
72  assert doc(m.get_list) == "get_list() -> list"
73  assert doc(m.print_list) == "print_list(arg0: list) -> None"
74 
75 
76 def test_dict(capture, doc):
77  d = m.get_dict()
78  assert d == {"key": "value"}
79 
80  with capture:
81  d["key2"] = "value2"
82  m.print_dict(d)
83  assert (
84  capture.unordered
85  == """
86  key: key, value=value
87  key: key2, value=value2
88  """
89  )
90 
91  assert not m.dict_contains({}, 42)
92  assert m.dict_contains({42: None}, 42)
93  assert m.dict_contains({"foo": None}, "foo")
94 
95  assert doc(m.get_dict) == "get_dict() -> dict"
96  assert doc(m.print_dict) == "print_dict(arg0: dict) -> None"
97 
98  assert m.dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3}
99 
100 
101 def test_str(doc):
102  assert m.str_from_string().encode().decode() == "baz"
103  assert m.str_from_bytes().encode().decode() == "boo"
104 
105  assert doc(m.str_from_bytes) == "str_from_bytes() -> str"
106 
107  class A(object):
108  def __str__(self):
109  return "this is a str"
110 
111  def __repr__(self):
112  return "this is a repr"
113 
114  assert m.str_from_object(A()) == "this is a str"
115  assert m.repr_from_object(A()) == "this is a repr"
116  assert m.str_from_handle(A()) == "this is a str"
117 
118  s1, s2 = m.str_format()
119  assert s1 == "1 + 2 = 3"
120  assert s1 == s2
121 
122  malformed_utf8 = b"\x80"
123  if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
124  assert m.str_from_object(malformed_utf8) is malformed_utf8
125  elif env.PY2:
126  with pytest.raises(UnicodeDecodeError):
127  m.str_from_object(malformed_utf8)
128  else:
129  assert m.str_from_object(malformed_utf8) == "b'\\x80'"
130  if env.PY2:
131  with pytest.raises(UnicodeDecodeError):
132  m.str_from_handle(malformed_utf8)
133  else:
134  assert m.str_from_handle(malformed_utf8) == "b'\\x80'"
135 
136 
137 def test_bytes(doc):
138  assert m.bytes_from_string().decode() == "foo"
139  assert m.bytes_from_str().decode() == "bar"
140 
141  assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format(
142  "str" if env.PY2 else "bytes"
143  )
144 
145 
146 def test_capsule(capture):
147  pytest.gc_collect()
148  with capture:
149  a = m.return_capsule_with_destructor()
150  del a
151  pytest.gc_collect()
152  assert (
153  capture.unordered
154  == """
155  creating capsule
156  destructing capsule
157  """
158  )
159 
160  with capture:
161  a = m.return_capsule_with_destructor_2()
162  del a
163  pytest.gc_collect()
164  assert (
165  capture.unordered
166  == """
167  creating capsule
168  destructing capsule: 1234
169  """
170  )
171 
172  with capture:
173  a = m.return_capsule_with_name_and_destructor()
174  del a
175  pytest.gc_collect()
176  assert (
177  capture.unordered
178  == """
179  created capsule (1234, 'pointer type description')
180  destructing capsule (1234, 'pointer type description')
181  """
182  )
183 
184 
186  class SubTestObject:
187  attr_obj = 1
188  attr_char = 2
189 
190  class TestObject:
191  basic_attr = 1
192  begin_end = [1, 2, 3]
193  d = {"operator[object]": 1, "operator[char *]": 2}
194  sub = SubTestObject()
195 
196  def func(self, x, *args):
197  return self.basic_attr + x + sum(args)
198 
199  d = m.accessor_api(TestObject())
200  assert d["basic_attr"] == 1
201  assert d["begin_end"] == [1, 2, 3]
202  assert d["operator[object]"] == 1
203  assert d["operator[char *]"] == 2
204  assert d["attr(object)"] == 1
205  assert d["attr(char *)"] == 2
206  assert d["missing_attr_ptr"] == "raised"
207  assert d["missing_attr_chain"] == "raised"
208  assert d["is_none"] is False
209  assert d["operator()"] == 2
210  assert d["operator*"] == 7
211  assert d["implicit_list"] == [1, 2, 3]
212  assert all(x in TestObject.__dict__ for x in d["implicit_dict"])
213 
214  assert m.tuple_accessor(tuple()) == (0, 1, 2)
215 
216  d = m.accessor_assignment()
217  assert d["get"] == 0
218  assert d["deferred_get"] == 0
219  assert d["set"] == 1
220  assert d["deferred_set"] == 1
221  assert d["var"] == 99
222 
223 
225  """C++ default and converting constructors are equivalent to type calls in Python"""
226  types = [bytes, str, bool, int, float, tuple, list, dict, set]
227  expected = {t.__name__: t() for t in types}
228  if env.PY2:
229  # Note that bytes.__name__ == 'str' in Python 2.
230  # pybind11::str is unicode even under Python 2.
231  expected["bytes"] = bytes()
232  expected["str"] = unicode() # noqa: F821
233  assert m.default_constructors() == expected
234 
235  data = {
236  bytes: b"41", # Currently no supported or working conversions.
237  str: 42,
238  bool: "Not empty",
239  int: "42",
240  float: "+1e3",
241  tuple: range(3),
242  list: range(3),
243  dict: [("two", 2), ("one", 1), ("three", 3)],
244  set: [4, 4, 5, 6, 6, 6],
245  memoryview: b"abc",
246  }
247  inputs = {k.__name__: v for k, v in data.items()}
248  expected = {k.__name__: k(v) for k, v in data.items()}
249  if env.PY2: # Similar to the above. See comments above.
250  inputs["bytes"] = b"41"
251  inputs["str"] = 42
252  expected["bytes"] = b"41"
253  expected["str"] = u"42"
254 
255  assert m.converting_constructors(inputs) == expected
256  assert m.cast_functions(inputs) == expected
257 
258  # Converting constructors and cast functions should just reference rather
259  # than copy when no conversion is needed:
260  noconv1 = m.converting_constructors(expected)
261  for k in noconv1:
262  assert noconv1[k] is expected[k]
263 
264  noconv2 = m.cast_functions(expected)
265  for k in noconv2:
266  assert noconv2[k] is expected[k]
267 
268 
270  non_converting_test_cases = [
271  ("bytes", range(10)),
272  ("none", 42),
273  ("ellipsis", 42),
274  ("type", 42),
275  ]
276  for t, v in non_converting_test_cases:
277  for move in [True, False]:
278  with pytest.raises(TypeError) as excinfo:
279  m.nonconverting_constructor(t, v, move)
280  expected_error = "Object of type '{}' is not an instance of '{}'".format(
281  type(v).__name__, t
282  )
283  assert str(excinfo.value) == expected_error
284 
285 
287  # specifically to exercise pybind11::str::raw_str
288  cvt = m.convert_to_pybind11_str
289  assert cvt(u"Str") == u"Str"
290  assert cvt(b"Bytes") == u"Bytes" if env.PY2 else "b'Bytes'"
291  assert cvt(None) == u"None"
292  assert cvt(False) == u"False"
293  assert cvt(True) == u"True"
294  assert cvt(42) == u"42"
295  assert cvt(2 ** 65) == u"36893488147419103232"
296  assert cvt(-1.50) == u"-1.5"
297  assert cvt(()) == u"()"
298  assert cvt((18,)) == u"(18,)"
299  assert cvt([]) == u"[]"
300  assert cvt([28]) == u"[28]"
301  assert cvt({}) == u"{}"
302  assert cvt({3: 4}) == u"{3: 4}"
303  assert cvt(set()) == u"set([])" if env.PY2 else "set()"
304  assert cvt({3, 3}) == u"set([3])" if env.PY2 else "{3}"
305 
306  valid_orig = u"DZ"
307  valid_utf8 = valid_orig.encode("utf-8")
308  valid_cvt = cvt(valid_utf8)
309  if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
310  assert valid_cvt is valid_utf8
311  else:
312  assert type(valid_cvt) is unicode if env.PY2 else str # noqa: F821
313  if env.PY2:
314  assert valid_cvt == valid_orig
315  else:
316  assert valid_cvt == "b'\\xc7\\xb1'"
317 
318  malformed_utf8 = b"\x80"
319  if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
320  assert cvt(malformed_utf8) is malformed_utf8
321  else:
322  if env.PY2:
323  with pytest.raises(UnicodeDecodeError):
324  cvt(malformed_utf8)
325  else:
326  malformed_cvt = cvt(malformed_utf8)
327  assert type(malformed_cvt) is str
328  assert malformed_cvt == "b'\\x80'"
329 
330 
332  """Tests implicit casting when assigning or appending to dicts and lists."""
333  z = m.get_implicit_casting()
334  assert z["d"] == {
335  "char*_i1": "abc",
336  "char*_i2": "abc",
337  "char*_e": "abc",
338  "char*_p": "abc",
339  "str_i1": "str",
340  "str_i2": "str1",
341  "str_e": "str2",
342  "str_p": "str3",
343  "int_i1": 42,
344  "int_i2": 42,
345  "int_e": 43,
346  "int_p": 44,
347  }
348  assert z["l"] == [3, 6, 9, 12, 15]
349 
350 
351 def test_print(capture):
352  with capture:
353  m.print_function()
354  assert (
355  capture
356  == """
357  Hello, World!
358  1 2.0 three True -- multiple args
359  *args-and-a-custom-separator
360  no new line here -- next print
361  flush
362  py::print + str.format = this
363  """
364  )
365  assert capture.stderr == "this goes to stderr"
366 
367  with pytest.raises(RuntimeError) as excinfo:
368  m.print_failure()
369  assert str(excinfo.value) == "make_tuple(): unable to convert " + (
370  "argument of type 'UnregisteredType' to Python object"
371  if debug_enabled
372  else "arguments to Python object (compile in debug mode for details)"
373  )
374 
375 
376 def test_hash():
377  class Hashable(object):
378  def __init__(self, value):
379  self.value = value
380 
381  def __hash__(self):
382  return self.value
383 
384  class Unhashable(object):
385  __hash__ = None
386 
387  assert m.hash_function(Hashable(42)) == 42
388  with pytest.raises(TypeError):
389  m.hash_function(Unhashable())
390 
391 
393  for a, b in [(1, 1), (3, 5)]:
394  li = [
395  a == b,
396  a != b,
397  a < b,
398  a <= b,
399  a > b,
400  a >= b,
401  a + b,
402  a - b,
403  a * b,
404  a / b,
405  a | b,
406  a & b,
407  a ^ b,
408  a >> b,
409  a << b,
410  ]
411  assert m.test_number_protocol(a, b) == li
412 
413 
415  li = list(range(100))
416  assert li[::2] == m.test_list_slicing(li)
417 
418 
420  # See issue #2361
421  assert m.issue2361_str_implicit_copy_none() == "None"
422  with pytest.raises(TypeError) as excinfo:
423  assert m.issue2361_dict_implicit_copy_none()
424  assert "'NoneType' object is not iterable" in str(excinfo.value)
425 
426 
427 @pytest.mark.parametrize(
428  "method, args, fmt, expected_view",
429  [
430  (m.test_memoryview_object, (b"red",), "B", b"red"),
431  (m.test_memoryview_buffer_info, (b"green",), "B", b"green"),
432  (m.test_memoryview_from_buffer, (False,), "h", [3, 1, 4, 1, 5]),
433  (m.test_memoryview_from_buffer, (True,), "H", [2, 7, 1, 8]),
434  (m.test_memoryview_from_buffer_nativeformat, (), "@i", [4, 7, 5]),
435  ],
436 )
437 def test_memoryview(method, args, fmt, expected_view):
438  view = method(*args)
439  assert isinstance(view, memoryview)
440  assert view.format == fmt
441  if isinstance(expected_view, bytes) or not env.PY2:
442  view_as_list = list(view)
443  else:
444  # Using max to pick non-zero byte (big-endian vs little-endian).
445  view_as_list = [max([ord(c) for c in s]) for s in view]
446  assert view_as_list == list(expected_view)
447 
448 
449 @pytest.mark.xfail("env.PYPY", reason="getrefcount is not available")
450 @pytest.mark.parametrize(
451  "method",
452  [
453  m.test_memoryview_object,
454  m.test_memoryview_buffer_info,
455  ],
456 )
458  buf = b"\x0a\x0b\x0c\x0d"
459  ref_before = sys.getrefcount(buf)
460  view = method(buf)
461  ref_after = sys.getrefcount(buf)
462  assert ref_before < ref_after
463  assert list(view) == list(buf)
464 
465 
467  view = m.test_memoryview_from_buffer_empty_shape()
468  assert isinstance(view, memoryview)
469  assert view.format == "B"
470  if env.PY2:
471  # Python 2 behavior is weird, but Python 3 (the future) is fine.
472  # PyPy3 has <memoryview, while CPython 2 has <memory
473  assert bytes(view).startswith(b"<memory")
474  else:
475  assert bytes(view) == b""
476 
477 
479  with pytest.raises(RuntimeError):
480  m.test_memoryview_from_buffer_invalid_strides()
481 
482 
484  if env.PY2:
485  m.test_memoryview_from_buffer_nullptr()
486  else:
487  with pytest.raises(ValueError):
488  m.test_memoryview_from_buffer_nullptr()
489 
490 
491 @pytest.mark.skipif("env.PY2")
493  view = m.test_memoryview_from_memory()
494  assert isinstance(view, memoryview)
495  assert view.format == "B"
496  assert bytes(view) == b"\xff\xe1\xab\x37"
497 
498 
500  assert m.get_len([i for i in range(42)]) == 42
501  with pytest.raises(TypeError) as exc_info:
502  m.get_len(i for i in range(42))
503  assert str(exc_info.value) in [
504  "object of type 'generator' has no len()",
505  "'generator' has no length",
506  ] # PyPy
507 
508 
510  assert m.isinstance_pybind11_bytes(b"")
511  assert not m.isinstance_pybind11_bytes(u"")
512 
513  assert m.isinstance_pybind11_str(u"")
514  if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
515  assert m.isinstance_pybind11_str(b"")
516  else:
517  assert not m.isinstance_pybind11_str(b"")
518 
519 
521  assert m.pass_to_pybind11_bytes(b"Bytes") == 5
522  with pytest.raises(TypeError):
523  m.pass_to_pybind11_bytes(u"Str")
524 
525  if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE") or env.PY2:
526  assert m.pass_to_pybind11_str(b"Bytes") == 5
527  else:
528  with pytest.raises(TypeError):
529  m.pass_to_pybind11_str(b"Bytes")
530  assert m.pass_to_pybind11_str(u"Str") == 3
531 
532  assert m.pass_to_std_string(b"Bytes") == 5
533  assert m.pass_to_std_string(u"Str") == 3
534 
535  malformed_utf8 = b"\x80"
536  if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
537  assert m.pass_to_pybind11_str(malformed_utf8) == 1
538  elif env.PY2:
539  with pytest.raises(UnicodeDecodeError):
540  m.pass_to_pybind11_str(malformed_utf8)
541  else:
542  with pytest.raises(TypeError):
543  m.pass_to_pybind11_str(malformed_utf8)
544 
545 
546 @pytest.mark.parametrize(
547  "create_weakref, create_weakref_with_callback",
548  [
549  (m.weakref_from_handle, m.weakref_from_handle_and_function),
550  (m.weakref_from_object, m.weakref_from_object_and_function),
551  ],
552 )
553 def test_weakref(create_weakref, create_weakref_with_callback):
554  from weakref import getweakrefcount
555 
556  # Apparently, you cannot weakly reference an object()
557  class WeaklyReferenced(object):
558  pass
559 
560  def callback(wr):
561  # No `nonlocal` in Python 2
562  callback.called = True
563 
564  obj = WeaklyReferenced()
565  assert getweakrefcount(obj) == 0
566  wr = create_weakref(obj) # noqa: F841
567  assert getweakrefcount(obj) == 1
568 
569  obj = WeaklyReferenced()
570  assert getweakrefcount(obj) == 0
571  callback.called = False
572  wr = create_weakref_with_callback(obj, callback) # noqa: F841
573  assert getweakrefcount(obj) == 1
574  assert not callback.called
575  del obj
576  pytest.gc_collect()
577  assert callback.called
test_pytypes.test_dict
def test_dict(capture, doc)
Definition: test_pytypes.py:76
test_pytypes.test_implicit_casting
def test_implicit_casting()
Definition: test_pytypes.py:331
test_pytypes.test_str
def test_str(doc)
Definition: test_pytypes.py:101
bytes
Definition: pytypes.h:1013
set
Definition: pytypes.h:1369
test_pytypes.test_iterator
def test_iterator(doc)
Definition: test_pytypes.py:16
test_pytypes.test_pybind11_str_raw_str
def test_pybind11_str_raw_str()
Definition: test_pytypes.py:286
list
Definition: pytypes.h:1345
test_pytypes.test_test_memoryview_from_buffer_invalid_strides
def test_test_memoryview_from_buffer_invalid_strides()
Definition: test_pytypes.py:478
test_pytypes.test_test_memoryview_from_buffer_nullptr
def test_test_memoryview_from_buffer_nullptr()
Definition: test_pytypes.py:483
hasattr
bool hasattr(handle obj, handle name)
Definition: pytypes.h:405
test_pytypes.test_memoryview_refcount
def test_memoryview_refcount(method)
Definition: test_pytypes.py:457
type
Definition: pytypes.h:915
test_pytypes.test_hash
def test_hash()
Definition: test_pytypes.py:376
test_pytypes.test_builtin_functions
def test_builtin_functions()
Definition: test_pytypes.py:499
test_pytypes.test_list
def test_list(capture, doc)
Definition: test_pytypes.py:24
test_pytypes.test_pass_bytes_or_unicode_to_string_types
def test_pass_bytes_or_unicode_to_string_types()
Definition: test_pytypes.py:520
test_pytypes.test_memoryview_from_memory
def test_memoryview_from_memory()
Definition: test_pytypes.py:492
test_pytypes.test_constructors
def test_constructors()
Definition: test_pytypes.py:224
test_pytypes.test_print
def test_print(capture)
Definition: test_pytypes.py:351
test_pytypes.test_none
def test_none(capture, doc)
Definition: test_pytypes.py:46
object
Definition: pytypes.h:232
doc
Annotation for documentation.
Definition: attr.h:33
isinstance
bool isinstance(handle obj)
Definition: pytypes.h:386
test_pytypes.test_set
def test_set(capture, doc)
Definition: test_pytypes.py:51
test_pytypes.test_accessors
def test_accessors()
Definition: test_pytypes.py:185
test_pytypes.test_int
def test_int(doc)
Definition: test_pytypes.py:12
A
Definition: test_numpy_dtypes.cpp:254
str
Definition: pytypes.h:946
test_pytypes.test_bytes
def test_bytes(doc)
Definition: test_pytypes.py:137
test_pytypes.test_weakref
def test_weakref(create_weakref, create_weakref_with_callback)
Definition: test_pytypes.py:553
tuple
Definition: pytypes.h:1276
test_pytypes.test_memoryview_from_buffer_empty_shape
def test_memoryview_from_buffer_empty_shape()
Definition: test_pytypes.py:466
test_pytypes.test_iterable
def test_iterable(doc)
Definition: test_pytypes.py:20
test_pytypes.test_memoryview
def test_memoryview(method, args, fmt, expected_view)
Definition: test_pytypes.py:437
test_pytypes.test_non_converting_constructors
def test_non_converting_constructors()
Definition: test_pytypes.py:269
test_pytypes.test_list_slicing
def test_list_slicing()
Definition: test_pytypes.py:414
test_pytypes.test_isinstance_string_types
def test_isinstance_string_types()
Definition: test_pytypes.py:509
test_pytypes.test_number_protocol
def test_number_protocol()
Definition: test_pytypes.py:392
test_pytypes.test_capsule
def test_capsule(capture)
Definition: test_pytypes.py:146
test_pytypes.test_issue2361
def test_issue2361()
Definition: test_pytypes.py:419