diff options
author | gatecat <gatecat@ds0.me> | 2022-09-14 09:28:47 +0200 |
---|---|---|
committer | gatecat <gatecat@ds0.me> | 2022-09-14 09:28:47 +0200 |
commit | a72f898ff4c4237424c468044a6db9d6953b541e (patch) | |
tree | 1c4a543f661dd1b281aecf4660388491702fa8d8 /3rdparty/pybind11/tests/test_pytypes.py | |
parent | f1349e114f3a16ccd002e8513339e18f5be4d31b (diff) | |
download | nextpnr-a72f898ff4c4237424c468044a6db9d6953b541e.tar.gz nextpnr-a72f898ff4c4237424c468044a6db9d6953b541e.tar.bz2 nextpnr-a72f898ff4c4237424c468044a6db9d6953b541e.zip |
3rdparty: Bump vendored pybind11 version for py3.11 support
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to '3rdparty/pybind11/tests/test_pytypes.py')
-rw-r--r-- | 3rdparty/pybind11/tests/test_pytypes.py | 517 |
1 files changed, 429 insertions, 88 deletions
diff --git a/3rdparty/pybind11/tests/test_pytypes.py b/3rdparty/pybind11/tests/test_pytypes.py index 9e5c302e..a34eaa59 100644 --- a/3rdparty/pybind11/tests/test_pytypes.py +++ b/3rdparty/pybind11/tests/test_pytypes.py @@ -1,12 +1,21 @@ -# -*- coding: utf-8 -*- -from __future__ import division -import pytest +import contextlib import sys +import types -import env # noqa: F401 +import pytest +import env +from pybind11_tests import detailed_error_messages_enabled from pybind11_tests import pytypes as m -from pybind11_tests import debug_enabled + + +def test_handle_from_move_only_type_with_operator_PyObject(): # noqa: N802 + assert m.handle_from_move_only_type_with_operator_PyObject_ncnst() + assert m.handle_from_move_only_type_with_operator_PyObject_const() + + +def test_bool(doc): + assert doc(m.get_bool) == "get_bool() -> bool" def test_int(doc): @@ -17,11 +26,40 @@ def test_iterator(doc): assert doc(m.get_iterator) == "get_iterator() -> Iterator" +@pytest.mark.parametrize( + "pytype, from_iter_func", + [ + (frozenset, m.get_frozenset_from_iterable), + (list, m.get_list_from_iterable), + (set, m.get_set_from_iterable), + (tuple, m.get_tuple_from_iterable), + ], +) +def test_from_iterable(pytype, from_iter_func): + my_iter = iter(range(10)) + s = from_iter_func(my_iter) + assert type(s) == pytype + assert s == pytype(range(10)) + + def test_iterable(doc): assert doc(m.get_iterable) == "get_iterable() -> Iterable" +def test_float(doc): + assert doc(m.get_float) == "get_float() -> float" + + def test_list(capture, doc): + assert m.list_no_args() == [] + assert m.list_ssize_t() == [] + assert m.list_size_t() == [] + lins = [1, 2] + m.list_insert_ssize_t(lins) + assert lins == [1, 83, 2] + m.list_insert_size_t(lins) + assert lins == [1, 83, 2, 57] + with capture: lst = m.get_list() assert lst == ["inserted-0", "overwritten", "inserted-2"] @@ -50,11 +88,12 @@ def test_none(capture, doc): def test_set(capture, doc): s = m.get_set() + assert isinstance(s, set) assert s == {"key1", "key2", "key3"} + s.add("key4") with capture: - s.add("key4") - m.print_set(s) + m.print_anyset(s) assert ( capture.unordered == """ @@ -65,12 +104,43 @@ def test_set(capture, doc): """ ) - assert not m.set_contains(set([]), 42) - assert m.set_contains({42}, 42) - assert m.set_contains({"foo"}, "foo") + m.set_add(s, "key5") + assert m.anyset_size(s) == 5 - assert doc(m.get_list) == "get_list() -> list" - assert doc(m.print_list) == "print_list(arg0: list) -> None" + m.set_clear(s) + assert m.anyset_empty(s) + + assert not m.anyset_contains(set(), 42) + assert m.anyset_contains({42}, 42) + assert m.anyset_contains({"foo"}, "foo") + + assert doc(m.get_set) == "get_set() -> set" + assert doc(m.print_anyset) == "print_anyset(arg0: anyset) -> None" + + +def test_frozenset(capture, doc): + s = m.get_frozenset() + assert isinstance(s, frozenset) + assert s == frozenset({"key1", "key2", "key3"}) + + with capture: + m.print_anyset(s) + assert ( + capture.unordered + == """ + key: key1 + key: key2 + key: key3 + """ + ) + assert m.anyset_size(s) == 3 + assert not m.anyset_empty(s) + + assert not m.anyset_contains(frozenset(), 42) + assert m.anyset_contains(frozenset({42}), 42) + assert m.anyset_contains(frozenset({"foo"}), "foo") + + assert doc(m.get_frozenset) == "get_frozenset() -> frozenset" def test_dict(capture, doc): @@ -98,13 +168,30 @@ def test_dict(capture, doc): assert m.dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3} +def test_tuple(): + assert m.tuple_no_args() == () + assert m.tuple_ssize_t() == () + assert m.tuple_size_t() == () + assert m.get_tuple() == (42, None, "spam") + + +def test_simple_namespace(): + ns = m.get_simple_namespace() + assert ns.attr == 42 + assert ns.x == "foo" + assert ns.right == 2 + assert not hasattr(ns, "wrong") + + def test_str(doc): + assert m.str_from_char_ssize_t().encode().decode() == "red" + assert m.str_from_char_size_t().encode().decode() == "blue" assert m.str_from_string().encode().decode() == "baz" assert m.str_from_bytes().encode().decode() == "boo" assert doc(m.str_from_bytes) == "str_from_bytes() -> str" - class A(object): + class A: def __str__(self): return "this is a str" @@ -120,24 +207,32 @@ def test_str(doc): 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) + if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"): + assert m.str_from_object(malformed_utf8) is malformed_utf8 else: - # assert m.str_from_object(malformed_utf8) == "b'\\x80'" - assert m.str_from_handle(malformed_utf8) == "b'\\x80'" + assert m.str_from_object(malformed_utf8) == "b'\\x80'" + assert m.str_from_handle(malformed_utf8) == "b'\\x80'" + + assert m.str_from_string_from_str("this is a str") == "this is a str" + ucs_surrogates_str = "\udcc3" + with pytest.raises(UnicodeEncodeError): + m.str_from_string_from_str(ucs_surrogates_str) def test_bytes(doc): + assert m.bytes_from_char_ssize_t().decode() == "green" + assert m.bytes_from_char_size_t().decode() == "purple" assert m.bytes_from_string().decode() == "foo" assert m.bytes_from_str().decode() == "bar" - assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format( - "str" if env.PY2 else "bytes" - ) + assert doc(m.bytes_from_str) == "bytes_from_str() -> bytes" + + +def test_bytearray(doc): + assert m.bytearray_from_char_ssize_t().decode() == "$%" + assert m.bytearray_from_char_size_t().decode() == "@$!" + assert m.bytearray_from_string().decode() == "foo" + assert m.bytearray_size() == len("foo") def test_capsule(capture): @@ -155,6 +250,19 @@ def test_capsule(capture): ) with capture: + a = m.return_renamed_capsule_with_destructor() + del a + pytest.gc_collect() + assert ( + capture.unordered + == """ + creating capsule + renaming capsule + destructing capsule + """ + ) + + with capture: a = m.return_capsule_with_destructor_2() del a pytest.gc_collect() @@ -167,6 +275,19 @@ def test_capsule(capture): ) with capture: + a = m.return_renamed_capsule_with_destructor_2() + del a + pytest.gc_collect() + assert ( + capture.unordered + == """ + creating capsule + renaming capsule + destructing capsule: 1234 + """ + ) + + with capture: a = m.return_capsule_with_name_and_destructor() del a pytest.gc_collect() @@ -218,19 +339,23 @@ def test_accessors(): assert d["var"] == 99 +def test_accessor_moves(): + inc_refs = m.accessor_moves() + if inc_refs: + assert inc_refs == [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0] + else: + pytest.skip("Not defined: PYBIND11_HANDLE_REF_DEBUG") + + def test_constructors(): """C++ default and converting constructors are equivalent to type calls in Python""" - types = [bytes, str, bool, int, float, tuple, list, dict, set] + types = [bytes, bytearray, 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. + bytearray: bytearray(b"41"), str: 42, bool: "Not empty", int: "42", @@ -239,15 +364,11 @@ def test_constructors(): list: range(3), dict: [("two", 2), ("one", 1), ("three", 3)], set: [4, 4, 5, 6, 6, 6], + frozenset: [4, 4, 5, 6, 6, 6], 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 @@ -268,46 +389,54 @@ def test_non_converting_constructors(): ("bytes", range(10)), ("none", 42), ("ellipsis", 42), + ("type", 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 + for move in [True, False]: + with pytest.raises(TypeError) as excinfo: + m.nonconverting_constructor(t, v, move) + expected_error = ( + f"Object of type '{type(v).__name__}' is not an instance of '{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" + assert cvt("Str") == "Str" + assert cvt(b"Bytes") == "b'Bytes'" + assert cvt(None) == "None" + assert cvt(False) == "False" + assert cvt(True) == "True" + assert cvt(42) == "42" + assert cvt(2**65) == "36893488147419103232" + assert cvt(-1.50) == "-1.5" + assert cvt(()) == "()" + assert cvt((18,)) == "(18,)" + assert cvt([]) == "[]" + assert cvt([28]) == "[28]" + assert cvt({}) == "{}" + assert cvt({3: 4}) == "{3: 4}" + assert cvt(set()) == "set()" + assert cvt({3, 3}) == "{3}" + + valid_orig = "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" + if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"): + assert valid_cvt is valid_utf8 + else: + assert type(valid_cvt) is str + 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" + if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"): + assert cvt(malformed_utf8) is malformed_utf8 + else: + malformed_cvt = cvt(malformed_utf8) + assert type(malformed_cvt) is str + assert malformed_cvt == "b'\\x80'" def test_implicit_casting(): @@ -348,22 +477,22 @@ def test_print(capture): 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)" + assert str(excinfo.value) == "Unable to convert call argument " + ( + "'1' of type 'UnregisteredType' to Python object" + if detailed_error_messages_enabled + else "to Python object (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)" ) def test_hash(): - class Hashable(object): + class Hashable: def __init__(self, value): self.value = value def __hash__(self): return self.value - class Unhashable(object): + class Unhashable: __hash__ = None assert m.hash_function(Hashable(42)) == 42 @@ -403,7 +532,8 @@ def test_issue2361(): 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) + assert "NoneType" in str(excinfo.value) + assert "iterable" in str(excinfo.value) @pytest.mark.parametrize( @@ -420,12 +550,7 @@ 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) + assert list(view) == list(expected_view) @pytest.mark.xfail("env.PYPY", reason="getrefcount is not available") @@ -449,12 +574,7 @@ 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 <memoryview, while CPython 2 has <memory - assert bytes(view).startswith(b"<memory") - else: - assert bytes(view) == b"" + assert bytes(view) == b"" def test_test_memoryview_from_buffer_invalid_strides(): @@ -463,14 +583,10 @@ def test_test_memoryview_from_buffer_invalid_strides(): def test_test_memoryview_from_buffer_nullptr(): - if env.PY2: + with pytest.raises(ValueError): m.test_memoryview_from_buffer_nullptr() - else: - with pytest.raises(ValueError): - m.test_memoryview_from_buffer_nullptr() -@pytest.mark.skipif("env.PY2") def test_memoryview_from_memory(): view = m.test_memoryview_from_memory() assert isinstance(view, memoryview) @@ -486,3 +602,228 @@ def test_builtin_functions(): "object of type 'generator' has no len()", "'generator' has no length", ] # PyPy + + +def test_isinstance_string_types(): + assert m.isinstance_pybind11_bytes(b"") + assert not m.isinstance_pybind11_bytes("") + + assert m.isinstance_pybind11_str("") + if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"): + assert m.isinstance_pybind11_str(b"") + else: + assert not m.isinstance_pybind11_str(b"") + + +def test_pass_bytes_or_unicode_to_string_types(): + assert m.pass_to_pybind11_bytes(b"Bytes") == 5 + with pytest.raises(TypeError): + m.pass_to_pybind11_bytes("Str") + + if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"): + assert m.pass_to_pybind11_str(b"Bytes") == 5 + else: + with pytest.raises(TypeError): + m.pass_to_pybind11_str(b"Bytes") + assert m.pass_to_pybind11_str("Str") == 3 + + assert m.pass_to_std_string(b"Bytes") == 5 + assert m.pass_to_std_string("Str") == 3 + + malformed_utf8 = b"\x80" + if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"): + assert m.pass_to_pybind11_str(malformed_utf8) == 1 + else: + with pytest.raises(TypeError): + m.pass_to_pybind11_str(malformed_utf8) + + +@pytest.mark.parametrize( + "create_weakref, create_weakref_with_callback", + [ + (m.weakref_from_handle, m.weakref_from_handle_and_function), + (m.weakref_from_object, m.weakref_from_object_and_function), + ], +) +def test_weakref(create_weakref, create_weakref_with_callback): + from weakref import getweakrefcount + + # Apparently, you cannot weakly reference an object() + class WeaklyReferenced: + pass + + callback_called = False + + def callback(wr): + nonlocal callback_called + callback_called = True + + obj = WeaklyReferenced() + assert getweakrefcount(obj) == 0 + wr = create_weakref(obj) + assert getweakrefcount(obj) == 1 + + obj = WeaklyReferenced() + assert getweakrefcount(obj) == 0 + wr = create_weakref_with_callback(obj, callback) # noqa: F841 + assert getweakrefcount(obj) == 1 + assert not callback_called + del obj + pytest.gc_collect() + assert callback_called + + +@pytest.mark.parametrize( + "create_weakref, has_callback", + [ + (m.weakref_from_handle, False), + (m.weakref_from_object, False), + (m.weakref_from_handle_and_function, True), + (m.weakref_from_object_and_function, True), + ], +) +def test_weakref_err(create_weakref, has_callback): + class C: + __slots__ = [] + + def callback(_): + pass + + ob = C() + # Should raise TypeError on CPython + with pytest.raises(TypeError) if not env.PYPY else contextlib.nullcontext(): + if has_callback: + _ = create_weakref(ob, callback) + else: + _ = create_weakref(ob) + + +def test_cpp_iterators(): + assert m.tuple_iterator() == 12 + assert m.dict_iterator() == 305 + 711 + assert m.passed_iterator(iter((-7, 3))) == -4 + + +def test_implementation_details(): + lst = [39, 43, 92, 49, 22, 29, 93, 98, 26, 57, 8] + tup = tuple(lst) + assert m.sequence_item_get_ssize_t(lst) == 43 + assert m.sequence_item_set_ssize_t(lst) is None + assert lst[1] == "peppa" + assert m.sequence_item_get_size_t(lst) == 92 + assert m.sequence_item_set_size_t(lst) is None + assert lst[2] == "george" + assert m.list_item_get_ssize_t(lst) == 49 + assert m.list_item_set_ssize_t(lst) is None + assert lst[3] == "rebecca" + assert m.list_item_get_size_t(lst) == 22 + assert m.list_item_set_size_t(lst) is None + assert lst[4] == "richard" + assert m.tuple_item_get_ssize_t(tup) == 29 + assert m.tuple_item_set_ssize_t() == ("emely", "edmond") + assert m.tuple_item_get_size_t(tup) == 93 + assert m.tuple_item_set_size_t() == ("candy", "cat") + + +def test_external_float_(): + r1 = m.square_float_(2.0) + assert r1 == 4.0 + + +def test_tuple_rvalue_getter(): + pop = 1000 + tup = tuple(range(pop)) + m.tuple_rvalue_getter(tup) + + +def test_list_rvalue_getter(): + pop = 1000 + my_list = list(range(pop)) + m.list_rvalue_getter(my_list) + + +def test_populate_dict_rvalue(): + pop = 1000 + my_dict = {i: i for i in range(pop)} + assert m.populate_dict_rvalue(pop) == my_dict + + +def test_populate_obj_str_attrs(): + pop = 1000 + o = types.SimpleNamespace(**{str(i): i for i in range(pop)}) + new_o = m.populate_obj_str_attrs(o, pop) + new_attrs = {k: v for k, v in new_o.__dict__.items() if not k.startswith("_")} + assert all(isinstance(v, str) for v in new_attrs.values()) + assert len(new_attrs) == pop + + +@pytest.mark.parametrize( + "a,b", [("foo", "bar"), (1, 2), (1.0, 2.0), (list(range(3)), list(range(3, 6)))] +) +def test_inplace_append(a, b): + expected = a + b + assert m.inplace_append(a, b) == expected + + +@pytest.mark.parametrize("a,b", [(3, 2), (3.0, 2.0), (set(range(3)), set(range(2)))]) +def test_inplace_subtract(a, b): + expected = a - b + assert m.inplace_subtract(a, b) == expected + + +@pytest.mark.parametrize("a,b", [(3, 2), (3.0, 2.0), ([1], 3)]) +def test_inplace_multiply(a, b): + expected = a * b + assert m.inplace_multiply(a, b) == expected + + +@pytest.mark.parametrize("a,b", [(6, 3), (6.0, 3.0)]) +def test_inplace_divide(a, b): + expected = a / b + assert m.inplace_divide(a, b) == expected + + +@pytest.mark.parametrize( + "a,b", + [ + (False, True), + ( + set(), + { + 1, + }, + ), + ], +) +def test_inplace_or(a, b): + expected = a | b + assert m.inplace_or(a, b) == expected + + +@pytest.mark.parametrize( + "a,b", + [ + (True, False), + ( + {1, 2, 3}, + { + 1, + }, + ), + ], +) +def test_inplace_and(a, b): + expected = a & b + assert m.inplace_and(a, b) == expected + + +@pytest.mark.parametrize("a,b", [(8, 1), (-3, 2)]) +def test_inplace_lshift(a, b): + expected = a << b + assert m.inplace_lshift(a, b) == expected + + +@pytest.mark.parametrize("a,b", [(8, 1), (-2, 2)]) +def test_inplace_rshift(a, b): + expected = a >> b + assert m.inplace_rshift(a, b) == expected |