From e76cdab6dd77bad411e6ac9372ee527aff89ef17 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sat, 2 Jan 2021 10:15:39 +0100 Subject: Update pybind11 to version 2.6.1 --- 3rdparty/pybind11/tests/test_pytypes.py | 263 +++++++++++++++++++++++++++++--- 1 file changed, 244 insertions(+), 19 deletions(-) (limited to '3rdparty/pybind11/tests/test_pytypes.py') diff --git a/3rdparty/pybind11/tests/test_pytypes.py b/3rdparty/pybind11/tests/test_pytypes.py index 0e8d6c33..9e5c302e 100644 --- a/3rdparty/pybind11/tests/test_pytypes.py +++ b/3rdparty/pybind11/tests/test_pytypes.py @@ -1,11 +1,26 @@ +# -*- coding: utf-8 -*- from __future__ import division import pytest import sys +import env # noqa: F401 + from pybind11_tests import pytypes as m from pybind11_tests import debug_enabled +def test_int(doc): + assert doc(m.get_int) == "get_int() -> int" + + +def test_iterator(doc): + assert doc(m.get_iterator) == "get_iterator() -> Iterator" + + +def test_iterable(doc): + assert doc(m.get_iterable) == "get_iterable() -> Iterable" + + def test_list(capture, doc): with capture: lst = m.get_list() @@ -13,18 +28,26 @@ def test_list(capture, doc): lst.append("value2") m.print_list(lst) - assert capture.unordered == """ + assert ( + capture.unordered + == """ Entry at position 0: value list item 0: inserted-0 list item 1: overwritten list item 2: inserted-2 list item 3: value2 """ + ) assert doc(m.get_list) == "get_list() -> list" assert doc(m.print_list) == "print_list(arg0: list) -> None" +def test_none(capture, doc): + assert doc(m.get_none) == "get_none() -> None" + assert doc(m.print_none) == "print_none(arg0: None) -> None" + + def test_set(capture, doc): s = m.get_set() assert s == {"key1", "key2", "key3"} @@ -32,12 +55,15 @@ def test_set(capture, doc): with capture: s.add("key4") m.print_set(s) - assert capture.unordered == """ + assert ( + capture.unordered + == """ key: key1 key: key2 key: key3 key: key4 """ + ) assert not m.set_contains(set([]), 42) assert m.set_contains({42}, 42) @@ -54,10 +80,13 @@ def test_dict(capture, doc): with capture: d["key2"] = "value2" m.print_dict(d) - assert capture.unordered == """ + assert ( + capture.unordered + == """ key: key, value=value key: key2, value=value2 """ + ) assert not m.dict_contains({}, 42) assert m.dict_contains({42: None}, 42) @@ -84,18 +113,30 @@ def test_str(doc): assert m.str_from_object(A()) == "this is a str" assert m.repr_from_object(A()) == "this is a repr" + assert m.str_from_handle(A()) == "this is a str" s1, s2 = m.str_format() assert s1 == "1 + 2 = 3" assert s1 == s2 + malformed_utf8 = b"\x80" + assert m.str_from_object(malformed_utf8) is malformed_utf8 # To be fixed; see #2380 + if env.PY2: + # with pytest.raises(UnicodeDecodeError): + # m.str_from_object(malformed_utf8) + with pytest.raises(UnicodeDecodeError): + m.str_from_handle(malformed_utf8) + else: + # assert m.str_from_object(malformed_utf8) == "b'\\x80'" + assert m.str_from_handle(malformed_utf8) == "b'\\x80'" + def test_bytes(doc): assert m.bytes_from_string().decode() == "foo" assert m.bytes_from_str().decode() == "bar" assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format( - "bytes" if sys.version_info[0] == 3 else "str" + "str" if env.PY2 else "bytes" ) @@ -105,28 +146,37 @@ def test_capsule(capture): a = m.return_capsule_with_destructor() del a pytest.gc_collect() - assert capture.unordered == """ + assert ( + capture.unordered + == """ creating capsule destructing capsule """ + ) with capture: a = m.return_capsule_with_destructor_2() del a pytest.gc_collect() - assert capture.unordered == """ + assert ( + capture.unordered + == """ creating capsule destructing capsule: 1234 """ + ) with capture: a = m.return_capsule_with_name_and_destructor() del a pytest.gc_collect() - assert capture.unordered == """ + assert ( + capture.unordered + == """ created capsule (1234, 'pointer type description') destructing capsule (1234, 'pointer type description') """ + ) def test_accessors(): @@ -170,11 +220,17 @@ def test_accessors(): def test_constructors(): """C++ default and converting constructors are equivalent to type calls in Python""" - types = [str, bool, int, float, tuple, list, dict, set] + types = [bytes, str, bool, int, float, tuple, list, dict, set] expected = {t.__name__: t() for t in types} + if env.PY2: + # Note that bytes.__name__ == 'str' in Python 2. + # pybind11::str is unicode even under Python 2. + expected["bytes"] = bytes() + expected["str"] = unicode() # noqa: F821 assert m.default_constructors() == expected data = { + bytes: b"41", # Currently no supported or working conversions. str: 42, bool: "Not empty", int: "42", @@ -183,10 +239,15 @@ def test_constructors(): list: range(3), dict: [("two", 2), ("one", 1), ("three", 3)], set: [4, 4, 5, 6, 6, 6], - memoryview: b'abc' + memoryview: b"abc", } inputs = {k.__name__: v for k, v in data.items()} expected = {k.__name__: k(v) for k, v in data.items()} + if env.PY2: # Similar to the above. See comments above. + inputs["bytes"] = b"41" + inputs["str"] = 42 + expected["bytes"] = b"41" + expected["str"] = u"42" assert m.converting_constructors(inputs) == expected assert m.cast_functions(inputs) == expected @@ -202,21 +263,79 @@ def test_constructors(): assert noconv2[k] is expected[k] +def test_non_converting_constructors(): + non_converting_test_cases = [ + ("bytes", range(10)), + ("none", 42), + ("ellipsis", 42), + ] + for t, v in non_converting_test_cases: + with pytest.raises(TypeError) as excinfo: + m.nonconverting_constructor(t, v) + expected_error = "Object of type '{}' is not an instance of '{}'".format( + type(v).__name__, t + ) + assert str(excinfo.value) == expected_error + + +def test_pybind11_str_raw_str(): + # specifically to exercise pybind11::str::raw_str + cvt = m.convert_to_pybind11_str + assert cvt(u"Str") == u"Str" + assert cvt(b"Bytes") == u"Bytes" if env.PY2 else "b'Bytes'" + assert cvt(None) == u"None" + assert cvt(False) == u"False" + assert cvt(True) == u"True" + assert cvt(42) == u"42" + assert cvt(2 ** 65) == u"36893488147419103232" + assert cvt(-1.50) == u"-1.5" + assert cvt(()) == u"()" + assert cvt((18,)) == u"(18,)" + assert cvt([]) == u"[]" + assert cvt([28]) == u"[28]" + assert cvt({}) == u"{}" + assert cvt({3: 4}) == u"{3: 4}" + assert cvt(set()) == u"set([])" if env.PY2 else "set()" + assert cvt({3, 3}) == u"set([3])" if env.PY2 else "{3}" + + valid_orig = u"DZ" + valid_utf8 = valid_orig.encode("utf-8") + valid_cvt = cvt(valid_utf8) + assert type(valid_cvt) == bytes # Probably surprising. + assert valid_cvt == b"\xc7\xb1" + + malformed_utf8 = b"\x80" + malformed_cvt = cvt(malformed_utf8) + assert type(malformed_cvt) == bytes # Probably surprising. + assert malformed_cvt == b"\x80" + + def test_implicit_casting(): """Tests implicit casting when assigning or appending to dicts and lists.""" z = m.get_implicit_casting() - assert z['d'] == { - 'char*_i1': 'abc', 'char*_i2': 'abc', 'char*_e': 'abc', 'char*_p': 'abc', - 'str_i1': 'str', 'str_i2': 'str1', 'str_e': 'str2', 'str_p': 'str3', - 'int_i1': 42, 'int_i2': 42, 'int_e': 43, 'int_p': 44 + assert z["d"] == { + "char*_i1": "abc", + "char*_i2": "abc", + "char*_e": "abc", + "char*_p": "abc", + "str_i1": "str", + "str_i2": "str1", + "str_e": "str2", + "str_p": "str3", + "int_i1": 42, + "int_i2": 42, + "int_e": 43, + "int_p": 44, } - assert z['l'] == [3, 6, 9, 12, 15] + assert z["l"] == [3, 6, 9, 12, 15] def test_print(capture): with capture: m.print_function() - assert capture == """ + assert ( + capture + == """ Hello, World! 1 2.0 three True -- multiple args *args-and-a-custom-separator @@ -224,14 +343,15 @@ def test_print(capture): flush py::print + str.format = this """ + ) assert capture.stderr == "this goes to stderr" with pytest.raises(RuntimeError) as excinfo: m.print_failure() assert str(excinfo.value) == "make_tuple(): unable to convert " + ( "argument of type 'UnregisteredType' to Python object" - if debug_enabled else - "arguments to Python object (compile in debug mode for details)" + if debug_enabled + else "arguments to Python object (compile in debug mode for details)" ) @@ -253,11 +373,116 @@ def test_hash(): def test_number_protocol(): for a, b in [(1, 1), (3, 5)]: - li = [a == b, a != b, a < b, a <= b, a > b, a >= b, a + b, - a - b, a * b, a / b, a | b, a & b, a ^ b, a >> b, a << b] + li = [ + a == b, + a != b, + a < b, + a <= b, + a > b, + a >= b, + a + b, + a - b, + a * b, + a / b, + a | b, + a & b, + a ^ b, + a >> b, + a << b, + ] assert m.test_number_protocol(a, b) == li def test_list_slicing(): li = list(range(100)) assert li[::2] == m.test_list_slicing(li) + + +def test_issue2361(): + # See issue #2361 + assert m.issue2361_str_implicit_copy_none() == "None" + with pytest.raises(TypeError) as excinfo: + assert m.issue2361_dict_implicit_copy_none() + assert "'NoneType' object is not iterable" in str(excinfo.value) + + +@pytest.mark.parametrize( + "method, args, fmt, expected_view", + [ + (m.test_memoryview_object, (b"red",), "B", b"red"), + (m.test_memoryview_buffer_info, (b"green",), "B", b"green"), + (m.test_memoryview_from_buffer, (False,), "h", [3, 1, 4, 1, 5]), + (m.test_memoryview_from_buffer, (True,), "H", [2, 7, 1, 8]), + (m.test_memoryview_from_buffer_nativeformat, (), "@i", [4, 7, 5]), + ], +) +def test_memoryview(method, args, fmt, expected_view): + view = method(*args) + assert isinstance(view, memoryview) + assert view.format == fmt + if isinstance(expected_view, bytes) or not env.PY2: + view_as_list = list(view) + else: + # Using max to pick non-zero byte (big-endian vs little-endian). + view_as_list = [max([ord(c) for c in s]) for s in view] + assert view_as_list == list(expected_view) + + +@pytest.mark.xfail("env.PYPY", reason="getrefcount is not available") +@pytest.mark.parametrize( + "method", + [ + m.test_memoryview_object, + m.test_memoryview_buffer_info, + ], +) +def test_memoryview_refcount(method): + buf = b"\x0a\x0b\x0c\x0d" + ref_before = sys.getrefcount(buf) + view = method(buf) + ref_after = sys.getrefcount(buf) + assert ref_before < ref_after + assert list(view) == list(buf) + + +def test_memoryview_from_buffer_empty_shape(): + view = m.test_memoryview_from_buffer_empty_shape() + assert isinstance(view, memoryview) + assert view.format == "B" + if env.PY2: + # Python 2 behavior is weird, but Python 3 (the future) is fine. + # PyPy3 has