aboutsummaryrefslogtreecommitdiffstats
path: root/3rdparty/pybind11/tests
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/pybind11/tests')
-rw-r--r--3rdparty/pybind11/tests/CMakeLists.txt259
-rw-r--r--3rdparty/pybind11/tests/conftest.py244
-rw-r--r--3rdparty/pybind11/tests/constructor_stats.h276
-rw-r--r--3rdparty/pybind11/tests/cross_module_gil_utils.cpp73
-rw-r--r--3rdparty/pybind11/tests/local_bindings.h64
-rw-r--r--3rdparty/pybind11/tests/object.h175
-rw-r--r--3rdparty/pybind11/tests/pybind11_cross_module_tests.cpp123
-rw-r--r--3rdparty/pybind11/tests/pybind11_tests.cpp93
-rw-r--r--3rdparty/pybind11/tests/pybind11_tests.h65
-rw-r--r--3rdparty/pybind11/tests/pytest.ini16
-rw-r--r--3rdparty/pybind11/tests/test_async.cpp26
-rw-r--r--3rdparty/pybind11/tests/test_async.py23
-rw-r--r--3rdparty/pybind11/tests/test_buffers.cpp195
-rw-r--r--3rdparty/pybind11/tests/test_buffers.py118
-rw-r--r--3rdparty/pybind11/tests/test_builtin_casters.cpp188
-rw-r--r--3rdparty/pybind11/tests/test_builtin_casters.py385
-rw-r--r--3rdparty/pybind11/tests/test_call_policies.cpp100
-rw-r--r--3rdparty/pybind11/tests/test_call_policies.py187
-rw-r--r--3rdparty/pybind11/tests/test_callbacks.cpp168
-rw-r--r--3rdparty/pybind11/tests/test_callbacks.py136
-rw-r--r--3rdparty/pybind11/tests/test_chrono.cpp55
-rw-r--r--3rdparty/pybind11/tests/test_chrono.py176
-rw-r--r--3rdparty/pybind11/tests/test_class.cpp422
-rw-r--r--3rdparty/pybind11/tests/test_class.py281
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt58
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/embed.cpp21
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt15
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt12
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt22
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/main.cpp6
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt25
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt8
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt15
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/test.py5
-rw-r--r--3rdparty/pybind11/tests/test_constants_and_functions.cpp127
-rw-r--r--3rdparty/pybind11/tests/test_constants_and_functions.py39
-rw-r--r--3rdparty/pybind11/tests/test_copy_move.cpp213
-rw-r--r--3rdparty/pybind11/tests/test_copy_move.py112
-rw-r--r--3rdparty/pybind11/tests/test_docstring_options.cpp61
-rw-r--r--3rdparty/pybind11/tests/test_docstring_options.py38
-rw-r--r--3rdparty/pybind11/tests/test_eigen.cpp329
-rw-r--r--3rdparty/pybind11/tests/test_eigen.py694
-rw-r--r--3rdparty/pybind11/tests/test_embed/CMakeLists.txt41
-rw-r--r--3rdparty/pybind11/tests/test_embed/catch.cpp22
-rw-r--r--3rdparty/pybind11/tests/test_embed/external_module.cpp23
-rw-r--r--3rdparty/pybind11/tests/test_embed/test_interpreter.cpp284
-rw-r--r--3rdparty/pybind11/tests/test_embed/test_interpreter.py9
-rw-r--r--3rdparty/pybind11/tests/test_enum.cpp87
-rw-r--r--3rdparty/pybind11/tests/test_enum.py206
-rw-r--r--3rdparty/pybind11/tests/test_eval.cpp91
-rw-r--r--3rdparty/pybind11/tests/test_eval.py17
-rw-r--r--3rdparty/pybind11/tests/test_eval_call.py4
-rw-r--r--3rdparty/pybind11/tests/test_exceptions.cpp197
-rw-r--r--3rdparty/pybind11/tests/test_exceptions.py150
-rw-r--r--3rdparty/pybind11/tests/test_factory_constructors.cpp338
-rw-r--r--3rdparty/pybind11/tests/test_factory_constructors.py459
-rw-r--r--3rdparty/pybind11/tests/test_gil_scoped.cpp52
-rw-r--r--3rdparty/pybind11/tests/test_gil_scoped.py85
-rw-r--r--3rdparty/pybind11/tests/test_iostream.cpp73
-rw-r--r--3rdparty/pybind11/tests/test_iostream.py214
-rw-r--r--3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp102
-rw-r--r--3rdparty/pybind11/tests/test_kwargs_and_defaults.py147
-rw-r--r--3rdparty/pybind11/tests/test_local_bindings.cpp101
-rw-r--r--3rdparty/pybind11/tests/test_local_bindings.py226
-rw-r--r--3rdparty/pybind11/tests/test_methods_and_attributes.cpp460
-rw-r--r--3rdparty/pybind11/tests/test_methods_and_attributes.py512
-rw-r--r--3rdparty/pybind11/tests/test_modules.cpp98
-rw-r--r--3rdparty/pybind11/tests/test_modules.py72
-rw-r--r--3rdparty/pybind11/tests/test_multiple_inheritance.cpp220
-rw-r--r--3rdparty/pybind11/tests/test_multiple_inheritance.py349
-rw-r--r--3rdparty/pybind11/tests/test_numpy_array.cpp390
-rw-r--r--3rdparty/pybind11/tests/test_numpy_array.py447
-rw-r--r--3rdparty/pybind11/tests/test_numpy_dtypes.cpp474
-rw-r--r--3rdparty/pybind11/tests/test_numpy_dtypes.py310
-rw-r--r--3rdparty/pybind11/tests/test_numpy_vectorize.cpp89
-rw-r--r--3rdparty/pybind11/tests/test_numpy_vectorize.py196
-rw-r--r--3rdparty/pybind11/tests/test_opaque_types.cpp67
-rw-r--r--3rdparty/pybind11/tests/test_opaque_types.py46
-rw-r--r--3rdparty/pybind11/tests/test_operator_overloading.cpp171
-rw-r--r--3rdparty/pybind11/tests/test_operator_overloading.py108
-rw-r--r--3rdparty/pybind11/tests/test_pickling.cpp130
-rw-r--r--3rdparty/pybind11/tests/test_pickling.py42
-rw-r--r--3rdparty/pybind11/tests/test_pytypes.cpp310
-rw-r--r--3rdparty/pybind11/tests/test_pytypes.py263
-rw-r--r--3rdparty/pybind11/tests/test_sequences_and_iterators.cpp353
-rw-r--r--3rdparty/pybind11/tests/test_sequences_and_iterators.py171
-rw-r--r--3rdparty/pybind11/tests/test_smart_ptr.cpp366
-rw-r--r--3rdparty/pybind11/tests/test_smart_ptr.py286
-rw-r--r--3rdparty/pybind11/tests/test_stl.cpp284
-rw-r--r--3rdparty/pybind11/tests/test_stl.py241
-rw-r--r--3rdparty/pybind11/tests/test_stl_binders.cpp129
-rw-r--r--3rdparty/pybind11/tests/test_stl_binders.py276
-rw-r--r--3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp136
-rw-r--r--3rdparty/pybind11/tests/test_tagbased_polymorphic.py20
-rw-r--r--3rdparty/pybind11/tests/test_union.cpp22
-rw-r--r--3rdparty/pybind11/tests/test_union.py8
-rw-r--r--3rdparty/pybind11/tests/test_virtual_functions.cpp479
-rw-r--r--3rdparty/pybind11/tests/test_virtual_functions.py377
98 files changed, 16478 insertions, 0 deletions
diff --git a/3rdparty/pybind11/tests/CMakeLists.txt b/3rdparty/pybind11/tests/CMakeLists.txt
new file mode 100644
index 00000000..765c47ad
--- /dev/null
+++ b/3rdparty/pybind11/tests/CMakeLists.txt
@@ -0,0 +1,259 @@
+# CMakeLists.txt -- Build system for the pybind11 test suite
+#
+# Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
+#
+# All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+cmake_minimum_required(VERSION 2.8.12)
+
+option(PYBIND11_WERROR "Report all warnings as errors" OFF)
+
+if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
+ # We're being loaded directly, i.e. not via add_subdirectory, so make this
+ # work as its own project and load the pybind11Config to get the tools we need
+ project(pybind11_tests CXX)
+
+ find_package(pybind11 REQUIRED CONFIG)
+endif()
+
+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+ message(STATUS "Setting tests build type to MinSizeRel as none was specified")
+ set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE)
+ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
+ "MinSizeRel" "RelWithDebInfo")
+endif()
+
+# Full set of test files (you can override these; see below)
+set(PYBIND11_TEST_FILES
+ test_async.cpp
+ test_buffers.cpp
+ test_builtin_casters.cpp
+ test_call_policies.cpp
+ test_callbacks.cpp
+ test_chrono.cpp
+ test_class.cpp
+ test_constants_and_functions.cpp
+ test_copy_move.cpp
+ test_docstring_options.cpp
+ test_eigen.cpp
+ test_enum.cpp
+ test_eval.cpp
+ test_exceptions.cpp
+ test_factory_constructors.cpp
+ test_gil_scoped.cpp
+ test_iostream.cpp
+ test_kwargs_and_defaults.cpp
+ test_local_bindings.cpp
+ test_methods_and_attributes.cpp
+ test_modules.cpp
+ test_multiple_inheritance.cpp
+ test_numpy_array.cpp
+ test_numpy_dtypes.cpp
+ test_numpy_vectorize.cpp
+ test_opaque_types.cpp
+ test_operator_overloading.cpp
+ test_pickling.cpp
+ test_pytypes.cpp
+ test_sequences_and_iterators.cpp
+ test_smart_ptr.cpp
+ test_stl.cpp
+ test_stl_binders.cpp
+ test_tagbased_polymorphic.cpp
+ test_union.cpp
+ test_virtual_functions.cpp
+)
+
+# Invoking cmake with something like:
+# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_picking.cpp" ..
+# lets you override the tests that get compiled and run. You can restore to all tests with:
+# cmake -DPYBIND11_TEST_OVERRIDE= ..
+if (PYBIND11_TEST_OVERRIDE)
+ set(PYBIND11_TEST_FILES ${PYBIND11_TEST_OVERRIDE})
+endif()
+
+# Skip test_async for Python < 3.5
+list(FIND PYBIND11_TEST_FILES test_async.cpp PYBIND11_TEST_FILES_ASYNC_I)
+if((PYBIND11_TEST_FILES_ASYNC_I GREATER -1) AND ("${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" VERSION_LESS 3.5))
+ message(STATUS "Skipping test_async because Python version ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} < 3.5")
+ list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_ASYNC_I})
+endif()
+
+string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")
+
+# Contains the set of test files that require pybind11_cross_module_tests to be
+# built; if none of these are built (i.e. because TEST_OVERRIDE is used and
+# doesn't include them) the second module doesn't get built.
+set(PYBIND11_CROSS_MODULE_TESTS
+ test_exceptions.py
+ test_local_bindings.py
+ test_stl.py
+ test_stl_binders.py
+)
+
+set(PYBIND11_CROSS_MODULE_GIL_TESTS
+ test_gil_scoped.py
+)
+
+# Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but
+# keep it in PYBIND11_PYTEST_FILES, so that we get the "eigen is not installed"
+# skip message).
+list(FIND PYBIND11_TEST_FILES test_eigen.cpp PYBIND11_TEST_FILES_EIGEN_I)
+if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
+ # Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake).
+ # Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also
+ # produces a fatal error if loaded from a pre-3.0 cmake.
+ if (NOT CMAKE_VERSION VERSION_LESS 3.0)
+ find_package(Eigen3 3.2.7 QUIET CONFIG)
+ if (EIGEN3_FOUND)
+ if (EIGEN3_VERSION_STRING AND NOT EIGEN3_VERSION_STRING VERSION_LESS 3.3.1)
+ set(PYBIND11_EIGEN_VIA_TARGET 1)
+ endif()
+ endif()
+ endif()
+ if (NOT EIGEN3_FOUND)
+ # Couldn't load via target, so fall back to allowing module mode finding, which will pick up
+ # tools/FindEigen3.cmake
+ find_package(Eigen3 3.2.7 QUIET)
+ endif()
+
+ if(EIGEN3_FOUND)
+ # Eigen 3.3.1+ cmake sets EIGEN3_VERSION_STRING (and hard codes the version when installed
+ # rather than looking it up in the cmake script); older versions, and the
+ # tools/FindEigen3.cmake, set EIGEN3_VERSION instead.
+ if(NOT EIGEN3_VERSION AND EIGEN3_VERSION_STRING)
+ set(EIGEN3_VERSION ${EIGEN3_VERSION_STRING})
+ endif()
+ message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}")
+ else()
+ list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
+ message(STATUS "Building tests WITHOUT Eigen")
+ endif()
+endif()
+
+# Optional dependency for some tests (boost::variant is only supported with version >= 1.56)
+find_package(Boost 1.56)
+
+# Compile with compiler warnings turned on
+function(pybind11_enable_warnings target_name)
+ if(MSVC)
+ target_compile_options(${target_name} PRIVATE /W4)
+ elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)")
+ target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual -Wdeprecated)
+ endif()
+
+ if(PYBIND11_WERROR)
+ if(MSVC)
+ target_compile_options(${target_name} PRIVATE /WX)
+ elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)")
+ target_compile_options(${target_name} PRIVATE -Werror)
+ endif()
+ endif()
+endfunction()
+
+set(test_targets pybind11_tests)
+
+# Build pybind11_cross_module_tests if any test_whatever.py are being built that require it
+foreach(t ${PYBIND11_CROSS_MODULE_TESTS})
+ list(FIND PYBIND11_PYTEST_FILES ${t} i)
+ if (i GREATER -1)
+ list(APPEND test_targets pybind11_cross_module_tests)
+ break()
+ endif()
+endforeach()
+
+foreach(t ${PYBIND11_CROSS_MODULE_GIL_TESTS})
+ list(FIND PYBIND11_PYTEST_FILES ${t} i)
+ if (i GREATER -1)
+ list(APPEND test_targets cross_module_gil_utils)
+ break()
+ endif()
+endforeach()
+
+set(testdir ${CMAKE_CURRENT_SOURCE_DIR})
+foreach(target ${test_targets})
+ set(test_files ${PYBIND11_TEST_FILES})
+ if(NOT target STREQUAL "pybind11_tests")
+ set(test_files "")
+ endif()
+
+ # Create the binding library
+ pybind11_add_module(${target} THIN_LTO ${target}.cpp ${test_files} ${PYBIND11_HEADERS})
+ pybind11_enable_warnings(${target})
+
+ if(MSVC)
+ target_compile_options(${target} PRIVATE /utf-8)
+ endif()
+
+ if(EIGEN3_FOUND)
+ if (PYBIND11_EIGEN_VIA_TARGET)
+ target_link_libraries(${target} PRIVATE Eigen3::Eigen)
+ else()
+ target_include_directories(${target} PRIVATE ${EIGEN3_INCLUDE_DIR})
+ endif()
+ target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_EIGEN)
+ endif()
+
+ if(Boost_FOUND)
+ target_include_directories(${target} PRIVATE ${Boost_INCLUDE_DIRS})
+ target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST)
+ endif()
+
+ # Always write the output file directly into the 'tests' directory (even on MSVC)
+ if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
+ set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${testdir})
+ foreach(config ${CMAKE_CONFIGURATION_TYPES})
+ string(TOUPPER ${config} config)
+ set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} ${testdir})
+ endforeach()
+ endif()
+endforeach()
+
+# Make sure pytest is found or produce a fatal error
+if(NOT PYBIND11_PYTEST_FOUND)
+ execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import pytest; print(pytest.__version__)"
+ RESULT_VARIABLE pytest_not_found OUTPUT_VARIABLE pytest_version ERROR_QUIET)
+ if(pytest_not_found)
+ message(FATAL_ERROR "Running the tests requires pytest. Please install it manually"
+ " (try: ${PYTHON_EXECUTABLE} -m pip install pytest)")
+ elseif(pytest_version VERSION_LESS 3.0)
+ message(FATAL_ERROR "Running the tests requires pytest >= 3.0. Found: ${pytest_version}"
+ "Please update it (try: ${PYTHON_EXECUTABLE} -m pip install -U pytest)")
+ endif()
+ set(PYBIND11_PYTEST_FOUND TRUE CACHE INTERNAL "")
+endif()
+
+if(CMAKE_VERSION VERSION_LESS 3.2)
+ set(PYBIND11_USES_TERMINAL "")
+else()
+ set(PYBIND11_USES_TERMINAL "USES_TERMINAL")
+endif()
+
+# A single command to compile and run the tests
+add_custom_target(pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_PYTEST_FILES}
+ DEPENDS ${test_targets} WORKING_DIRECTORY ${testdir} ${PYBIND11_USES_TERMINAL})
+
+if(PYBIND11_TEST_OVERRIDE)
+ add_custom_command(TARGET pytest POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo "Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect")
+endif()
+
+# Add a check target to run all the tests, starting with pytest (we add dependencies to this below)
+add_custom_target(check DEPENDS pytest)
+
+# The remaining tests only apply when being built as part of the pybind11 project, but not if the
+# tests are being built independently.
+if (NOT PROJECT_NAME STREQUAL "pybind11")
+ return()
+endif()
+
+# Add a post-build comment to show the primary test suite .so size and, if a previous size, compare it:
+add_custom_command(TARGET pybind11_tests POST_BUILD
+ COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/libsize.py
+ $<TARGET_FILE:pybind11_tests> ${CMAKE_CURRENT_BINARY_DIR}/sosize-$<TARGET_FILE_NAME:pybind11_tests>.txt)
+
+# Test embedding the interpreter. Provides the `cpptest` target.
+add_subdirectory(test_embed)
+
+# Test CMake build using functions and targets from subdirectory or installed location
+add_subdirectory(test_cmake_build)
diff --git a/3rdparty/pybind11/tests/conftest.py b/3rdparty/pybind11/tests/conftest.py
new file mode 100644
index 00000000..57f681c6
--- /dev/null
+++ b/3rdparty/pybind11/tests/conftest.py
@@ -0,0 +1,244 @@
+"""pytest configuration
+
+Extends output capture as needed by pybind11: ignore constructors, optional unordered lines.
+Adds docstring and exceptions message sanitizers: ignore Python 2 vs 3 differences.
+"""
+
+import pytest
+import textwrap
+import difflib
+import re
+import sys
+import contextlib
+import platform
+import gc
+
+_unicode_marker = re.compile(r'u(\'[^\']*\')')
+_long_marker = re.compile(r'([0-9])L')
+_hexadecimal = re.compile(r'0x[0-9a-fA-F]+')
+
+# test_async.py requires support for async and await
+collect_ignore = []
+if sys.version_info[:2] < (3, 5):
+ collect_ignore.append("test_async.py")
+
+
+def _strip_and_dedent(s):
+ """For triple-quote strings"""
+ return textwrap.dedent(s.lstrip('\n').rstrip())
+
+
+def _split_and_sort(s):
+ """For output which does not require specific line order"""
+ return sorted(_strip_and_dedent(s).splitlines())
+
+
+def _make_explanation(a, b):
+ """Explanation for a failed assert -- the a and b arguments are List[str]"""
+ return ["--- actual / +++ expected"] + [line.strip('\n') for line in difflib.ndiff(a, b)]
+
+
+class Output(object):
+ """Basic output post-processing and comparison"""
+ def __init__(self, string):
+ self.string = string
+ self.explanation = []
+
+ def __str__(self):
+ return self.string
+
+ def __eq__(self, other):
+ # Ignore constructor/destructor output which is prefixed with "###"
+ a = [line for line in self.string.strip().splitlines() if not line.startswith("###")]
+ b = _strip_and_dedent(other).splitlines()
+ if a == b:
+ return True
+ else:
+ self.explanation = _make_explanation(a, b)
+ return False
+
+
+class Unordered(Output):
+ """Custom comparison for output without strict line ordering"""
+ def __eq__(self, other):
+ a = _split_and_sort(self.string)
+ b = _split_and_sort(other)
+ if a == b:
+ return True
+ else:
+ self.explanation = _make_explanation(a, b)
+ return False
+
+
+class Capture(object):
+ def __init__(self, capfd):
+ self.capfd = capfd
+ self.out = ""
+ self.err = ""
+
+ def __enter__(self):
+ self.capfd.readouterr()
+ return self
+
+ def __exit__(self, *args):
+ self.out, self.err = self.capfd.readouterr()
+
+ def __eq__(self, other):
+ a = Output(self.out)
+ b = other
+ if a == b:
+ return True
+ else:
+ self.explanation = a.explanation
+ return False
+
+ def __str__(self):
+ return self.out
+
+ def __contains__(self, item):
+ return item in self.out
+
+ @property
+ def unordered(self):
+ return Unordered(self.out)
+
+ @property
+ def stderr(self):
+ return Output(self.err)
+
+
+@pytest.fixture
+def capture(capsys):
+ """Extended `capsys` with context manager and custom equality operators"""
+ return Capture(capsys)
+
+
+class SanitizedString(object):
+ def __init__(self, sanitizer):
+ self.sanitizer = sanitizer
+ self.string = ""
+ self.explanation = []
+
+ def __call__(self, thing):
+ self.string = self.sanitizer(thing)
+ return self
+
+ def __eq__(self, other):
+ a = self.string
+ b = _strip_and_dedent(other)
+ if a == b:
+ return True
+ else:
+ self.explanation = _make_explanation(a.splitlines(), b.splitlines())
+ return False
+
+
+def _sanitize_general(s):
+ s = s.strip()
+ s = s.replace("pybind11_tests.", "m.")
+ s = s.replace("unicode", "str")
+ s = _long_marker.sub(r"\1", s)
+ s = _unicode_marker.sub(r"\1", s)
+ return s
+
+
+def _sanitize_docstring(thing):
+ s = thing.__doc__
+ s = _sanitize_general(s)
+ return s
+
+
+@pytest.fixture
+def doc():
+ """Sanitize docstrings and add custom failure explanation"""
+ return SanitizedString(_sanitize_docstring)
+
+
+def _sanitize_message(thing):
+ s = str(thing)
+ s = _sanitize_general(s)
+ s = _hexadecimal.sub("0", s)
+ return s
+
+
+@pytest.fixture
+def msg():
+ """Sanitize messages and add custom failure explanation"""
+ return SanitizedString(_sanitize_message)
+
+
+# noinspection PyUnusedLocal
+def pytest_assertrepr_compare(op, left, right):
+ """Hook to insert custom failure explanation"""
+ if hasattr(left, 'explanation'):
+ return left.explanation
+
+
+@contextlib.contextmanager
+def suppress(exception):
+ """Suppress the desired exception"""
+ try:
+ yield
+ except exception:
+ pass
+
+
+def gc_collect():
+ ''' Run the garbage collector twice (needed when running
+ reference counting tests with PyPy) '''
+ gc.collect()
+ gc.collect()
+
+
+def pytest_configure():
+ """Add import suppression and test requirements to `pytest` namespace"""
+ try:
+ import numpy as np
+ except ImportError:
+ np = None
+ try:
+ import scipy
+ except ImportError:
+ scipy = None
+ try:
+ from pybind11_tests.eigen import have_eigen
+ except ImportError:
+ have_eigen = False
+ pypy = platform.python_implementation() == "PyPy"
+
+ skipif = pytest.mark.skipif
+ pytest.suppress = suppress
+ pytest.requires_numpy = skipif(not np, reason="numpy is not installed")
+ pytest.requires_scipy = skipif(not np, reason="scipy is not installed")
+ pytest.requires_eigen_and_numpy = skipif(not have_eigen or not np,
+ reason="eigen and/or numpy are not installed")
+ pytest.requires_eigen_and_scipy = skipif(
+ not have_eigen or not scipy, reason="eigen and/or scipy are not installed")
+ pytest.unsupported_on_pypy = skipif(pypy, reason="unsupported on PyPy")
+ pytest.unsupported_on_py2 = skipif(sys.version_info.major < 3,
+ reason="unsupported on Python 2.x")
+ pytest.gc_collect = gc_collect
+
+
+def _test_import_pybind11():
+ """Early diagnostic for test module initialization errors
+
+ When there is an error during initialization, the first import will report the
+ real error while all subsequent imports will report nonsense. This import test
+ is done early (in the pytest configuration file, before any tests) in order to
+ avoid the noise of having all tests fail with identical error messages.
+
+ Any possible exception is caught here and reported manually *without* the stack
+ trace. This further reduces noise since the trace would only show pytest internals
+ which are not useful for debugging pybind11 module issues.
+ """
+ # noinspection PyBroadException
+ try:
+ import pybind11_tests # noqa: F401 imported but unused
+ except Exception as e:
+ print("Failed to import pybind11_tests from pytest:")
+ print(" {}: {}".format(type(e).__name__, e))
+ sys.exit(1)
+
+
+_test_import_pybind11()
diff --git a/3rdparty/pybind11/tests/constructor_stats.h b/3rdparty/pybind11/tests/constructor_stats.h
new file mode 100644
index 00000000..431e5ace
--- /dev/null
+++ b/3rdparty/pybind11/tests/constructor_stats.h
@@ -0,0 +1,276 @@
+#pragma once
+/*
+ tests/constructor_stats.h -- framework for printing and tracking object
+ instance lifetimes in example/test code.
+
+ Copyright (c) 2016 Jason Rhinelander <jason@imaginary.ca>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+
+This header provides a few useful tools for writing examples or tests that want to check and/or
+display object instance lifetimes. It requires that you include this header and add the following
+function calls to constructors:
+
+ class MyClass {
+ MyClass() { ...; print_default_created(this); }
+ ~MyClass() { ...; print_destroyed(this); }
+ MyClass(const MyClass &c) { ...; print_copy_created(this); }
+ MyClass(MyClass &&c) { ...; print_move_created(this); }
+ MyClass(int a, int b) { ...; print_created(this, a, b); }
+ MyClass &operator=(const MyClass &c) { ...; print_copy_assigned(this); }
+ MyClass &operator=(MyClass &&c) { ...; print_move_assigned(this); }
+
+ ...
+ }
+
+You can find various examples of these in several of the existing testing .cpp files. (Of course
+you don't need to add any of the above constructors/operators that you don't actually have, except
+for the destructor).
+
+Each of these will print an appropriate message such as:
+
+ ### MyClass @ 0x2801910 created via default constructor
+ ### MyClass @ 0x27fa780 created 100 200
+ ### MyClass @ 0x2801910 destroyed
+ ### MyClass @ 0x27fa780 destroyed
+
+You can also include extra arguments (such as the 100, 200 in the output above, coming from the
+value constructor) for all of the above methods which will be included in the output.
+
+For testing, each of these also keeps track the created instances and allows you to check how many
+of the various constructors have been invoked from the Python side via code such as:
+
+ from pybind11_tests import ConstructorStats
+ cstats = ConstructorStats.get(MyClass)
+ print(cstats.alive())
+ print(cstats.default_constructions)
+
+Note that `.alive()` should usually be the first thing you call as it invokes Python's garbage
+collector to actually destroy objects that aren't yet referenced.
+
+For everything except copy and move constructors and destructors, any extra values given to the
+print_...() function is stored in a class-specific values list which you can retrieve and inspect
+from the ConstructorStats instance `.values()` method.
+
+In some cases, when you need to track instances of a C++ class not registered with pybind11, you
+need to add a function returning the ConstructorStats for the C++ class; this can be done with:
+
+ m.def("get_special_cstats", &ConstructorStats::get<SpecialClass>, py::return_value_policy::reference)
+
+Finally, you can suppress the output messages, but keep the constructor tracking (for
+inspection/testing in python) by using the functions with `print_` replaced with `track_` (e.g.
+`track_copy_created(this)`).
+
+*/
+
+#include "pybind11_tests.h"
+#include <unordered_map>
+#include <list>
+#include <typeindex>
+#include <sstream>
+
+class ConstructorStats {
+protected:
+ std::unordered_map<void*, int> _instances; // Need a map rather than set because members can shared address with parents
+ std::list<std::string> _values; // Used to track values (e.g. of value constructors)
+public:
+ int default_constructions = 0;
+ int copy_constructions = 0;
+ int move_constructions = 0;
+ int copy_assignments = 0;
+ int move_assignments = 0;
+
+ void copy_created(void *inst) {
+ created(inst);
+ copy_constructions++;
+ }
+
+ void move_created(void *inst) {
+ created(inst);
+ move_constructions++;
+ }
+
+ void default_created(void *inst) {
+ created(inst);
+ default_constructions++;
+ }
+
+ void created(void *inst) {
+ ++_instances[inst];
+ }
+
+ void destroyed(void *inst) {
+ if (--_instances[inst] < 0)
+ throw std::runtime_error("cstats.destroyed() called with unknown "
+ "instance; potential double-destruction "
+ "or a missing cstats.created()");
+ }
+
+ static void gc() {
+ // Force garbage collection to ensure any pending destructors are invoked:
+#if defined(PYPY_VERSION)
+ PyObject *globals = PyEval_GetGlobals();
+ PyObject *result = PyRun_String(
+ "import gc\n"
+ "for i in range(2):"
+ " gc.collect()\n",
+ Py_file_input, globals, globals);
+ if (result == nullptr)
+ throw py::error_already_set();
+ Py_DECREF(result);
+#else
+ py::module::import("gc").attr("collect")();
+#endif
+ }
+
+ int alive() {
+ gc();
+ int total = 0;
+ for (const auto &p : _instances)
+ if (p.second > 0)
+ total += p.second;
+ return total;
+ }
+
+ void value() {} // Recursion terminator
+ // Takes one or more values, converts them to strings, then stores them.
+ template <typename T, typename... Tmore> void value(const T &v, Tmore &&...args) {
+ std::ostringstream oss;
+ oss << v;
+ _values.push_back(oss.str());
+ value(std::forward<Tmore>(args)...);
+ }
+
+ // Move out stored values
+ py::list values() {
+ py::list l;
+ for (const auto &v : _values) l.append(py::cast(v));
+ _values.clear();
+ return l;
+ }
+
+ // Gets constructor stats from a C++ type index
+ static ConstructorStats& get(std::type_index type) {
+ static std::unordered_map<std::type_index, ConstructorStats> all_cstats;
+ return all_cstats[type];
+ }
+
+ // Gets constructor stats from a C++ type
+ template <typename T> static ConstructorStats& get() {
+#if defined(PYPY_VERSION)
+ gc();
+#endif
+ return get(typeid(T));
+ }
+
+ // Gets constructor stats from a Python class
+ static ConstructorStats& get(py::object class_) {
+ auto &internals = py::detail::get_internals();
+ const std::type_index *t1 = nullptr, *t2 = nullptr;
+ try {
+ auto *type_info = internals.registered_types_py.at((PyTypeObject *) class_.ptr()).at(0);
+ for (auto &p : internals.registered_types_cpp) {
+ if (p.second == type_info) {
+ if (t1) {
+ t2 = &p.first;
+ break;
+ }
+ t1 = &p.first;
+ }
+ }
+ }
+ catch (const std::out_of_range&) {}
+ if (!t1) throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
+ auto &cs1 = get(*t1);
+ // If we have both a t1 and t2 match, one is probably the trampoline class; return whichever
+ // has more constructions (typically one or the other will be 0)
+ if (t2) {
+ auto &cs2 = get(*t2);
+ int cs1_total = cs1.default_constructions + cs1.copy_constructions + cs1.move_constructions + (int) cs1._values.size();
+ int cs2_total = cs2.default_constructions + cs2.copy_constructions + cs2.move_constructions + (int) cs2._values.size();
+ if (cs2_total > cs1_total) return cs2;
+ }
+ return cs1;
+ }
+};
+
+// To track construction/destruction, you need to call these methods from the various
+// constructors/operators. The ones that take extra values record the given values in the
+// constructor stats values for later inspection.
+template <class T> void track_copy_created(T *inst) { ConstructorStats::get<T>().copy_created(inst); }
+template <class T> void track_move_created(T *inst) { ConstructorStats::get<T>().move_created(inst); }
+template <class T, typename... Values> void track_copy_assigned(T *, Values &&...values) {
+ auto &cst = ConstructorStats::get<T>();
+ cst.copy_assignments++;
+ cst.value(std::forward<Values>(values)...);
+}
+template <class T, typename... Values> void track_move_assigned(T *, Values &&...values) {
+ auto &cst = ConstructorStats::get<T>();
+ cst.move_assignments++;
+ cst.value(std::forward<Values>(values)...);
+}
+template <class T, typename... Values> void track_default_created(T *inst, Values &&...values) {
+ auto &cst = ConstructorStats::get<T>();
+ cst.default_created(inst);
+ cst.value(std::forward<Values>(values)...);
+}
+template <class T, typename... Values> void track_created(T *inst, Values &&...values) {
+ auto &cst = ConstructorStats::get<T>();
+ cst.created(inst);
+ cst.value(std::forward<Values>(values)...);
+}
+template <class T, typename... Values> void track_destroyed(T *inst) {
+ ConstructorStats::get<T>().destroyed(inst);
+}
+template <class T, typename... Values> void track_values(T *, Values &&...values) {
+ ConstructorStats::get<T>().value(std::forward<Values>(values)...);
+}
+
+/// Don't cast pointers to Python, print them as strings
+inline const char *format_ptrs(const char *p) { return p; }
+template <typename T>
+py::str format_ptrs(T *p) { return "{:#x}"_s.format(reinterpret_cast<std::uintptr_t>(p)); }
+template <typename T>
+auto format_ptrs(T &&x) -> decltype(std::forward<T>(x)) { return std::forward<T>(x); }
+
+template <class T, typename... Output>
+void print_constr_details(T *inst, const std::string &action, Output &&...output) {
+ py::print("###", py::type_id<T>(), "@", format_ptrs(inst), action,
+ format_ptrs(std::forward<Output>(output))...);
+}
+
+// Verbose versions of the above:
+template <class T, typename... Values> void print_copy_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
+ print_constr_details(inst, "created via copy constructor", values...);
+ track_copy_created(inst);
+}
+template <class T, typename... Values> void print_move_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
+ print_constr_details(inst, "created via move constructor", values...);
+ track_move_created(inst);
+}
+template <class T, typename... Values> void print_copy_assigned(T *inst, Values &&...values) {
+ print_constr_details(inst, "assigned via copy assignment", values...);
+ track_copy_assigned(inst, values...);
+}
+template <class T, typename... Values> void print_move_assigned(T *inst, Values &&...values) {
+ print_constr_details(inst, "assigned via move assignment", values...);
+ track_move_assigned(inst, values...);
+}
+template <class T, typename... Values> void print_default_created(T *inst, Values &&...values) {
+ print_constr_details(inst, "created via default constructor", values...);
+ track_default_created(inst, values...);
+}
+template <class T, typename... Values> void print_created(T *inst, Values &&...values) {
+ print_constr_details(inst, "created", values...);
+ track_created(inst, values...);
+}
+template <class T, typename... Values> void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values
+ print_constr_details(inst, "destroyed", values...);
+ track_destroyed(inst);
+}
+template <class T, typename... Values> void print_values(T *inst, Values &&...values) {
+ print_constr_details(inst, ":", values...);
+ track_values(inst, values...);
+}
+
diff --git a/3rdparty/pybind11/tests/cross_module_gil_utils.cpp b/3rdparty/pybind11/tests/cross_module_gil_utils.cpp
new file mode 100644
index 00000000..07db9f6e
--- /dev/null
+++ b/3rdparty/pybind11/tests/cross_module_gil_utils.cpp
@@ -0,0 +1,73 @@
+/*
+ tests/cross_module_gil_utils.cpp -- tools for acquiring GIL from a different module
+
+ Copyright (c) 2019 Google LLC
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+#include <pybind11/pybind11.h>
+#include <cstdint>
+
+// This file mimics a DSO that makes pybind11 calls but does not define a
+// PYBIND11_MODULE. The purpose is to test that such a DSO can create a
+// py::gil_scoped_acquire when the running thread is in a GIL-released state.
+//
+// Note that we define a Python module here for convenience, but in general
+// this need not be the case. The typical scenario would be a DSO that implements
+// shared logic used internally by multiple pybind11 modules.
+
+namespace {
+
+namespace py = pybind11;
+void gil_acquire() { py::gil_scoped_acquire gil; }
+
+constexpr char kModuleName[] = "cross_module_gil_utils";
+
+#if PY_MAJOR_VERSION >= 3
+struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ kModuleName,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+#else
+PyMethodDef module_methods[] = {
+ {NULL, NULL, 0, NULL}
+};
+#endif
+
+} // namespace
+
+extern "C" PYBIND11_EXPORT
+#if PY_MAJOR_VERSION >= 3
+PyObject* PyInit_cross_module_gil_utils()
+#else
+void initcross_module_gil_utils()
+#endif
+{
+
+ PyObject* m =
+#if PY_MAJOR_VERSION >= 3
+ PyModule_Create(&moduledef);
+#else
+ Py_InitModule(kModuleName, module_methods);
+#endif
+
+ if (m != NULL) {
+ static_assert(
+ sizeof(&gil_acquire) == sizeof(void*),
+ "Function pointer must have the same size as void*");
+ PyModule_AddObject(m, "gil_acquire_funcaddr",
+ PyLong_FromVoidPtr(reinterpret_cast<void*>(&gil_acquire)));
+ }
+
+#if PY_MAJOR_VERSION >= 3
+ return m;
+#endif
+}
diff --git a/3rdparty/pybind11/tests/local_bindings.h b/3rdparty/pybind11/tests/local_bindings.h
new file mode 100644
index 00000000..b6afb808
--- /dev/null
+++ b/3rdparty/pybind11/tests/local_bindings.h
@@ -0,0 +1,64 @@
+#pragma once
+#include "pybind11_tests.h"
+
+/// Simple class used to test py::local:
+template <int> class LocalBase {
+public:
+ LocalBase(int i) : i(i) { }
+ int i = -1;
+};
+
+/// Registered with py::module_local in both main and secondary modules:
+using LocalType = LocalBase<0>;
+/// Registered without py::module_local in both modules:
+using NonLocalType = LocalBase<1>;
+/// A second non-local type (for stl_bind tests):
+using NonLocal2 = LocalBase<2>;
+/// Tests within-module, different-compilation-unit local definition conflict:
+using LocalExternal = LocalBase<3>;
+/// Mixed: registered local first, then global
+using MixedLocalGlobal = LocalBase<4>;
+/// Mixed: global first, then local
+using MixedGlobalLocal = LocalBase<5>;
+
+/// Registered with py::module_local only in the secondary module:
+using ExternalType1 = LocalBase<6>;
+using ExternalType2 = LocalBase<7>;
+
+using LocalVec = std::vector<LocalType>;
+using LocalVec2 = std::vector<NonLocal2>;
+using LocalMap = std::unordered_map<std::string, LocalType>;
+using NonLocalVec = std::vector<NonLocalType>;
+using NonLocalVec2 = std::vector<NonLocal2>;
+using NonLocalMap = std::unordered_map<std::string, NonLocalType>;
+using NonLocalMap2 = std::unordered_map<std::string, uint8_t>;
+
+PYBIND11_MAKE_OPAQUE(LocalVec);
+PYBIND11_MAKE_OPAQUE(LocalVec2);
+PYBIND11_MAKE_OPAQUE(LocalMap);
+PYBIND11_MAKE_OPAQUE(NonLocalVec);
+//PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2
+PYBIND11_MAKE_OPAQUE(NonLocalMap);
+PYBIND11_MAKE_OPAQUE(NonLocalMap2);
+
+
+// Simple bindings (used with the above):
+template <typename T, int Adjust = 0, typename... Args>
+py::class_<T> bind_local(Args && ...args) {
+ return py::class_<T>(std::forward<Args>(args)...)
+ .def(py::init<int>())
+ .def("get", [](T &i) { return i.i + Adjust; });
+};
+
+// Simulate a foreign library base class (to match the example in the docs):
+namespace pets {
+class Pet {
+public:
+ Pet(std::string name) : name_(name) {}
+ std::string name_;
+ const std::string &name() { return name_; }
+};
+}
+
+struct MixGL { int i; MixGL(int i) : i{i} {} };
+struct MixGL2 { int i; MixGL2(int i) : i{i} {} };
diff --git a/3rdparty/pybind11/tests/object.h b/3rdparty/pybind11/tests/object.h
new file mode 100644
index 00000000..9235f19c
--- /dev/null
+++ b/3rdparty/pybind11/tests/object.h
@@ -0,0 +1,175 @@
+#if !defined(__OBJECT_H)
+#define __OBJECT_H
+
+#include <atomic>
+#include "constructor_stats.h"
+
+/// Reference counted object base class
+class Object {
+public:
+ /// Default constructor
+ Object() { print_default_created(this); }
+
+ /// Copy constructor
+ Object(const Object &) : m_refCount(0) { print_copy_created(this); }
+
+ /// Return the current reference count
+ int getRefCount() const { return m_refCount; };
+
+ /// Increase the object's reference count by one
+ void incRef() const { ++m_refCount; }
+
+ /** \brief Decrease the reference count of
+ * the object and possibly deallocate it.
+ *
+ * The object will automatically be deallocated once
+ * the reference count reaches zero.
+ */
+ void decRef(bool dealloc = true) const {
+ --m_refCount;
+ if (m_refCount == 0 && dealloc)
+ delete this;
+ else if (m_refCount < 0)
+ throw std::runtime_error("Internal error: reference count < 0!");
+ }
+
+ virtual std::string toString() const = 0;
+protected:
+ /** \brief Virtual protected deconstructor.
+ * (Will only be called by \ref ref)
+ */
+ virtual ~Object() { print_destroyed(this); }
+private:
+ mutable std::atomic<int> m_refCount { 0 };
+};
+
+// Tag class used to track constructions of ref objects. When we track constructors, below, we
+// track and print out the actual class (e.g. ref<MyObject>), and *also* add a fake tracker for
+// ref_tag. This lets us check that the total number of ref<Anything> constructors/destructors is
+// correct without having to check each individual ref<Whatever> type individually.
+class ref_tag {};
+
+/**
+ * \brief Reference counting helper
+ *
+ * The \a ref refeference template is a simple wrapper to store a
+ * pointer to an object. It takes care of increasing and decreasing
+ * the reference count of the object. When the last reference goes
+ * out of scope, the associated object will be deallocated.
+ *
+ * \ingroup libcore
+ */
+template <typename T> class ref {
+public:
+ /// Create a nullptr reference
+ ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); }
+
+ /// Construct a reference from a pointer
+ ref(T *ptr) : m_ptr(ptr) {
+ if (m_ptr) ((Object *) m_ptr)->incRef();
+
+ print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer");
+
+ }
+
+ /// Copy constructor
+ ref(const ref &r) : m_ptr(r.m_ptr) {
+ if (m_ptr)
+ ((Object *) m_ptr)->incRef();
+
+ print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
+ }
+
+ /// Move constructor
+ ref(ref &&r) : m_ptr(r.m_ptr) {
+ r.m_ptr = nullptr;
+
+ print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
+ }
+
+ /// Destroy this reference
+ ~ref() {
+ if (m_ptr)
+ ((Object *) m_ptr)->decRef();
+
+ print_destroyed(this); track_destroyed((ref_tag*) this);
+ }
+
+ /// Move another reference into the current one
+ ref& operator=(ref&& r) {
+ print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this);
+
+ if (*this == r)
+ return *this;
+ if (m_ptr)
+ ((Object *) m_ptr)->decRef();
+ m_ptr = r.m_ptr;
+ r.m_ptr = nullptr;
+ return *this;
+ }
+
+ /// Overwrite this reference with another reference
+ ref& operator=(const ref& r) {
+ print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this);
+
+ if (m_ptr == r.m_ptr)
+ return *this;
+ if (m_ptr)
+ ((Object *) m_ptr)->decRef();
+ m_ptr = r.m_ptr;
+ if (m_ptr)
+ ((Object *) m_ptr)->incRef();
+ return *this;
+ }
+
+ /// Overwrite this reference with a pointer to another object
+ ref& operator=(T *ptr) {
+ print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer");
+
+ if (m_ptr == ptr)
+ return *this;
+ if (m_ptr)
+ ((Object *) m_ptr)->decRef();
+ m_ptr = ptr;
+ if (m_ptr)
+ ((Object *) m_ptr)->incRef();
+ return *this;
+ }
+
+ /// Compare this reference with another reference
+ bool operator==(const ref &r) const { return m_ptr == r.m_ptr; }
+
+ /// Compare this reference with another reference
+ bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
+
+ /// Compare this reference with a pointer
+ bool operator==(const T* ptr) const { return m_ptr == ptr; }
+
+ /// Compare this reference with a pointer
+ bool operator!=(const T* ptr) const { return m_ptr != ptr; }
+
+ /// Access the object referenced by this reference
+ T* operator->() { return m_ptr; }
+
+ /// Access the object referenced by this reference
+ const T* operator->() const { return m_ptr; }
+
+ /// Return a C++ reference to the referenced object
+ T& operator*() { return *m_ptr; }
+
+ /// Return a const C++ reference to the referenced object
+ const T& operator*() const { return *m_ptr; }
+
+ /// Return a pointer to the referenced object
+ operator T* () { return m_ptr; }
+
+ /// Return a const pointer to the referenced object
+ T* get_ptr() { return m_ptr; }
+
+ /// Return a pointer to the referenced object
+ const T* get_ptr() const { return m_ptr; }
+private:
+ T *m_ptr;
+};
+
+#endif /* __OBJECT_H */
diff --git a/3rdparty/pybind11/tests/pybind11_cross_module_tests.cpp b/3rdparty/pybind11/tests/pybind11_cross_module_tests.cpp
new file mode 100644
index 00000000..f705e310
--- /dev/null
+++ b/3rdparty/pybind11/tests/pybind11_cross_module_tests.cpp
@@ -0,0 +1,123 @@
+/*
+ tests/pybind11_cross_module_tests.cpp -- contains tests that require multiple modules
+
+ Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "local_bindings.h"
+#include <pybind11/stl_bind.h>
+#include <numeric>
+
+PYBIND11_MODULE(pybind11_cross_module_tests, m) {
+ m.doc() = "pybind11 cross-module test module";
+
+ // test_local_bindings.py tests:
+ //
+ // Definitions here are tested by importing both this module and the
+ // relevant pybind11_tests submodule from a test_whatever.py
+
+ // test_load_external
+ bind_local<ExternalType1>(m, "ExternalType1", py::module_local());
+ bind_local<ExternalType2>(m, "ExternalType2", py::module_local());
+
+ // test_exceptions.py
+ m.def("raise_runtime_error", []() { PyErr_SetString(PyExc_RuntimeError, "My runtime error"); throw py::error_already_set(); });
+ m.def("raise_value_error", []() { PyErr_SetString(PyExc_ValueError, "My value error"); throw py::error_already_set(); });
+ m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); });
+ m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); });
+ m.def("throw_stop_iteration", []() { throw py::stop_iteration(); });
+
+ // test_local_bindings.py
+ // Local to both:
+ bind_local<LocalType, 1>(m, "LocalType", py::module_local())
+ .def("get2", [](LocalType &t) { return t.i + 2; })
+ ;
+
+ // Can only be called with our python type:
+ m.def("local_value", [](LocalType &l) { return l.i; });
+
+ // test_nonlocal_failure
+ // This registration will fail (global registration when LocalFail is already registered
+ // globally in the main test module):
+ m.def("register_nonlocal", [m]() {
+ bind_local<NonLocalType, 0>(m, "NonLocalType");
+ });
+
+ // test_stl_bind_local
+ // stl_bind.h binders defaults to py::module_local if the types are local or converting:
+ py::bind_vector<LocalVec>(m, "LocalVec");
+ py::bind_map<LocalMap>(m, "LocalMap");
+
+ // test_stl_bind_global
+ // and global if the type (or one of the types, for the map) is global (so these will fail,
+ // assuming pybind11_tests is already loaded):
+ m.def("register_nonlocal_vec", [m]() {
+ py::bind_vector<NonLocalVec>(m, "NonLocalVec");
+ });
+ m.def("register_nonlocal_map", [m]() {
+ py::bind_map<NonLocalMap>(m, "NonLocalMap");
+ });
+ // The default can, however, be overridden to global using `py::module_local()` or
+ // `py::module_local(false)`.
+ // Explicitly made local:
+ py::bind_vector<NonLocalVec2>(m, "NonLocalVec2", py::module_local());
+ // Explicitly made global (and so will fail to bind):
+ m.def("register_nonlocal_map2", [m]() {
+ py::bind_map<NonLocalMap2>(m, "NonLocalMap2", py::module_local(false));
+ });
+
+ // test_mixed_local_global
+ // We try this both with the global type registered first and vice versa (the order shouldn't
+ // matter).
+ m.def("register_mixed_global_local", [m]() {
+ bind_local<MixedGlobalLocal, 200>(m, "MixedGlobalLocal", py::module_local());
+ });
+ m.def("register_mixed_local_global", [m]() {
+ bind_local<MixedLocalGlobal, 2000>(m, "MixedLocalGlobal", py::module_local(false));
+ });
+ m.def("get_mixed_gl", [](int i) { return MixedGlobalLocal(i); });
+ m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });
+
+ // test_internal_locals_differ
+ m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); });
+
+ // test_stl_caster_vs_stl_bind
+ py::bind_vector<std::vector<int>>(m, "VectorInt");
+
+ m.def("load_vector_via_binding", [](std::vector<int> &v) {
+ return std::accumulate(v.begin(), v.end(), 0);
+ });
+
+ // test_cross_module_calls
+ m.def("return_self", [](LocalVec *v) { return v; });
+ m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); });
+
+ class Dog : public pets::Pet { public: Dog(std::string name) : Pet(name) {}; };
+ py::class_<pets::Pet>(m, "Pet", py::module_local())
+ .def("name", &pets::Pet::name);
+ // Binding for local extending class:
+ py::class_<Dog, pets::Pet>(m, "Dog")
+ .def(py::init<std::string>());
+ m.def("pet_name", [](pets::Pet &p) { return p.name(); });
+
+ py::class_<MixGL>(m, "MixGL", py::module_local()).def(py::init<int>());
+ m.def("get_gl_value", [](MixGL &o) { return o.i + 100; });
+
+ py::class_<MixGL2>(m, "MixGL2", py::module_local()).def(py::init<int>());
+
+ // test_vector_bool
+ // We can't test both stl.h and stl_bind.h conversions of `std::vector<bool>` within
+ // the same module (it would be an ODR violation). Therefore `bind_vector` of `bool`
+ // is defined here and tested in `test_stl_binders.py`.
+ py::bind_vector<std::vector<bool>>(m, "VectorBool");
+
+ // test_missing_header_message
+ // The main module already includes stl.h, but we need to test the error message
+ // which appears when this header is missing.
+ m.def("missing_header_arg", [](std::vector<float>) { });
+ m.def("missing_header_return", []() { return std::vector<float>(); });
+}
diff --git a/3rdparty/pybind11/tests/pybind11_tests.cpp b/3rdparty/pybind11/tests/pybind11_tests.cpp
new file mode 100644
index 00000000..bc7d2c3e
--- /dev/null
+++ b/3rdparty/pybind11/tests/pybind11_tests.cpp
@@ -0,0 +1,93 @@
+/*
+ tests/pybind11_tests.cpp -- pybind example plugin
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+
+#include <functional>
+#include <list>
+
+/*
+For testing purposes, we define a static global variable here in a function that each individual
+test .cpp calls with its initialization lambda. It's convenient here because we can just not
+compile some test files to disable/ignore some of the test code.
+
+It is NOT recommended as a way to use pybind11 in practice, however: the initialization order will
+be essentially random, which is okay for our test scripts (there are no dependencies between the
+individual pybind11 test .cpp files), but most likely not what you want when using pybind11
+productively.
+
+Instead, see the "How can I reduce the build time?" question in the "Frequently asked questions"
+section of the documentation for good practice on splitting binding code over multiple files.
+*/
+std::list<std::function<void(py::module &)>> &initializers() {
+ static std::list<std::function<void(py::module &)>> inits;
+ return inits;
+}
+
+test_initializer::test_initializer(Initializer init) {
+ initializers().push_back(init);
+}
+
+test_initializer::test_initializer(const char *submodule_name, Initializer init) {
+ initializers().push_back([=](py::module &parent) {
+ auto m = parent.def_submodule(submodule_name);
+ init(m);
+ });
+}
+
+void bind_ConstructorStats(py::module &m) {
+ py::class_<ConstructorStats>(m, "ConstructorStats")
+ .def("alive", &ConstructorStats::alive)
+ .def("values", &ConstructorStats::values)
+ .def_readwrite("default_constructions", &ConstructorStats::default_constructions)
+ .def_readwrite("copy_assignments", &ConstructorStats::copy_assignments)
+ .def_readwrite("move_assignments", &ConstructorStats::move_assignments)
+ .def_readwrite("copy_constructions", &ConstructorStats::copy_constructions)
+ .def_readwrite("move_constructions", &ConstructorStats::move_constructions)
+ .def_static("get", (ConstructorStats &(*)(py::object)) &ConstructorStats::get, py::return_value_policy::reference_internal)
+
+ // Not exactly ConstructorStats, but related: expose the internal pybind number of registered instances
+ // to allow instance cleanup checks (invokes a GC first)
+ .def_static("detail_reg_inst", []() {
+ ConstructorStats::gc();
+ return py::detail::get_internals().registered_instances.size();
+ })
+ ;
+}
+
+PYBIND11_MODULE(pybind11_tests, m) {
+ m.doc() = "pybind11 test module";
+
+ bind_ConstructorStats(m);
+
+#if !defined(NDEBUG)
+ m.attr("debug_enabled") = true;
+#else
+ m.attr("debug_enabled") = false;
+#endif
+
+ py::class_<UserType>(m, "UserType", "A `py::class_` type for testing")
+ .def(py::init<>())
+ .def(py::init<int>())
+ .def("get_value", &UserType::value, "Get value using a method")
+ .def("set_value", &UserType::set, "Set value using a method")
+ .def_property("value", &UserType::value, &UserType::set, "Get/set value using a property")
+ .def("__repr__", [](const UserType& u) { return "UserType({})"_s.format(u.value()); });
+
+ py::class_<IncType, UserType>(m, "IncType")
+ .def(py::init<>())
+ .def(py::init<int>())
+ .def("__repr__", [](const IncType& u) { return "IncType({})"_s.format(u.value()); });
+
+ for (const auto &initializer : initializers())
+ initializer(m);
+
+ if (!py::hasattr(m, "have_eigen")) m.attr("have_eigen") = false;
+}
diff --git a/3rdparty/pybind11/tests/pybind11_tests.h b/3rdparty/pybind11/tests/pybind11_tests.h
new file mode 100644
index 00000000..90963a5d
--- /dev/null
+++ b/3rdparty/pybind11/tests/pybind11_tests.h
@@ -0,0 +1,65 @@
+#pragma once
+#include <pybind11/pybind11.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1910
+// We get some really long type names here which causes MSVC 2015 to emit warnings
+# pragma warning(disable: 4503) // warning C4503: decorated name length exceeded, name was truncated
+#endif
+
+namespace py = pybind11;
+using namespace pybind11::literals;
+
+class test_initializer {
+ using Initializer = void (*)(py::module &);
+
+public:
+ test_initializer(Initializer init);
+ test_initializer(const char *submodule_name, Initializer init);
+};
+
+#define TEST_SUBMODULE(name, variable) \
+ void test_submodule_##name(py::module &); \
+ test_initializer name(#name, test_submodule_##name); \
+ void test_submodule_##name(py::module &variable)
+
+
+/// Dummy type which is not exported anywhere -- something to trigger a conversion error
+struct UnregisteredType { };
+
+/// A user-defined type which is exported and can be used by any test
+class UserType {
+public:
+ UserType() = default;
+ UserType(int i) : i(i) { }
+
+ int value() const { return i; }
+ void set(int set) { i = set; }
+
+private:
+ int i = -1;
+};
+
+/// Like UserType, but increments `value` on copy for quick reference vs. copy tests
+class IncType : public UserType {
+public:
+ using UserType::UserType;
+ IncType() = default;
+ IncType(const IncType &other) : IncType(other.value() + 1) { }
+ IncType(IncType &&) = delete;
+ IncType &operator=(const IncType &) = delete;
+ IncType &operator=(IncType &&) = delete;
+};
+
+/// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast context.
+/// Used to test recursive casters (e.g. std::tuple, stl containers).
+struct RValueCaster {};
+NAMESPACE_BEGIN(pybind11)
+NAMESPACE_BEGIN(detail)
+template<> class type_caster<RValueCaster> {
+public:
+ PYBIND11_TYPE_CASTER(RValueCaster, _("RValueCaster"));
+ static handle cast(RValueCaster &&, return_value_policy, handle) { return py::str("rvalue").release(); }
+ static handle cast(const RValueCaster &, return_value_policy, handle) { return py::str("lvalue").release(); }
+};
+NAMESPACE_END(detail)
+NAMESPACE_END(pybind11)
diff --git a/3rdparty/pybind11/tests/pytest.ini b/3rdparty/pybind11/tests/pytest.ini
new file mode 100644
index 00000000..f209964a
--- /dev/null
+++ b/3rdparty/pybind11/tests/pytest.ini
@@ -0,0 +1,16 @@
+[pytest]
+minversion = 3.0
+norecursedirs = test_cmake_build test_embed
+addopts =
+ # show summary of skipped tests
+ -rs
+ # capture only Python print and C++ py::print, but not C output (low-level Python errors)
+ --capture=sys
+filterwarnings =
+ # make warnings into errors but ignore certain third-party extension issues
+ error
+ # importing scipy submodules on some version of Python
+ ignore::ImportWarning
+ # bogus numpy ABI warning (see numpy/#432)
+ ignore:.*numpy.dtype size changed.*:RuntimeWarning
+ ignore:.*numpy.ufunc size changed.*:RuntimeWarning
diff --git a/3rdparty/pybind11/tests/test_async.cpp b/3rdparty/pybind11/tests/test_async.cpp
new file mode 100644
index 00000000..f0ad0d53
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_async.cpp
@@ -0,0 +1,26 @@
+/*
+ tests/test_async.cpp -- __await__ support
+
+ Copyright (c) 2019 Google Inc.
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+TEST_SUBMODULE(async_module, m) {
+ struct DoesNotSupportAsync {};
+ py::class_<DoesNotSupportAsync>(m, "DoesNotSupportAsync")
+ .def(py::init<>());
+ struct SupportsAsync {};
+ py::class_<SupportsAsync>(m, "SupportsAsync")
+ .def(py::init<>())
+ .def("__await__", [](const SupportsAsync& self) -> py::object {
+ static_cast<void>(self);
+ py::object loop = py::module::import("asyncio.events").attr("get_event_loop")();
+ py::object f = loop.attr("create_future")();
+ f.attr("set_result")(5);
+ return f.attr("__await__")();
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_async.py b/3rdparty/pybind11/tests/test_async.py
new file mode 100644
index 00000000..e1c959d6
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_async.py
@@ -0,0 +1,23 @@
+import asyncio
+import pytest
+from pybind11_tests import async_module as m
+
+
+@pytest.fixture
+def event_loop():
+ loop = asyncio.new_event_loop()
+ yield loop
+ loop.close()
+
+
+async def get_await_result(x):
+ return await x
+
+
+def test_await(event_loop):
+ assert 5 == event_loop.run_until_complete(get_await_result(m.SupportsAsync()))
+
+
+def test_await_missing(event_loop):
+ with pytest.raises(TypeError):
+ event_loop.run_until_complete(get_await_result(m.DoesNotSupportAsync()))
diff --git a/3rdparty/pybind11/tests/test_buffers.cpp b/3rdparty/pybind11/tests/test_buffers.cpp
new file mode 100644
index 00000000..1bc67ff7
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_buffers.cpp
@@ -0,0 +1,195 @@
+/*
+ tests/test_buffers.cpp -- supporting Pythons' buffer protocol
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+
+TEST_SUBMODULE(buffers, m) {
+ // test_from_python / test_to_python:
+ class Matrix {
+ public:
+ Matrix(ssize_t rows, ssize_t cols) : m_rows(rows), m_cols(cols) {
+ print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
+ m_data = new float[(size_t) (rows*cols)];
+ memset(m_data, 0, sizeof(float) * (size_t) (rows * cols));
+ }
+
+ Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
+ print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
+ m_data = new float[(size_t) (m_rows * m_cols)];
+ memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
+ }
+
+ Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
+ print_move_created(this);
+ s.m_rows = 0;
+ s.m_cols = 0;
+ s.m_data = nullptr;
+ }
+
+ ~Matrix() {
+ print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
+ delete[] m_data;
+ }
+
+ Matrix &operator=(const Matrix &s) {
+ print_copy_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
+ delete[] m_data;
+ m_rows = s.m_rows;
+ m_cols = s.m_cols;
+ m_data = new float[(size_t) (m_rows * m_cols)];
+ memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
+ return *this;
+ }
+
+ Matrix &operator=(Matrix &&s) {
+ print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
+ if (&s != this) {
+ delete[] m_data;
+ m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data;
+ s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr;
+ }
+ return *this;
+ }
+
+ float operator()(ssize_t i, ssize_t j) const {
+ return m_data[(size_t) (i*m_cols + j)];
+ }
+
+ float &operator()(ssize_t i, ssize_t j) {
+ return m_data[(size_t) (i*m_cols + j)];
+ }
+
+ float *data() { return m_data; }
+
+ ssize_t rows() const { return m_rows; }
+ ssize_t cols() const { return m_cols; }
+ private:
+ ssize_t m_rows;
+ ssize_t m_cols;
+ float *m_data;
+ };
+ py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
+ .def(py::init<ssize_t, ssize_t>())
+ /// Construct from a buffer
+ .def(py::init([](py::buffer const b) {
+ py::buffer_info info = b.request();
+ if (info.format != py::format_descriptor<float>::format() || info.ndim != 2)
+ throw std::runtime_error("Incompatible buffer format!");
+
+ auto v = new Matrix(info.shape[0], info.shape[1]);
+ memcpy(v->data(), info.ptr, sizeof(float) * (size_t) (v->rows() * v->cols()));
+ return v;
+ }))
+
+ .def("rows", &Matrix::rows)
+ .def("cols", &Matrix::cols)
+
+ /// Bare bones interface
+ .def("__getitem__", [](const Matrix &m, std::pair<ssize_t, ssize_t> i) {
+ if (i.first >= m.rows() || i.second >= m.cols())
+ throw py::index_error();
+ return m(i.first, i.second);
+ })
+ .def("__setitem__", [](Matrix &m, std::pair<ssize_t, ssize_t> i, float v) {
+ if (i.first >= m.rows() || i.second >= m.cols())
+ throw py::index_error();
+ m(i.first, i.second) = v;
+ })
+ /// Provide buffer access
+ .def_buffer([](Matrix &m) -> py::buffer_info {
+ return py::buffer_info(
+ m.data(), /* Pointer to buffer */
+ { m.rows(), m.cols() }, /* Buffer dimensions */
+ { sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */
+ sizeof(float) }
+ );
+ })
+ ;
+
+
+ // test_inherited_protocol
+ class SquareMatrix : public Matrix {
+ public:
+ SquareMatrix(ssize_t n) : Matrix(n, n) { }
+ };
+ // Derived classes inherit the buffer protocol and the buffer access function
+ py::class_<SquareMatrix, Matrix>(m, "SquareMatrix")
+ .def(py::init<ssize_t>());
+
+
+ // test_pointer_to_member_fn
+ // Tests that passing a pointer to member to the base class works in
+ // the derived class.
+ struct Buffer {
+ int32_t value = 0;
+
+ py::buffer_info get_buffer_info() {
+ return py::buffer_info(&value, sizeof(value),
+ py::format_descriptor<int32_t>::format(), 1);
+ }
+ };
+ py::class_<Buffer>(m, "Buffer", py::buffer_protocol())
+ .def(py::init<>())
+ .def_readwrite("value", &Buffer::value)
+ .def_buffer(&Buffer::get_buffer_info);
+
+
+ class ConstBuffer {
+ std::unique_ptr<int32_t> value;
+
+ public:
+ int32_t get_value() const { return *value; }
+ void set_value(int32_t v) { *value = v; }
+
+ py::buffer_info get_buffer_info() const {
+ return py::buffer_info(value.get(), sizeof(*value),
+ py::format_descriptor<int32_t>::format(), 1);
+ }
+
+ ConstBuffer() : value(new int32_t{0}) { };
+ };
+ py::class_<ConstBuffer>(m, "ConstBuffer", py::buffer_protocol())
+ .def(py::init<>())
+ .def_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value)
+ .def_buffer(&ConstBuffer::get_buffer_info);
+
+ struct DerivedBuffer : public Buffer { };
+ py::class_<DerivedBuffer>(m, "DerivedBuffer", py::buffer_protocol())
+ .def(py::init<>())
+ .def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value)
+ .def_buffer(&DerivedBuffer::get_buffer_info);
+
+ struct BufferReadOnly {
+ const uint8_t value = 0;
+ BufferReadOnly(uint8_t value): value(value) {}
+
+ py::buffer_info get_buffer_info() {
+ return py::buffer_info(&value, 1);
+ }
+ };
+ py::class_<BufferReadOnly>(m, "BufferReadOnly", py::buffer_protocol())
+ .def(py::init<uint8_t>())
+ .def_buffer(&BufferReadOnly::get_buffer_info);
+
+ struct BufferReadOnlySelect {
+ uint8_t value = 0;
+ bool readonly = false;
+
+ py::buffer_info get_buffer_info() {
+ return py::buffer_info(&value, 1, readonly);
+ }
+ };
+ py::class_<BufferReadOnlySelect>(m, "BufferReadOnlySelect", py::buffer_protocol())
+ .def(py::init<>())
+ .def_readwrite("value", &BufferReadOnlySelect::value)
+ .def_readwrite("readonly", &BufferReadOnlySelect::readonly)
+ .def_buffer(&BufferReadOnlySelect::get_buffer_info);
+
+}
diff --git a/3rdparty/pybind11/tests/test_buffers.py b/3rdparty/pybind11/tests/test_buffers.py
new file mode 100644
index 00000000..bf7aaed7
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_buffers.py
@@ -0,0 +1,118 @@
+import io
+import struct
+import sys
+
+import pytest
+
+from pybind11_tests import buffers as m
+from pybind11_tests import ConstructorStats
+
+PY3 = sys.version_info[0] >= 3
+
+pytestmark = pytest.requires_numpy
+
+with pytest.suppress(ImportError):
+ import numpy as np
+
+
+def test_from_python():
+ with pytest.raises(RuntimeError) as excinfo:
+ m.Matrix(np.array([1, 2, 3])) # trying to assign a 1D array
+ assert str(excinfo.value) == "Incompatible buffer format!"
+
+ m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32)
+ m4 = m.Matrix(m3)
+
+ for i in range(m4.rows()):
+ for j in range(m4.cols()):
+ assert m3[i, j] == m4[i, j]
+
+ cstats = ConstructorStats.get(m.Matrix)
+ assert cstats.alive() == 1
+ del m3, m4
+ assert cstats.alive() == 0
+ assert cstats.values() == ["2x3 matrix"]
+ assert cstats.copy_constructions == 0
+ # assert cstats.move_constructions >= 0 # Don't invoke any
+ assert cstats.copy_assignments == 0
+ assert cstats.move_assignments == 0
+
+
+# PyPy: Memory leak in the "np.array(m, copy=False)" call
+# https://bitbucket.org/pypy/pypy/issues/2444
+@pytest.unsupported_on_pypy
+def test_to_python():
+ mat = m.Matrix(5, 4)
+ assert memoryview(mat).shape == (5, 4)
+
+ assert mat[2, 3] == 0
+ mat[2, 3] = 4.0
+ mat[3, 2] = 7.0
+ assert mat[2, 3] == 4
+ assert mat[3, 2] == 7
+ assert struct.unpack_from('f', mat, (3 * 4 + 2) * 4) == (7, )
+ assert struct.unpack_from('f', mat, (2 * 4 + 3) * 4) == (4, )
+
+ mat2 = np.array(mat, copy=False)
+ assert mat2.shape == (5, 4)
+ assert abs(mat2).sum() == 11
+ assert mat2[2, 3] == 4 and mat2[3, 2] == 7
+ mat2[2, 3] = 5
+ assert mat2[2, 3] == 5
+
+ cstats = ConstructorStats.get(m.Matrix)
+ assert cstats.alive() == 1
+ del mat
+ pytest.gc_collect()
+ assert cstats.alive() == 1
+ del mat2 # holds a mat reference
+ pytest.gc_collect()
+ assert cstats.alive() == 0
+ assert cstats.values() == ["5x4 matrix"]
+ assert cstats.copy_constructions == 0
+ # assert cstats.move_constructions >= 0 # Don't invoke any
+ assert cstats.copy_assignments == 0
+ assert cstats.move_assignments == 0
+
+
+@pytest.unsupported_on_pypy
+def test_inherited_protocol():
+ """SquareMatrix is derived from Matrix and inherits the buffer protocol"""
+
+ matrix = m.SquareMatrix(5)
+ assert memoryview(matrix).shape == (5, 5)
+ assert np.asarray(matrix).shape == (5, 5)
+
+
+@pytest.unsupported_on_pypy
+def test_pointer_to_member_fn():
+ for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]:
+ buf = cls()
+ buf.value = 0x12345678
+ value = struct.unpack('i', bytearray(buf))[0]
+ assert value == 0x12345678
+
+
+@pytest.unsupported_on_pypy
+def test_readonly_buffer():
+ buf = m.BufferReadOnly(0x64)
+ view = memoryview(buf)
+ assert view[0] == 0x64 if PY3 else b'd'
+ assert view.readonly
+
+
+@pytest.unsupported_on_pypy
+def test_selective_readonly_buffer():
+ buf = m.BufferReadOnlySelect()
+
+ memoryview(buf)[0] = 0x64 if PY3 else b'd'
+ assert buf.value == 0x64
+
+ io.BytesIO(b'A').readinto(buf)
+ assert buf.value == ord(b'A')
+
+ buf.readonly = True
+ with pytest.raises(TypeError):
+ memoryview(buf)[0] = 0 if PY3 else b'\0'
+ with pytest.raises(TypeError):
+ io.BytesIO(b'1').readinto(buf)
diff --git a/3rdparty/pybind11/tests/test_builtin_casters.cpp b/3rdparty/pybind11/tests/test_builtin_casters.cpp
new file mode 100644
index 00000000..acb24469
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_builtin_casters.cpp
@@ -0,0 +1,188 @@
+/*
+ tests/test_builtin_casters.cpp -- Casters available without any additional headers
+
+ Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include <pybind11/complex.h>
+
+#if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
+#endif
+
+TEST_SUBMODULE(builtin_casters, m) {
+ // test_simple_string
+ m.def("string_roundtrip", [](const char *s) { return s; });
+
+ // test_unicode_conversion
+ // Some test characters in utf16 and utf32 encodings. The last one (the 𝐀) contains a null byte
+ char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/, mathbfA32 = 0x1d400 /*𝐀*/;
+ char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82, mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00;
+ std::wstring wstr;
+ wstr.push_back(0x61); // a
+ wstr.push_back(0x2e18); // ⸘
+ if (sizeof(wchar_t) == 2) { wstr.push_back(mathbfA16_1); wstr.push_back(mathbfA16_2); } // 𝐀, utf16
+ else { wstr.push_back((wchar_t) mathbfA32); } // 𝐀, utf32
+ wstr.push_back(0x7a); // z
+
+ m.def("good_utf8_string", []() { return std::string((const char*)u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀
+ m.def("good_utf16_string", [=]() { return std::u16string({ b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16 }); }); // b‽🎂𝐀z
+ m.def("good_utf32_string", [=]() { return std::u32string({ a32, mathbfA32, cake32, ib32, z32 }); }); // a𝐀🎂‽z
+ m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z
+ m.def("bad_utf8_string", []() { return std::string("abc\xd0" "def"); });
+ m.def("bad_utf16_string", [=]() { return std::u16string({ b16, char16_t(0xd800), z16 }); });
+ // Under Python 2.7, invalid unicode UTF-32 characters don't appear to trigger UnicodeDecodeError
+ if (PY_MAJOR_VERSION >= 3)
+ m.def("bad_utf32_string", [=]() { return std::u32string({ a32, char32_t(0xd800), z32 }); });
+ if (PY_MAJOR_VERSION >= 3 || sizeof(wchar_t) == 2)
+ m.def("bad_wchar_string", [=]() { return std::wstring({ wchar_t(0x61), wchar_t(0xd800) }); });
+ m.def("u8_Z", []() -> char { return 'Z'; });
+ m.def("u8_eacute", []() -> char { return '\xe9'; });
+ m.def("u16_ibang", [=]() -> char16_t { return ib16; });
+ m.def("u32_mathbfA", [=]() -> char32_t { return mathbfA32; });
+ m.def("wchar_heart", []() -> wchar_t { return 0x2665; });
+
+ // test_single_char_arguments
+ m.attr("wchar_size") = py::cast(sizeof(wchar_t));
+ m.def("ord_char", [](char c) -> int { return static_cast<unsigned char>(c); });
+ m.def("ord_char_lv", [](char &c) -> int { return static_cast<unsigned char>(c); });
+ m.def("ord_char16", [](char16_t c) -> uint16_t { return c; });
+ m.def("ord_char16_lv", [](char16_t &c) -> uint16_t { return c; });
+ m.def("ord_char32", [](char32_t c) -> uint32_t { return c; });
+ m.def("ord_wchar", [](wchar_t c) -> int { return c; });
+
+ // test_bytes_to_string
+ m.def("strlen", [](char *s) { return strlen(s); });
+ m.def("string_length", [](std::string s) { return s.length(); });
+
+#ifdef PYBIND11_HAS_U8STRING
+ m.attr("has_u8string") = true;
+ m.def("good_utf8_u8string", []() { return std::u8string(u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀
+ m.def("bad_utf8_u8string", []() { return std::u8string((const char8_t*)"abc\xd0" "def"); });
+
+ m.def("u8_char8_Z", []() -> char8_t { return u8'Z'; });
+
+ // test_single_char_arguments
+ m.def("ord_char8", [](char8_t c) -> int { return static_cast<unsigned char>(c); });
+ m.def("ord_char8_lv", [](char8_t &c) -> int { return static_cast<unsigned char>(c); });
+#endif
+
+ // test_string_view
+#ifdef PYBIND11_HAS_STRING_VIEW
+ m.attr("has_string_view") = true;
+ m.def("string_view_print", [](std::string_view s) { py::print(s, s.size()); });
+ m.def("string_view16_print", [](std::u16string_view s) { py::print(s, s.size()); });
+ m.def("string_view32_print", [](std::u32string_view s) { py::print(s, s.size()); });
+ m.def("string_view_chars", [](std::string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; });
+ m.def("string_view16_chars", [](std::u16string_view s) { py::list l; for (auto c : s) l.append((int) c); return l; });
+ m.def("string_view32_chars", [](std::u32string_view s) { py::list l; for (auto c : s) l.append((int) c); return l; });
+ m.def("string_view_return", []() { return std::string_view((const char*)u8"utf8 secret \U0001f382"); });
+ m.def("string_view16_return", []() { return std::u16string_view(u"utf16 secret \U0001f382"); });
+ m.def("string_view32_return", []() { return std::u32string_view(U"utf32 secret \U0001f382"); });
+
+# ifdef PYBIND11_HAS_U8STRING
+ m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); });
+ m.def("string_view8_chars", [](std::u8string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; });
+ m.def("string_view8_return", []() { return std::u8string_view(u8"utf8 secret \U0001f382"); });
+# endif
+#endif
+
+ // test_integer_casting
+ m.def("i32_str", [](std::int32_t v) { return std::to_string(v); });
+ m.def("u32_str", [](std::uint32_t v) { return std::to_string(v); });
+ m.def("i64_str", [](std::int64_t v) { return std::to_string(v); });
+ m.def("u64_str", [](std::uint64_t v) { return std::to_string(v); });
+
+ // test_tuple
+ m.def("pair_passthrough", [](std::pair<bool, std::string> input) {
+ return std::make_pair(input.second, input.first);
+ }, "Return a pair in reversed order");
+ m.def("tuple_passthrough", [](std::tuple<bool, std::string, int> input) {
+ return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input));
+ }, "Return a triple in reversed order");
+ m.def("empty_tuple", []() { return std::tuple<>(); });
+ static std::pair<RValueCaster, RValueCaster> lvpair;
+ static std::tuple<RValueCaster, RValueCaster, RValueCaster> lvtuple;
+ static std::pair<RValueCaster, std::tuple<RValueCaster, std::pair<RValueCaster, RValueCaster>>> lvnested;
+ m.def("rvalue_pair", []() { return std::make_pair(RValueCaster{}, RValueCaster{}); });
+ m.def("lvalue_pair", []() -> const decltype(lvpair) & { return lvpair; });
+ m.def("rvalue_tuple", []() { return std::make_tuple(RValueCaster{}, RValueCaster{}, RValueCaster{}); });
+ m.def("lvalue_tuple", []() -> const decltype(lvtuple) & { return lvtuple; });
+ m.def("rvalue_nested", []() {
+ return std::make_pair(RValueCaster{}, std::make_tuple(RValueCaster{}, std::make_pair(RValueCaster{}, RValueCaster{}))); });
+ m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; });
+
+ // test_builtins_cast_return_none
+ m.def("return_none_string", []() -> std::string * { return nullptr; });
+ m.def("return_none_char", []() -> const char * { return nullptr; });
+ m.def("return_none_bool", []() -> bool * { return nullptr; });
+ m.def("return_none_int", []() -> int * { return nullptr; });
+ m.def("return_none_float", []() -> float * { return nullptr; });
+
+ // test_none_deferred
+ m.def("defer_none_cstring", [](char *) { return false; });
+ m.def("defer_none_cstring", [](py::none) { return true; });
+ m.def("defer_none_custom", [](UserType *) { return false; });
+ m.def("defer_none_custom", [](py::none) { return true; });
+ m.def("nodefer_none_void", [](void *) { return true; });
+ m.def("nodefer_none_void", [](py::none) { return false; });
+
+ // test_void_caster
+ m.def("load_nullptr_t", [](std::nullptr_t) {}); // not useful, but it should still compile
+ m.def("cast_nullptr_t", []() { return std::nullptr_t{}; });
+
+ // test_bool_caster
+ m.def("bool_passthrough", [](bool arg) { return arg; });
+ m.def("bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg().noconvert());
+
+ // test_reference_wrapper
+ m.def("refwrap_builtin", [](std::reference_wrapper<int> p) { return 10 * p.get(); });
+ m.def("refwrap_usertype", [](std::reference_wrapper<UserType> p) { return p.get().value(); });
+ // Not currently supported (std::pair caster has return-by-value cast operator);
+ // triggers static_assert failure.
+ //m.def("refwrap_pair", [](std::reference_wrapper<std::pair<int, int>>) { });
+
+ m.def("refwrap_list", [](bool copy) {
+ static IncType x1(1), x2(2);
+ py::list l;
+ for (auto &f : {std::ref(x1), std::ref(x2)}) {
+ l.append(py::cast(f, copy ? py::return_value_policy::copy
+ : py::return_value_policy::reference));
+ }
+ return l;
+ }, "copy"_a);
+
+ m.def("refwrap_iiw", [](const IncType &w) { return w.value(); });
+ m.def("refwrap_call_iiw", [](IncType &w, py::function f) {
+ py::list l;
+ l.append(f(std::ref(w)));
+ l.append(f(std::cref(w)));
+ IncType x(w.value());
+ l.append(f(std::ref(x)));
+ IncType y(w.value());
+ auto r3 = std::ref(y);
+ l.append(f(r3));
+ return l;
+ });
+
+ // test_complex
+ m.def("complex_cast", [](float x) { return "{}"_s.format(x); });
+ m.def("complex_cast", [](std::complex<float> x) { return "({}, {})"_s.format(x.real(), x.imag()); });
+
+ // test int vs. long (Python 2)
+ m.def("int_cast", []() {return (int) 42;});
+ m.def("long_cast", []() {return (long) 42;});
+ m.def("longlong_cast", []() {return ULLONG_MAX;});
+
+ /// test void* cast operator
+ m.def("test_void_caster", []() -> bool {
+ void *v = (void *) 0xabcd;
+ py::object o = py::cast(v);
+ return py::cast<void *>(o) == v;
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_builtin_casters.py b/3rdparty/pybind11/tests/test_builtin_casters.py
new file mode 100644
index 00000000..91422588
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_builtin_casters.py
@@ -0,0 +1,385 @@
+# Python < 3 needs this: coding=utf-8
+import pytest
+
+from pybind11_tests import builtin_casters as m
+from pybind11_tests import UserType, IncType
+
+
+def test_simple_string():
+ assert m.string_roundtrip("const char *") == "const char *"
+
+
+def test_unicode_conversion():
+ """Tests unicode conversion and error reporting."""
+ assert m.good_utf8_string() == u"Say utf8‽ 🎂 𝐀"
+ assert m.good_utf16_string() == u"b‽🎂𝐀z"
+ assert m.good_utf32_string() == u"a𝐀🎂‽z"
+ assert m.good_wchar_string() == u"a⸘𝐀z"
+ if hasattr(m, "has_u8string"):
+ assert m.good_utf8_u8string() == u"Say utf8‽ 🎂 𝐀"
+
+ with pytest.raises(UnicodeDecodeError):
+ m.bad_utf8_string()
+
+ with pytest.raises(UnicodeDecodeError):
+ m.bad_utf16_string()
+
+ # These are provided only if they actually fail (they don't when 32-bit and under Python 2.7)
+ if hasattr(m, "bad_utf32_string"):
+ with pytest.raises(UnicodeDecodeError):
+ m.bad_utf32_string()
+ if hasattr(m, "bad_wchar_string"):
+ with pytest.raises(UnicodeDecodeError):
+ m.bad_wchar_string()
+ if hasattr(m, "has_u8string"):
+ with pytest.raises(UnicodeDecodeError):
+ m.bad_utf8_u8string()
+
+ assert m.u8_Z() == 'Z'
+ assert m.u8_eacute() == u'é'
+ assert m.u16_ibang() == u'‽'
+ assert m.u32_mathbfA() == u'𝐀'
+ assert m.wchar_heart() == u'♥'
+ if hasattr(m, "has_u8string"):
+ assert m.u8_char8_Z() == 'Z'
+
+
+def test_single_char_arguments():
+ """Tests failures for passing invalid inputs to char-accepting functions"""
+ def toobig_message(r):
+ return "Character code point not in range({0:#x})".format(r)
+ toolong_message = "Expected a character, but multi-character string found"
+
+ assert m.ord_char(u'a') == 0x61 # simple ASCII
+ assert m.ord_char_lv(u'b') == 0x62
+ assert m.ord_char(u'é') == 0xE9 # requires 2 bytes in utf-8, but can be stuffed in a char
+ with pytest.raises(ValueError) as excinfo:
+ assert m.ord_char(u'Ā') == 0x100 # requires 2 bytes, doesn't fit in a char
+ assert str(excinfo.value) == toobig_message(0x100)
+ with pytest.raises(ValueError) as excinfo:
+ assert m.ord_char(u'ab')
+ assert str(excinfo.value) == toolong_message
+
+ assert m.ord_char16(u'a') == 0x61
+ assert m.ord_char16(u'é') == 0xE9
+ assert m.ord_char16_lv(u'ê') == 0xEA
+ assert m.ord_char16(u'Ā') == 0x100
+ assert m.ord_char16(u'‽') == 0x203d
+ assert m.ord_char16(u'♥') == 0x2665
+ assert m.ord_char16_lv(u'♡') == 0x2661
+ with pytest.raises(ValueError) as excinfo:
+ assert m.ord_char16(u'🎂') == 0x1F382 # requires surrogate pair
+ assert str(excinfo.value) == toobig_message(0x10000)
+ with pytest.raises(ValueError) as excinfo:
+ assert m.ord_char16(u'aa')
+ assert str(excinfo.value) == toolong_message
+
+ assert m.ord_char32(u'a') == 0x61
+ assert m.ord_char32(u'é') == 0xE9
+ assert m.ord_char32(u'Ā') == 0x100
+ assert m.ord_char32(u'‽') == 0x203d
+ assert m.ord_char32(u'♥') == 0x2665
+ assert m.ord_char32(u'🎂') == 0x1F382
+ with pytest.raises(ValueError) as excinfo:
+ assert m.ord_char32(u'aa')
+ assert str(excinfo.value) == toolong_message
+
+ assert m.ord_wchar(u'a') == 0x61
+ assert m.ord_wchar(u'é') == 0xE9
+ assert m.ord_wchar(u'Ā') == 0x100
+ assert m.ord_wchar(u'‽') == 0x203d
+ assert m.ord_wchar(u'♥') == 0x2665
+ if m.wchar_size == 2:
+ with pytest.raises(ValueError) as excinfo:
+ assert m.ord_wchar(u'🎂') == 0x1F382 # requires surrogate pair
+ assert str(excinfo.value) == toobig_message(0x10000)
+ else:
+ assert m.ord_wchar(u'🎂') == 0x1F382
+ with pytest.raises(ValueError) as excinfo:
+ assert m.ord_wchar(u'aa')
+ assert str(excinfo.value) == toolong_message
+
+ if hasattr(m, "has_u8string"):
+ assert m.ord_char8(u'a') == 0x61 # simple ASCII
+ assert m.ord_char8_lv(u'b') == 0x62
+ assert m.ord_char8(u'é') == 0xE9 # requires 2 bytes in utf-8, but can be stuffed in a char
+ with pytest.raises(ValueError) as excinfo:
+ assert m.ord_char8(u'Ā') == 0x100 # requires 2 bytes, doesn't fit in a char
+ assert str(excinfo.value) == toobig_message(0x100)
+ with pytest.raises(ValueError) as excinfo:
+ assert m.ord_char8(u'ab')
+ assert str(excinfo.value) == toolong_message
+
+
+def test_bytes_to_string():
+ """Tests the ability to pass bytes to C++ string-accepting functions. Note that this is
+ one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
+ # Issue #816
+ import sys
+ byte = bytes if sys.version_info[0] < 3 else str
+
+ assert m.strlen(byte("hi")) == 2
+ assert m.string_length(byte("world")) == 5
+ assert m.string_length(byte("a\x00b")) == 3
+ assert m.strlen(byte("a\x00b")) == 1 # C-string limitation
+
+ # passing in a utf8 encoded string should work
+ assert m.string_length(u'💩'.encode("utf8")) == 4
+
+
+@pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")
+def test_string_view(capture):
+ """Tests support for C++17 string_view arguments and return values"""
+ assert m.string_view_chars("Hi") == [72, 105]
+ assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xf0, 0x9f, 0x8e, 0x82]
+ assert m.string_view16_chars("Hi 🎂") == [72, 105, 32, 0xd83c, 0xdf82]
+ assert m.string_view32_chars("Hi 🎂") == [72, 105, 32, 127874]
+ if hasattr(m, "has_u8string"):
+ assert m.string_view8_chars("Hi") == [72, 105]
+ assert m.string_view8_chars("Hi 🎂") == [72, 105, 32, 0xf0, 0x9f, 0x8e, 0x82]
+
+ assert m.string_view_return() == "utf8 secret 🎂"
+ assert m.string_view16_return() == "utf16 secret 🎂"
+ assert m.string_view32_return() == "utf32 secret 🎂"
+ if hasattr(m, "has_u8string"):
+ assert m.string_view8_return() == "utf8 secret 🎂"
+
+ with capture:
+ m.string_view_print("Hi")
+ m.string_view_print("utf8 🎂")
+ m.string_view16_print("utf16 🎂")
+ m.string_view32_print("utf32 🎂")
+ assert capture == """
+ Hi 2
+ utf8 🎂 9
+ utf16 🎂 8
+ utf32 🎂 7
+ """
+ if hasattr(m, "has_u8string"):
+ with capture:
+ m.string_view8_print("Hi")
+ m.string_view8_print("utf8 🎂")
+ assert capture == """
+ Hi 2
+ utf8 🎂 9
+ """
+
+ with capture:
+ m.string_view_print("Hi, ascii")
+ m.string_view_print("Hi, utf8 🎂")
+ m.string_view16_print("Hi, utf16 🎂")
+ m.string_view32_print("Hi, utf32 🎂")
+ assert capture == """
+ Hi, ascii 9
+ Hi, utf8 🎂 13
+ Hi, utf16 🎂 12
+ Hi, utf32 🎂 11
+ """
+ if hasattr(m, "has_u8string"):
+ with capture:
+ m.string_view8_print("Hi, ascii")
+ m.string_view8_print("Hi, utf8 🎂")
+ assert capture == """
+ Hi, ascii 9
+ Hi, utf8 🎂 13
+ """
+
+
+def test_integer_casting():
+ """Issue #929 - out-of-range integer values shouldn't be accepted"""
+ import sys
+ assert m.i32_str(-1) == "-1"
+ assert m.i64_str(-1) == "-1"
+ assert m.i32_str(2000000000) == "2000000000"
+ assert m.u32_str(2000000000) == "2000000000"
+ if sys.version_info < (3,):
+ assert m.i32_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
+ assert m.i64_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
+ assert m.i64_str(long(-999999999999)) == "-999999999999" # noqa: F821 undefined name
+ assert m.u64_str(long(999999999999)) == "999999999999" # noqa: F821 undefined name 'long'
+ else:
+ assert m.i64_str(-999999999999) == "-999999999999"
+ assert m.u64_str(999999999999) == "999999999999"
+
+ with pytest.raises(TypeError) as excinfo:
+ m.u32_str(-1)
+ assert "incompatible function arguments" in str(excinfo.value)
+ with pytest.raises(TypeError) as excinfo:
+ m.u64_str(-1)
+ assert "incompatible function arguments" in str(excinfo.value)
+ with pytest.raises(TypeError) as excinfo:
+ m.i32_str(-3000000000)
+ assert "incompatible function arguments" in str(excinfo.value)
+ with pytest.raises(TypeError) as excinfo:
+ m.i32_str(3000000000)
+ assert "incompatible function arguments" in str(excinfo.value)
+
+ if sys.version_info < (3,):
+ with pytest.raises(TypeError) as excinfo:
+ m.u32_str(long(-1)) # noqa: F821 undefined name 'long'
+ assert "incompatible function arguments" in str(excinfo.value)
+ with pytest.raises(TypeError) as excinfo:
+ m.u64_str(long(-1)) # noqa: F821 undefined name 'long'
+ assert "incompatible function arguments" in str(excinfo.value)
+
+
+def test_tuple(doc):
+ """std::pair <-> tuple & std::tuple <-> tuple"""
+ assert m.pair_passthrough((True, "test")) == ("test", True)
+ assert m.tuple_passthrough((True, "test", 5)) == (5, "test", True)
+ # Any sequence can be cast to a std::pair or std::tuple
+ assert m.pair_passthrough([True, "test"]) == ("test", True)
+ assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True)
+ assert m.empty_tuple() == ()
+
+ assert doc(m.pair_passthrough) == """
+ pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool]
+
+ Return a pair in reversed order
+ """
+ assert doc(m.tuple_passthrough) == """
+ tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool]
+
+ Return a triple in reversed order
+ """
+
+ assert m.rvalue_pair() == ("rvalue", "rvalue")
+ assert m.lvalue_pair() == ("lvalue", "lvalue")
+ assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")
+ assert m.lvalue_tuple() == ("lvalue", "lvalue", "lvalue")
+ assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue")))
+ assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue")))
+
+
+def test_builtins_cast_return_none():
+ """Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None"""
+ assert m.return_none_string() is None
+ assert m.return_none_char() is None
+ assert m.return_none_bool() is None
+ assert m.return_none_int() is None
+ assert m.return_none_float() is None
+
+
+def test_none_deferred():
+ """None passed as various argument types should defer to other overloads"""
+ assert not m.defer_none_cstring("abc")
+ assert m.defer_none_cstring(None)
+ assert not m.defer_none_custom(UserType())
+ assert m.defer_none_custom(None)
+ assert m.nodefer_none_void(None)
+
+
+def test_void_caster():
+ assert m.load_nullptr_t(None) is None
+ assert m.cast_nullptr_t() is None
+
+
+def test_reference_wrapper():
+ """std::reference_wrapper for builtin and user types"""
+ assert m.refwrap_builtin(42) == 420
+ assert m.refwrap_usertype(UserType(42)) == 42
+
+ with pytest.raises(TypeError) as excinfo:
+ m.refwrap_builtin(None)
+ assert "incompatible function arguments" in str(excinfo.value)
+
+ with pytest.raises(TypeError) as excinfo:
+ m.refwrap_usertype(None)
+ assert "incompatible function arguments" in str(excinfo.value)
+
+ a1 = m.refwrap_list(copy=True)
+ a2 = m.refwrap_list(copy=True)
+ assert [x.value for x in a1] == [2, 3]
+ assert [x.value for x in a2] == [2, 3]
+ assert not a1[0] is a2[0] and not a1[1] is a2[1]
+
+ b1 = m.refwrap_list(copy=False)
+ b2 = m.refwrap_list(copy=False)
+ assert [x.value for x in b1] == [1, 2]
+ assert [x.value for x in b2] == [1, 2]
+ assert b1[0] is b2[0] and b1[1] is b2[1]
+
+ assert m.refwrap_iiw(IncType(5)) == 5
+ assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10]
+
+
+def test_complex_cast():
+ """std::complex casts"""
+ assert m.complex_cast(1) == "1.0"
+ assert m.complex_cast(2j) == "(0.0, 2.0)"
+
+
+def test_bool_caster():
+ """Test bool caster implicit conversions."""
+ convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
+
+ def require_implicit(v):
+ pytest.raises(TypeError, noconvert, v)
+
+ def cant_convert(v):
+ pytest.raises(TypeError, convert, v)
+
+ # straight up bool
+ assert convert(True) is True
+ assert convert(False) is False
+ assert noconvert(True) is True
+ assert noconvert(False) is False
+
+ # None requires implicit conversion
+ require_implicit(None)
+ assert convert(None) is False
+
+ class A(object):
+ def __init__(self, x):
+ self.x = x
+
+ def __nonzero__(self):
+ return self.x
+
+ def __bool__(self):
+ return self.x
+
+ class B(object):
+ pass
+
+ # Arbitrary objects are not accepted
+ cant_convert(object())
+ cant_convert(B())
+
+ # Objects with __nonzero__ / __bool__ defined can be converted
+ require_implicit(A(True))
+ assert convert(A(True)) is True
+ assert convert(A(False)) is False
+
+
+@pytest.requires_numpy
+def test_numpy_bool():
+ import numpy as np
+ convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
+
+ def cant_convert(v):
+ pytest.raises(TypeError, convert, v)
+
+ # np.bool_ is not considered implicit
+ assert convert(np.bool_(True)) is True
+ assert convert(np.bool_(False)) is False
+ assert noconvert(np.bool_(True)) is True
+ assert noconvert(np.bool_(False)) is False
+ cant_convert(np.zeros(2, dtype='int'))
+
+
+def test_int_long():
+ """In Python 2, a C++ int should return a Python int rather than long
+ if possible: longs are not always accepted where ints are used (such
+ as the argument to sys.exit()). A C++ long long is always a Python
+ long."""
+
+ import sys
+ must_be_long = type(getattr(sys, 'maxint', 1) + 1)
+ assert isinstance(m.int_cast(), int)
+ assert isinstance(m.long_cast(), int)
+ assert isinstance(m.longlong_cast(), must_be_long)
+
+
+def test_void_caster_2():
+ assert m.test_void_caster()
diff --git a/3rdparty/pybind11/tests/test_call_policies.cpp b/3rdparty/pybind11/tests/test_call_policies.cpp
new file mode 100644
index 00000000..fd245578
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_call_policies.cpp
@@ -0,0 +1,100 @@
+/*
+ tests/test_call_policies.cpp -- keep_alive and call_guard
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+struct CustomGuard {
+ static bool enabled;
+
+ CustomGuard() { enabled = true; }
+ ~CustomGuard() { enabled = false; }
+
+ static const char *report_status() { return enabled ? "guarded" : "unguarded"; }
+};
+bool CustomGuard::enabled = false;
+
+struct DependentGuard {
+ static bool enabled;
+
+ DependentGuard() { enabled = CustomGuard::enabled; }
+ ~DependentGuard() { enabled = false; }
+
+ static const char *report_status() { return enabled ? "guarded" : "unguarded"; }
+};
+bool DependentGuard::enabled = false;
+
+TEST_SUBMODULE(call_policies, m) {
+ // Parent/Child are used in:
+ // test_keep_alive_argument, test_keep_alive_return_value, test_alive_gc_derived,
+ // test_alive_gc_multi_derived, test_return_none, test_keep_alive_constructor
+ class Child {
+ public:
+ Child() { py::print("Allocating child."); }
+ Child(const Child &) = default;
+ Child(Child &&) = default;
+ ~Child() { py::print("Releasing child."); }
+ };
+ py::class_<Child>(m, "Child")
+ .def(py::init<>());
+
+ class Parent {
+ public:
+ Parent() { py::print("Allocating parent."); }
+ ~Parent() { py::print("Releasing parent."); }
+ void addChild(Child *) { }
+ Child *returnChild() { return new Child(); }
+ Child *returnNullChild() { return nullptr; }
+ };
+ py::class_<Parent>(m, "Parent")
+ .def(py::init<>())
+ .def(py::init([](Child *) { return new Parent(); }), py::keep_alive<1, 2>())
+ .def("addChild", &Parent::addChild)
+ .def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>())
+ .def("returnChild", &Parent::returnChild)
+ .def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>())
+ .def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>())
+ .def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>());
+
+#if !defined(PYPY_VERSION)
+ // test_alive_gc
+ class ParentGC : public Parent {
+ public:
+ using Parent::Parent;
+ };
+ py::class_<ParentGC, Parent>(m, "ParentGC", py::dynamic_attr())
+ .def(py::init<>());
+#endif
+
+ // test_call_guard
+ m.def("unguarded_call", &CustomGuard::report_status);
+ m.def("guarded_call", &CustomGuard::report_status, py::call_guard<CustomGuard>());
+
+ m.def("multiple_guards_correct_order", []() {
+ return CustomGuard::report_status() + std::string(" & ") + DependentGuard::report_status();
+ }, py::call_guard<CustomGuard, DependentGuard>());
+
+ m.def("multiple_guards_wrong_order", []() {
+ return DependentGuard::report_status() + std::string(" & ") + CustomGuard::report_status();
+ }, py::call_guard<DependentGuard, CustomGuard>());
+
+#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
+ // `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well,
+ // but it's unclear how to test it without `PyGILState_GetThisThreadState`.
+ auto report_gil_status = []() {
+ auto is_gil_held = false;
+ if (auto tstate = py::detail::get_thread_state_unchecked())
+ is_gil_held = (tstate == PyGILState_GetThisThreadState());
+
+ return is_gil_held ? "GIL held" : "GIL released";
+ };
+
+ m.def("with_gil", report_gil_status);
+ m.def("without_gil", report_gil_status, py::call_guard<py::gil_scoped_release>());
+#endif
+}
diff --git a/3rdparty/pybind11/tests/test_call_policies.py b/3rdparty/pybind11/tests/test_call_policies.py
new file mode 100644
index 00000000..7c835599
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_call_policies.py
@@ -0,0 +1,187 @@
+import pytest
+from pybind11_tests import call_policies as m
+from pybind11_tests import ConstructorStats
+
+
+def test_keep_alive_argument(capture):
+ n_inst = ConstructorStats.detail_reg_inst()
+ with capture:
+ p = m.Parent()
+ assert capture == "Allocating parent."
+ with capture:
+ p.addChild(m.Child())
+ assert ConstructorStats.detail_reg_inst() == n_inst + 1
+ assert capture == """
+ Allocating child.
+ Releasing child.
+ """
+ with capture:
+ del p
+ assert ConstructorStats.detail_reg_inst() == n_inst
+ assert capture == "Releasing parent."
+
+ with capture:
+ p = m.Parent()
+ assert capture == "Allocating parent."
+ with capture:
+ p.addChildKeepAlive(m.Child())
+ assert ConstructorStats.detail_reg_inst() == n_inst + 2
+ assert capture == "Allocating child."
+ with capture:
+ del p
+ assert ConstructorStats.detail_reg_inst() == n_inst
+ assert capture == """
+ Releasing parent.
+ Releasing child.
+ """
+
+
+def test_keep_alive_return_value(capture):
+ n_inst = ConstructorStats.detail_reg_inst()
+ with capture:
+ p = m.Parent()
+ assert capture == "Allocating parent."
+ with capture:
+ p.returnChild()
+ assert ConstructorStats.detail_reg_inst() == n_inst + 1
+ assert capture == """
+ Allocating child.
+ Releasing child.
+ """
+ with capture:
+ del p
+ assert ConstructorStats.detail_reg_inst() == n_inst
+ assert capture == "Releasing parent."
+
+ with capture:
+ p = m.Parent()
+ assert capture == "Allocating parent."
+ with capture:
+ p.returnChildKeepAlive()
+ assert ConstructorStats.detail_reg_inst() == n_inst + 2
+ assert capture == "Allocating child."
+ with capture:
+ del p
+ assert ConstructorStats.detail_reg_inst() == n_inst
+ assert capture == """
+ Releasing parent.
+ Releasing child.
+ """
+
+
+# https://bitbucket.org/pypy/pypy/issues/2447
+@pytest.unsupported_on_pypy
+def test_alive_gc(capture):
+ n_inst = ConstructorStats.detail_reg_inst()
+ p = m.ParentGC()
+ p.addChildKeepAlive(m.Child())
+ assert ConstructorStats.detail_reg_inst() == n_inst + 2
+ lst = [p]
+ lst.append(lst) # creates a circular reference
+ with capture:
+ del p, lst
+ assert ConstructorStats.detail_reg_inst() == n_inst
+ assert capture == """
+ Releasing parent.
+ Releasing child.
+ """
+
+
+def test_alive_gc_derived(capture):
+ class Derived(m.Parent):
+ pass
+
+ n_inst = ConstructorStats.detail_reg_inst()
+ p = Derived()
+ p.addChildKeepAlive(m.Child())
+ assert ConstructorStats.detail_reg_inst() == n_inst + 2
+ lst = [p]
+ lst.append(lst) # creates a circular reference
+ with capture:
+ del p, lst
+ assert ConstructorStats.detail_reg_inst() == n_inst
+ assert capture == """
+ Releasing parent.
+ Releasing child.
+ """
+
+
+def test_alive_gc_multi_derived(capture):
+ class Derived(m.Parent, m.Child):
+ def __init__(self):
+ m.Parent.__init__(self)
+ m.Child.__init__(self)
+
+ n_inst = ConstructorStats.detail_reg_inst()
+ p = Derived()
+ p.addChildKeepAlive(m.Child())
+ # +3 rather than +2 because Derived corresponds to two registered instances
+ assert ConstructorStats.detail_reg_inst() == n_inst + 3
+ lst = [p]
+ lst.append(lst) # creates a circular reference
+ with capture:
+ del p, lst
+ assert ConstructorStats.detail_reg_inst() == n_inst
+ assert capture == """
+ Releasing parent.
+ Releasing child.
+ Releasing child.
+ """
+
+
+def test_return_none(capture):
+ n_inst = ConstructorStats.detail_reg_inst()
+ with capture:
+ p = m.Parent()
+ assert capture == "Allocating parent."
+ with capture:
+ p.returnNullChildKeepAliveChild()
+ assert ConstructorStats.detail_reg_inst() == n_inst + 1
+ assert capture == ""
+ with capture:
+ del p
+ assert ConstructorStats.detail_reg_inst() == n_inst
+ assert capture == "Releasing parent."
+
+ with capture:
+ p = m.Parent()
+ assert capture == "Allocating parent."
+ with capture:
+ p.returnNullChildKeepAliveParent()
+ assert ConstructorStats.detail_reg_inst() == n_inst + 1
+ assert capture == ""
+ with capture:
+ del p
+ assert ConstructorStats.detail_reg_inst() == n_inst
+ assert capture == "Releasing parent."
+
+
+def test_keep_alive_constructor(capture):
+ n_inst = ConstructorStats.detail_reg_inst()
+
+ with capture:
+ p = m.Parent(m.Child())
+ assert ConstructorStats.detail_reg_inst() == n_inst + 2
+ assert capture == """
+ Allocating child.
+ Allocating parent.
+ """
+ with capture:
+ del p
+ assert ConstructorStats.detail_reg_inst() == n_inst
+ assert capture == """
+ Releasing parent.
+ Releasing child.
+ """
+
+
+def test_call_guard():
+ assert m.unguarded_call() == "unguarded"
+ assert m.guarded_call() == "guarded"
+
+ assert m.multiple_guards_correct_order() == "guarded & guarded"
+ assert m.multiple_guards_wrong_order() == "unguarded & guarded"
+
+ if hasattr(m, "with_gil"):
+ assert m.with_gil() == "GIL held"
+ assert m.without_gil() == "GIL released"
diff --git a/3rdparty/pybind11/tests/test_callbacks.cpp b/3rdparty/pybind11/tests/test_callbacks.cpp
new file mode 100644
index 00000000..71b88c44
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_callbacks.cpp
@@ -0,0 +1,168 @@
+/*
+ tests/test_callbacks.cpp -- callbacks
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/functional.h>
+#include <thread>
+
+
+int dummy_function(int i) { return i + 1; }
+
+TEST_SUBMODULE(callbacks, m) {
+ // test_callbacks, test_function_signatures
+ m.def("test_callback1", [](py::object func) { return func(); });
+ m.def("test_callback2", [](py::object func) { return func("Hello", 'x', true, 5); });
+ m.def("test_callback3", [](const std::function<int(int)> &func) {
+ return "func(43) = " + std::to_string(func(43)); });
+ m.def("test_callback4", []() -> std::function<int(int)> { return [](int i) { return i+1; }; });
+ m.def("test_callback5", []() {
+ return py::cpp_function([](int i) { return i+1; }, py::arg("number"));
+ });
+
+ // test_keyword_args_and_generalized_unpacking
+ m.def("test_tuple_unpacking", [](py::function f) {
+ auto t1 = py::make_tuple(2, 3);
+ auto t2 = py::make_tuple(5, 6);
+ return f("positional", 1, *t1, 4, *t2);
+ });
+
+ m.def("test_dict_unpacking", [](py::function f) {
+ auto d1 = py::dict("key"_a="value", "a"_a=1);
+ auto d2 = py::dict();
+ auto d3 = py::dict("b"_a=2);
+ return f("positional", 1, **d1, **d2, **d3);
+ });
+
+ m.def("test_keyword_args", [](py::function f) {
+ return f("x"_a=10, "y"_a=20);
+ });
+
+ m.def("test_unpacking_and_keywords1", [](py::function f) {
+ auto args = py::make_tuple(2);
+ auto kwargs = py::dict("d"_a=4);
+ return f(1, *args, "c"_a=3, **kwargs);
+ });
+
+ m.def("test_unpacking_and_keywords2", [](py::function f) {
+ auto kwargs1 = py::dict("a"_a=1);
+ auto kwargs2 = py::dict("c"_a=3, "d"_a=4);
+ return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5,
+ "key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5);
+ });
+
+ m.def("test_unpacking_error1", [](py::function f) {
+ auto kwargs = py::dict("x"_a=3);
+ return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword
+ });
+
+ m.def("test_unpacking_error2", [](py::function f) {
+ auto kwargs = py::dict("x"_a=3);
+ return f(**kwargs, "x"_a=1); // duplicate keyword after **
+ });
+
+ m.def("test_arg_conversion_error1", [](py::function f) {
+ f(234, UnregisteredType(), "kw"_a=567);
+ });
+
+ m.def("test_arg_conversion_error2", [](py::function f) {
+ f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567);
+ });
+
+ // test_lambda_closure_cleanup
+ struct Payload {
+ Payload() { print_default_created(this); }
+ ~Payload() { print_destroyed(this); }
+ Payload(const Payload &) { print_copy_created(this); }
+ Payload(Payload &&) { print_move_created(this); }
+ };
+ // Export the payload constructor statistics for testing purposes:
+ m.def("payload_cstats", &ConstructorStats::get<Payload>);
+ /* Test cleanup of lambda closure */
+ m.def("test_cleanup", []() -> std::function<void(void)> {
+ Payload p;
+
+ return [p]() {
+ /* p should be cleaned up when the returned function is garbage collected */
+ (void) p;
+ };
+ });
+
+ // test_cpp_function_roundtrip
+ /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
+ m.def("dummy_function", &dummy_function);
+ m.def("dummy_function2", [](int i, int j) { return i + j; });
+ m.def("roundtrip", [](std::function<int(int)> f, bool expect_none = false) {
+ if (expect_none && f)
+ throw std::runtime_error("Expected None to be converted to empty std::function");
+ return f;
+ }, py::arg("f"), py::arg("expect_none")=false);
+ m.def("test_dummy_function", [](const std::function<int(int)> &f) -> std::string {
+ using fn_type = int (*)(int);
+ auto result = f.target<fn_type>();
+ if (!result) {
+ auto r = f(1);
+ return "can't convert to function pointer: eval(1) = " + std::to_string(r);
+ } else if (*result == dummy_function) {
+ auto r = (*result)(1);
+ return "matches dummy_function: eval(1) = " + std::to_string(r);
+ } else {
+ return "argument does NOT match dummy_function. This should never happen!";
+ }
+ });
+
+ class AbstractBase { public: virtual unsigned int func() = 0; };
+ m.def("func_accepting_func_accepting_base", [](std::function<double(AbstractBase&)>) { });
+
+ struct MovableObject {
+ bool valid = true;
+
+ MovableObject() = default;
+ MovableObject(const MovableObject &) = default;
+ MovableObject &operator=(const MovableObject &) = default;
+ MovableObject(MovableObject &&o) : valid(o.valid) { o.valid = false; }
+ MovableObject &operator=(MovableObject &&o) {
+ valid = o.valid;
+ o.valid = false;
+ return *this;
+ }
+ };
+ py::class_<MovableObject>(m, "MovableObject");
+
+ // test_movable_object
+ m.def("callback_with_movable", [](std::function<void(MovableObject &)> f) {
+ auto x = MovableObject();
+ f(x); // lvalue reference shouldn't move out object
+ return x.valid; // must still return `true`
+ });
+
+ // test_bound_method_callback
+ struct CppBoundMethodTest {};
+ py::class_<CppBoundMethodTest>(m, "CppBoundMethodTest")
+ .def(py::init<>())
+ .def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; });
+
+ // test async Python callbacks
+ using callback_f = std::function<void(int)>;
+ m.def("test_async_callback", [](callback_f f, py::list work) {
+ // make detached thread that calls `f` with piece of work after a little delay
+ auto start_f = [f](int j) {
+ auto invoke_f = [f, j] {
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ f(j);
+ };
+ auto t = std::thread(std::move(invoke_f));
+ t.detach();
+ };
+
+ // spawn worker threads
+ for (auto i : work)
+ start_f(py::cast<int>(i));
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_callbacks.py b/3rdparty/pybind11/tests/test_callbacks.py
new file mode 100644
index 00000000..6439c8e7
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_callbacks.py
@@ -0,0 +1,136 @@
+import pytest
+from pybind11_tests import callbacks as m
+from threading import Thread
+
+
+def test_callbacks():
+ from functools import partial
+
+ def func1():
+ return "func1"
+
+ def func2(a, b, c, d):
+ return "func2", a, b, c, d
+
+ def func3(a):
+ return "func3({})".format(a)
+
+ assert m.test_callback1(func1) == "func1"
+ assert m.test_callback2(func2) == ("func2", "Hello", "x", True, 5)
+ assert m.test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4)
+ assert m.test_callback1(partial(func3, "partial")) == "func3(partial)"
+ assert m.test_callback3(lambda i: i + 1) == "func(43) = 44"
+
+ f = m.test_callback4()
+ assert f(43) == 44
+ f = m.test_callback5()
+ assert f(number=43) == 44
+
+
+def test_bound_method_callback():
+ # Bound Python method:
+ class MyClass:
+ def double(self, val):
+ return 2 * val
+
+ z = MyClass()
+ assert m.test_callback3(z.double) == "func(43) = 86"
+
+ z = m.CppBoundMethodTest()
+ assert m.test_callback3(z.triple) == "func(43) = 129"
+
+
+def test_keyword_args_and_generalized_unpacking():
+
+ def f(*args, **kwargs):
+ return args, kwargs
+
+ assert m.test_tuple_unpacking(f) == (("positional", 1, 2, 3, 4, 5, 6), {})
+ assert m.test_dict_unpacking(f) == (("positional", 1), {"key": "value", "a": 1, "b": 2})
+ assert m.test_keyword_args(f) == ((), {"x": 10, "y": 20})
+ assert m.test_unpacking_and_keywords1(f) == ((1, 2), {"c": 3, "d": 4})
+ assert m.test_unpacking_and_keywords2(f) == (
+ ("positional", 1, 2, 3, 4, 5),
+ {"key": "value", "a": 1, "b": 2, "c": 3, "d": 4, "e": 5}
+ )
+
+ with pytest.raises(TypeError) as excinfo:
+ m.test_unpacking_error1(f)
+ assert "Got multiple values for keyword argument" in str(excinfo.value)
+
+ with pytest.raises(TypeError) as excinfo:
+ m.test_unpacking_error2(f)
+ assert "Got multiple values for keyword argument" in str(excinfo.value)
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.test_arg_conversion_error1(f)
+ assert "Unable to convert call argument" in str(excinfo.value)
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.test_arg_conversion_error2(f)
+ assert "Unable to convert call argument" in str(excinfo.value)
+
+
+def test_lambda_closure_cleanup():
+ m.test_cleanup()
+ cstats = m.payload_cstats()
+ assert cstats.alive() == 0
+ assert cstats.copy_constructions == 1
+ assert cstats.move_constructions >= 1
+
+
+def test_cpp_function_roundtrip():
+ """Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer"""
+
+ assert m.test_dummy_function(m.dummy_function) == "matches dummy_function: eval(1) = 2"
+ assert (m.test_dummy_function(m.roundtrip(m.dummy_function)) ==
+ "matches dummy_function: eval(1) = 2")
+ assert m.roundtrip(None, expect_none=True) is None
+ assert (m.test_dummy_function(lambda x: x + 2) ==
+ "can't convert to function pointer: eval(1) = 3")
+
+ with pytest.raises(TypeError) as excinfo:
+ m.test_dummy_function(m.dummy_function2)
+ assert "incompatible function arguments" in str(excinfo.value)
+
+ with pytest.raises(TypeError) as excinfo:
+ m.test_dummy_function(lambda x, y: x + y)
+ assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument",
+ "takes exactly 2 arguments"))
+
+
+def test_function_signatures(doc):
+ assert doc(m.test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str"
+ assert doc(m.test_callback4) == "test_callback4() -> Callable[[int], int]"
+
+
+def test_movable_object():
+ assert m.callback_with_movable(lambda _: None) is True
+
+
+def test_async_callbacks():
+ # serves as state for async callback
+ class Item:
+ def __init__(self, value):
+ self.value = value
+
+ res = []
+
+ # generate stateful lambda that will store result in `res`
+ def gen_f():
+ s = Item(3)
+ return lambda j: res.append(s.value + j)
+
+ # do some work async
+ work = [1, 2, 3, 4]
+ m.test_async_callback(gen_f(), work)
+ # wait until work is done
+ from time import sleep
+ sleep(0.5)
+ assert sum(res) == sum([x + 3 for x in work])
+
+
+def test_async_async_callbacks():
+ t = Thread(target=test_async_callbacks)
+ t.start()
+ t.join()
diff --git a/3rdparty/pybind11/tests/test_chrono.cpp b/3rdparty/pybind11/tests/test_chrono.cpp
new file mode 100644
index 00000000..899d08d8
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_chrono.cpp
@@ -0,0 +1,55 @@
+/*
+ tests/test_chrono.cpp -- test conversions to/from std::chrono types
+
+ Copyright (c) 2016 Trent Houliston <trent@houliston.me> and
+ Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include <pybind11/chrono.h>
+
+TEST_SUBMODULE(chrono, m) {
+ using system_time = std::chrono::system_clock::time_point;
+ using steady_time = std::chrono::steady_clock::time_point;
+
+ using timespan = std::chrono::duration<int64_t, std::nano>;
+ using timestamp = std::chrono::time_point<std::chrono::system_clock, timespan>;
+
+ // test_chrono_system_clock
+ // Return the current time off the wall clock
+ m.def("test_chrono1", []() { return std::chrono::system_clock::now(); });
+
+ // test_chrono_system_clock_roundtrip
+ // Round trip the passed in system clock time
+ m.def("test_chrono2", [](system_time t) { return t; });
+
+ // test_chrono_duration_roundtrip
+ // Round trip the passed in duration
+ m.def("test_chrono3", [](std::chrono::system_clock::duration d) { return d; });
+
+ // test_chrono_duration_subtraction_equivalence
+ // Difference between two passed in time_points
+ m.def("test_chrono4", [](system_time a, system_time b) { return a - b; });
+
+ // test_chrono_steady_clock
+ // Return the current time off the steady_clock
+ m.def("test_chrono5", []() { return std::chrono::steady_clock::now(); });
+
+ // test_chrono_steady_clock_roundtrip
+ // Round trip a steady clock timepoint
+ m.def("test_chrono6", [](steady_time t) { return t; });
+
+ // test_floating_point_duration
+ // Roundtrip a duration in microseconds from a float argument
+ m.def("test_chrono7", [](std::chrono::microseconds t) { return t; });
+ // Float durations (issue #719)
+ m.def("test_chrono_float_diff", [](std::chrono::duration<float> a, std::chrono::duration<float> b) {
+ return a - b; });
+
+ m.def("test_nano_timepoint", [](timestamp start, timespan delta) -> timestamp {
+ return start + delta;
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_chrono.py b/3rdparty/pybind11/tests/test_chrono.py
new file mode 100644
index 00000000..55c95440
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_chrono.py
@@ -0,0 +1,176 @@
+from pybind11_tests import chrono as m
+import datetime
+
+
+def test_chrono_system_clock():
+
+ # Get the time from both c++ and datetime
+ date1 = m.test_chrono1()
+ date2 = datetime.datetime.today()
+
+ # The returned value should be a datetime
+ assert isinstance(date1, datetime.datetime)
+
+ # The numbers should vary by a very small amount (time it took to execute)
+ diff = abs(date1 - date2)
+
+ # There should never be a days/seconds difference
+ assert diff.days == 0
+ assert diff.seconds == 0
+
+ # We test that no more than about 0.5 seconds passes here
+ # This makes sure that the dates created are very close to the same
+ # but if the testing system is incredibly overloaded this should still pass
+ assert diff.microseconds < 500000
+
+
+def test_chrono_system_clock_roundtrip():
+ date1 = datetime.datetime.today()
+
+ # Roundtrip the time
+ date2 = m.test_chrono2(date1)
+
+ # The returned value should be a datetime
+ assert isinstance(date2, datetime.datetime)
+
+ # They should be identical (no information lost on roundtrip)
+ diff = abs(date1 - date2)
+ assert diff.days == 0
+ assert diff.seconds == 0
+ assert diff.microseconds == 0
+
+
+def test_chrono_system_clock_roundtrip_date():
+ date1 = datetime.date.today()
+
+ # Roundtrip the time
+ datetime2 = m.test_chrono2(date1)
+ date2 = datetime2.date()
+ time2 = datetime2.time()
+
+ # The returned value should be a datetime
+ assert isinstance(datetime2, datetime.datetime)
+ assert isinstance(date2, datetime.date)
+ assert isinstance(time2, datetime.time)
+
+ # They should be identical (no information lost on roundtrip)
+ diff = abs(date1 - date2)
+ assert diff.days == 0
+ assert diff.seconds == 0
+ assert diff.microseconds == 0
+
+ # Year, Month & Day should be the same after the round trip
+ assert date1.year == date2.year
+ assert date1.month == date2.month
+ assert date1.day == date2.day
+
+ # There should be no time information
+ assert time2.hour == 0
+ assert time2.minute == 0
+ assert time2.second == 0
+ assert time2.microsecond == 0
+
+
+def test_chrono_system_clock_roundtrip_time():
+ time1 = datetime.datetime.today().time()
+
+ # Roundtrip the time
+ datetime2 = m.test_chrono2(time1)
+ date2 = datetime2.date()
+ time2 = datetime2.time()
+
+ # The returned value should be a datetime
+ assert isinstance(datetime2, datetime.datetime)
+ assert isinstance(date2, datetime.date)
+ assert isinstance(time2, datetime.time)
+
+ # Hour, Minute, Second & Microsecond should be the same after the round trip
+ assert time1.hour == time2.hour
+ assert time1.minute == time2.minute
+ assert time1.second == time2.second
+ assert time1.microsecond == time2.microsecond
+
+ # There should be no date information (i.e. date = python base date)
+ assert date2.year == 1970
+ assert date2.month == 1
+ assert date2.day == 1
+
+
+def test_chrono_duration_roundtrip():
+
+ # Get the difference between two times (a timedelta)
+ date1 = datetime.datetime.today()
+ date2 = datetime.datetime.today()
+ diff = date2 - date1
+
+ # Make sure this is a timedelta
+ assert isinstance(diff, datetime.timedelta)
+
+ cpp_diff = m.test_chrono3(diff)
+
+ assert cpp_diff.days == diff.days
+ assert cpp_diff.seconds == diff.seconds
+ assert cpp_diff.microseconds == diff.microseconds
+
+
+def test_chrono_duration_subtraction_equivalence():
+
+ date1 = datetime.datetime.today()
+ date2 = datetime.datetime.today()
+
+ diff = date2 - date1
+ cpp_diff = m.test_chrono4(date2, date1)
+
+ assert cpp_diff.days == diff.days
+ assert cpp_diff.seconds == diff.seconds
+ assert cpp_diff.microseconds == diff.microseconds
+
+
+def test_chrono_duration_subtraction_equivalence_date():
+
+ date1 = datetime.date.today()
+ date2 = datetime.date.today()
+
+ diff = date2 - date1
+ cpp_diff = m.test_chrono4(date2, date1)
+
+ assert cpp_diff.days == diff.days
+ assert cpp_diff.seconds == diff.seconds
+ assert cpp_diff.microseconds == diff.microseconds
+
+
+def test_chrono_steady_clock():
+ time1 = m.test_chrono5()
+ assert isinstance(time1, datetime.timedelta)
+
+
+def test_chrono_steady_clock_roundtrip():
+ time1 = datetime.timedelta(days=10, seconds=10, microseconds=100)
+ time2 = m.test_chrono6(time1)
+
+ assert isinstance(time2, datetime.timedelta)
+
+ # They should be identical (no information lost on roundtrip)
+ assert time1.days == time2.days
+ assert time1.seconds == time2.seconds
+ assert time1.microseconds == time2.microseconds
+
+
+def test_floating_point_duration():
+ # Test using a floating point number in seconds
+ time = m.test_chrono7(35.525123)
+
+ assert isinstance(time, datetime.timedelta)
+
+ assert time.seconds == 35
+ assert 525122 <= time.microseconds <= 525123
+
+ diff = m.test_chrono_float_diff(43.789012, 1.123456)
+ assert diff.seconds == 42
+ assert 665556 <= diff.microseconds <= 665557
+
+
+def test_nano_timepoint():
+ time = datetime.datetime.now()
+ time1 = m.test_nano_timepoint(time, datetime.timedelta(seconds=60))
+ assert(time1 == time + datetime.timedelta(seconds=60))
diff --git a/3rdparty/pybind11/tests/test_class.cpp b/3rdparty/pybind11/tests/test_class.cpp
new file mode 100644
index 00000000..499d0cc5
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_class.cpp
@@ -0,0 +1,422 @@
+/*
+ tests/test_class.cpp -- test py::class_ definitions and basic functionality
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include "local_bindings.h"
+#include <pybind11/stl.h>
+
+#if defined(_MSC_VER)
+# pragma warning(disable: 4324) // warning C4324: structure was padded due to alignment specifier
+#endif
+
+// test_brace_initialization
+struct NoBraceInitialization {
+ NoBraceInitialization(std::vector<int> v) : vec{std::move(v)} {}
+ template <typename T>
+ NoBraceInitialization(std::initializer_list<T> l) : vec(l) {}
+
+ std::vector<int> vec;
+};
+
+TEST_SUBMODULE(class_, m) {
+ // test_instance
+ struct NoConstructor {
+ NoConstructor() = default;
+ NoConstructor(const NoConstructor &) = default;
+ NoConstructor(NoConstructor &&) = default;
+ static NoConstructor *new_instance() {
+ auto *ptr = new NoConstructor();
+ print_created(ptr, "via new_instance");
+ return ptr;
+ }
+ ~NoConstructor() { print_destroyed(this); }
+ };
+
+ py::class_<NoConstructor>(m, "NoConstructor")
+ .def_static("new_instance", &NoConstructor::new_instance, "Return an instance");
+
+ // test_inheritance
+ class Pet {
+ public:
+ Pet(const std::string &name, const std::string &species)
+ : m_name(name), m_species(species) {}
+ std::string name() const { return m_name; }
+ std::string species() const { return m_species; }
+ private:
+ std::string m_name;
+ std::string m_species;
+ };
+
+ class Dog : public Pet {
+ public:
+ Dog(const std::string &name) : Pet(name, "dog") {}
+ std::string bark() const { return "Woof!"; }
+ };
+
+ class Rabbit : public Pet {
+ public:
+ Rabbit(const std::string &name) : Pet(name, "parrot") {}
+ };
+
+ class Hamster : public Pet {
+ public:
+ Hamster(const std::string &name) : Pet(name, "rodent") {}
+ };
+
+ class Chimera : public Pet {
+ Chimera() : Pet("Kimmy", "chimera") {}
+ };
+
+ py::class_<Pet> pet_class(m, "Pet");
+ pet_class
+ .def(py::init<std::string, std::string>())
+ .def("name", &Pet::name)
+ .def("species", &Pet::species);
+
+ /* One way of declaring a subclass relationship: reference parent's class_ object */
+ py::class_<Dog>(m, "Dog", pet_class)
+ .def(py::init<std::string>());
+
+ /* Another way of declaring a subclass relationship: reference parent's C++ type */
+ py::class_<Rabbit, Pet>(m, "Rabbit")
+ .def(py::init<std::string>());
+
+ /* And another: list parent in class template arguments */
+ py::class_<Hamster, Pet>(m, "Hamster")
+ .def(py::init<std::string>());
+
+ /* Constructors are not inherited by default */
+ py::class_<Chimera, Pet>(m, "Chimera");
+
+ m.def("pet_name_species", [](const Pet &pet) { return pet.name() + " is a " + pet.species(); });
+ m.def("dog_bark", [](const Dog &dog) { return dog.bark(); });
+
+ // test_automatic_upcasting
+ struct BaseClass {
+ BaseClass() = default;
+ BaseClass(const BaseClass &) = default;
+ BaseClass(BaseClass &&) = default;
+ virtual ~BaseClass() {}
+ };
+ struct DerivedClass1 : BaseClass { };
+ struct DerivedClass2 : BaseClass { };
+
+ py::class_<BaseClass>(m, "BaseClass").def(py::init<>());
+ py::class_<DerivedClass1>(m, "DerivedClass1").def(py::init<>());
+ py::class_<DerivedClass2>(m, "DerivedClass2").def(py::init<>());
+
+ m.def("return_class_1", []() -> BaseClass* { return new DerivedClass1(); });
+ m.def("return_class_2", []() -> BaseClass* { return new DerivedClass2(); });
+ m.def("return_class_n", [](int n) -> BaseClass* {
+ if (n == 1) return new DerivedClass1();
+ if (n == 2) return new DerivedClass2();
+ return new BaseClass();
+ });
+ m.def("return_none", []() -> BaseClass* { return nullptr; });
+
+ // test_isinstance
+ m.def("check_instances", [](py::list l) {
+ return py::make_tuple(
+ py::isinstance<py::tuple>(l[0]),
+ py::isinstance<py::dict>(l[1]),
+ py::isinstance<Pet>(l[2]),
+ py::isinstance<Pet>(l[3]),
+ py::isinstance<Dog>(l[4]),
+ py::isinstance<Rabbit>(l[5]),
+ py::isinstance<UnregisteredType>(l[6])
+ );
+ });
+
+ // test_mismatched_holder
+ struct MismatchBase1 { };
+ struct MismatchDerived1 : MismatchBase1 { };
+
+ struct MismatchBase2 { };
+ struct MismatchDerived2 : MismatchBase2 { };
+
+ m.def("mismatched_holder_1", []() {
+ auto mod = py::module::import("__main__");
+ py::class_<MismatchBase1, std::shared_ptr<MismatchBase1>>(mod, "MismatchBase1");
+ py::class_<MismatchDerived1, MismatchBase1>(mod, "MismatchDerived1");
+ });
+ m.def("mismatched_holder_2", []() {
+ auto mod = py::module::import("__main__");
+ py::class_<MismatchBase2>(mod, "MismatchBase2");
+ py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>,
+ MismatchBase2>(mod, "MismatchDerived2");
+ });
+
+ // test_override_static
+ // #511: problem with inheritance + overwritten def_static
+ struct MyBase {
+ static std::unique_ptr<MyBase> make() {
+ return std::unique_ptr<MyBase>(new MyBase());
+ }
+ };
+
+ struct MyDerived : MyBase {
+ static std::unique_ptr<MyDerived> make() {
+ return std::unique_ptr<MyDerived>(new MyDerived());
+ }
+ };
+
+ py::class_<MyBase>(m, "MyBase")
+ .def_static("make", &MyBase::make);
+
+ py::class_<MyDerived, MyBase>(m, "MyDerived")
+ .def_static("make", &MyDerived::make)
+ .def_static("make2", &MyDerived::make);
+
+ // test_implicit_conversion_life_support
+ struct ConvertibleFromUserType {
+ int i;
+
+ ConvertibleFromUserType(UserType u) : i(u.value()) { }
+ };
+
+ py::class_<ConvertibleFromUserType>(m, "AcceptsUserType")
+ .def(py::init<UserType>());
+ py::implicitly_convertible<UserType, ConvertibleFromUserType>();
+
+ m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; });
+ m.def("implicitly_convert_variable", [](py::object o) {
+ // `o` is `UserType` and `r` is a reference to a temporary created by implicit
+ // conversion. This is valid when called inside a bound function because the temp
+ // object is attached to the same life support system as the arguments.
+ const auto &r = o.cast<const ConvertibleFromUserType &>();
+ return r.i;
+ });
+ m.add_object("implicitly_convert_variable_fail", [&] {
+ auto f = [](PyObject *, PyObject *args) -> PyObject * {
+ auto o = py::reinterpret_borrow<py::tuple>(args)[0];
+ try { // It should fail here because there is no life support.
+ o.cast<const ConvertibleFromUserType &>();
+ } catch (const py::cast_error &e) {
+ return py::str(e.what()).release().ptr();
+ }
+ return py::str().release().ptr();
+ };
+
+ auto def = new PyMethodDef{"f", f, METH_VARARGS, nullptr};
+ return py::reinterpret_steal<py::object>(PyCFunction_NewEx(def, nullptr, m.ptr()));
+ }());
+
+ // test_operator_new_delete
+ struct HasOpNewDel {
+ std::uint64_t i;
+ static void *operator new(size_t s) { py::print("A new", s); return ::operator new(s); }
+ static void *operator new(size_t s, void *ptr) { py::print("A placement-new", s); return ptr; }
+ static void operator delete(void *p) { py::print("A delete"); return ::operator delete(p); }
+ };
+ struct HasOpNewDelSize {
+ std::uint32_t i;
+ static void *operator new(size_t s) { py::print("B new", s); return ::operator new(s); }
+ static void *operator new(size_t s, void *ptr) { py::print("B placement-new", s); return ptr; }
+ static void operator delete(void *p, size_t s) { py::print("B delete", s); return ::operator delete(p); }
+ };
+ struct AliasedHasOpNewDelSize {
+ std::uint64_t i;
+ static void *operator new(size_t s) { py::print("C new", s); return ::operator new(s); }
+ static void *operator new(size_t s, void *ptr) { py::print("C placement-new", s); return ptr; }
+ static void operator delete(void *p, size_t s) { py::print("C delete", s); return ::operator delete(p); }
+ virtual ~AliasedHasOpNewDelSize() = default;
+ };
+ struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize {
+ PyAliasedHasOpNewDelSize() = default;
+ PyAliasedHasOpNewDelSize(int) { }
+ std::uint64_t j;
+ };
+ struct HasOpNewDelBoth {
+ std::uint32_t i[8];
+ static void *operator new(size_t s) { py::print("D new", s); return ::operator new(s); }
+ static void *operator new(size_t s, void *ptr) { py::print("D placement-new", s); return ptr; }
+ static void operator delete(void *p) { py::print("D delete"); return ::operator delete(p); }
+ static void operator delete(void *p, size_t s) { py::print("D wrong delete", s); return ::operator delete(p); }
+ };
+ py::class_<HasOpNewDel>(m, "HasOpNewDel").def(py::init<>());
+ py::class_<HasOpNewDelSize>(m, "HasOpNewDelSize").def(py::init<>());
+ py::class_<HasOpNewDelBoth>(m, "HasOpNewDelBoth").def(py::init<>());
+ py::class_<AliasedHasOpNewDelSize, PyAliasedHasOpNewDelSize> aliased(m, "AliasedHasOpNewDelSize");
+ aliased.def(py::init<>());
+ aliased.attr("size_noalias") = py::int_(sizeof(AliasedHasOpNewDelSize));
+ aliased.attr("size_alias") = py::int_(sizeof(PyAliasedHasOpNewDelSize));
+
+ // This test is actually part of test_local_bindings (test_duplicate_local), but we need a
+ // definition in a different compilation unit within the same module:
+ bind_local<LocalExternal, 17>(m, "LocalExternal", py::module_local());
+
+ // test_bind_protected_functions
+ class ProtectedA {
+ protected:
+ int foo() const { return value; }
+
+ private:
+ int value = 42;
+ };
+
+ class PublicistA : public ProtectedA {
+ public:
+ using ProtectedA::foo;
+ };
+
+ py::class_<ProtectedA>(m, "ProtectedA")
+ .def(py::init<>())
+#if !defined(_MSC_VER) || _MSC_VER >= 1910
+ .def("foo", &PublicistA::foo);
+#else
+ .def("foo", static_cast<int (ProtectedA::*)() const>(&PublicistA::foo));
+#endif
+
+ class ProtectedB {
+ public:
+ virtual ~ProtectedB() = default;
+
+ protected:
+ virtual int foo() const { return value; }
+
+ private:
+ int value = 42;
+ };
+
+ class TrampolineB : public ProtectedB {
+ public:
+ int foo() const override { PYBIND11_OVERLOAD(int, ProtectedB, foo, ); }
+ };
+
+ class PublicistB : public ProtectedB {
+ public:
+ using ProtectedB::foo;
+ };
+
+ py::class_<ProtectedB, TrampolineB>(m, "ProtectedB")
+ .def(py::init<>())
+#if !defined(_MSC_VER) || _MSC_VER >= 1910
+ .def("foo", &PublicistB::foo);
+#else
+ .def("foo", static_cast<int (ProtectedB::*)() const>(&PublicistB::foo));
+#endif
+
+ // test_brace_initialization
+ struct BraceInitialization {
+ int field1;
+ std::string field2;
+ };
+
+ py::class_<BraceInitialization>(m, "BraceInitialization")
+ .def(py::init<int, const std::string &>())
+ .def_readwrite("field1", &BraceInitialization::field1)
+ .def_readwrite("field2", &BraceInitialization::field2);
+ // We *don't* want to construct using braces when the given constructor argument maps to a
+ // constructor, because brace initialization could go to the wrong place (in particular when
+ // there is also an `initializer_list<T>`-accept constructor):
+ py::class_<NoBraceInitialization>(m, "NoBraceInitialization")
+ .def(py::init<std::vector<int>>())
+ .def_readonly("vec", &NoBraceInitialization::vec);
+
+ // test_reentrant_implicit_conversion_failure
+ // #1035: issue with runaway reentrant implicit conversion
+ struct BogusImplicitConversion {
+ BogusImplicitConversion(const BogusImplicitConversion &) { }
+ };
+
+ py::class_<BogusImplicitConversion>(m, "BogusImplicitConversion")
+ .def(py::init<const BogusImplicitConversion &>());
+
+ py::implicitly_convertible<int, BogusImplicitConversion>();
+
+ // test_qualname
+ // #1166: nested class docstring doesn't show nested name
+ // Also related: tests that __qualname__ is set properly
+ struct NestBase {};
+ struct Nested {};
+ py::class_<NestBase> base(m, "NestBase");
+ base.def(py::init<>());
+ py::class_<Nested>(base, "Nested")
+ .def(py::init<>())
+ .def("fn", [](Nested &, int, NestBase &, Nested &) {})
+ .def("fa", [](Nested &, int, NestBase &, Nested &) {},
+ "a"_a, "b"_a, "c"_a);
+ base.def("g", [](NestBase &, Nested &) {});
+ base.def("h", []() { return NestBase(); });
+
+ // test_error_after_conversion
+ // The second-pass path through dispatcher() previously didn't
+ // remember which overload was used, and would crash trying to
+ // generate a useful error message
+
+ struct NotRegistered {};
+ struct StringWrapper { std::string str; };
+ m.def("test_error_after_conversions", [](int) {});
+ m.def("test_error_after_conversions",
+ [](StringWrapper) -> NotRegistered { return {}; });
+ py::class_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>());
+ py::implicitly_convertible<std::string, StringWrapper>();
+
+ #if defined(PYBIND11_CPP17)
+ struct alignas(1024) Aligned {
+ std::uintptr_t ptr() const { return (uintptr_t) this; }
+ };
+ py::class_<Aligned>(m, "Aligned")
+ .def(py::init<>())
+ .def("ptr", &Aligned::ptr);
+ #endif
+}
+
+template <int N> class BreaksBase { public: virtual ~BreaksBase() = default; };
+template <int N> class BreaksTramp : public BreaksBase<N> {};
+// These should all compile just fine:
+typedef py::class_<BreaksBase<1>, std::unique_ptr<BreaksBase<1>>, BreaksTramp<1>> DoesntBreak1;
+typedef py::class_<BreaksBase<2>, BreaksTramp<2>, std::unique_ptr<BreaksBase<2>>> DoesntBreak2;
+typedef py::class_<BreaksBase<3>, std::unique_ptr<BreaksBase<3>>> DoesntBreak3;
+typedef py::class_<BreaksBase<4>, BreaksTramp<4>> DoesntBreak4;
+typedef py::class_<BreaksBase<5>> DoesntBreak5;
+typedef py::class_<BreaksBase<6>, std::shared_ptr<BreaksBase<6>>, BreaksTramp<6>> DoesntBreak6;
+typedef py::class_<BreaksBase<7>, BreaksTramp<7>, std::shared_ptr<BreaksBase<7>>> DoesntBreak7;
+typedef py::class_<BreaksBase<8>, std::shared_ptr<BreaksBase<8>>> DoesntBreak8;
+#define CHECK_BASE(N) static_assert(std::is_same<typename DoesntBreak##N::type, BreaksBase<N>>::value, \
+ "DoesntBreak" #N " has wrong type!")
+CHECK_BASE(1); CHECK_BASE(2); CHECK_BASE(3); CHECK_BASE(4); CHECK_BASE(5); CHECK_BASE(6); CHECK_BASE(7); CHECK_BASE(8);
+#define CHECK_ALIAS(N) static_assert(DoesntBreak##N::has_alias && std::is_same<typename DoesntBreak##N::type_alias, BreaksTramp<N>>::value, \
+ "DoesntBreak" #N " has wrong type_alias!")
+#define CHECK_NOALIAS(N) static_assert(!DoesntBreak##N::has_alias && std::is_void<typename DoesntBreak##N::type_alias>::value, \
+ "DoesntBreak" #N " has type alias, but shouldn't!")
+CHECK_ALIAS(1); CHECK_ALIAS(2); CHECK_NOALIAS(3); CHECK_ALIAS(4); CHECK_NOALIAS(5); CHECK_ALIAS(6); CHECK_ALIAS(7); CHECK_NOALIAS(8);
+#define CHECK_HOLDER(N, TYPE) static_assert(std::is_same<typename DoesntBreak##N::holder_type, std::TYPE##_ptr<BreaksBase<N>>>::value, \
+ "DoesntBreak" #N " has wrong holder_type!")
+CHECK_HOLDER(1, unique); CHECK_HOLDER(2, unique); CHECK_HOLDER(3, unique); CHECK_HOLDER(4, unique); CHECK_HOLDER(5, unique);
+CHECK_HOLDER(6, shared); CHECK_HOLDER(7, shared); CHECK_HOLDER(8, shared);
+
+// There's no nice way to test that these fail because they fail to compile; leave them here,
+// though, so that they can be manually tested by uncommenting them (and seeing that compilation
+// failures occurs).
+
+// We have to actually look into the type: the typedef alone isn't enough to instantiate the type:
+#define CHECK_BROKEN(N) static_assert(std::is_same<typename Breaks##N::type, BreaksBase<-N>>::value, \
+ "Breaks1 has wrong type!");
+
+//// Two holder classes:
+//typedef py::class_<BreaksBase<-1>, std::unique_ptr<BreaksBase<-1>>, std::unique_ptr<BreaksBase<-1>>> Breaks1;
+//CHECK_BROKEN(1);
+//// Two aliases:
+//typedef py::class_<BreaksBase<-2>, BreaksTramp<-2>, BreaksTramp<-2>> Breaks2;
+//CHECK_BROKEN(2);
+//// Holder + 2 aliases
+//typedef py::class_<BreaksBase<-3>, std::unique_ptr<BreaksBase<-3>>, BreaksTramp<-3>, BreaksTramp<-3>> Breaks3;
+//CHECK_BROKEN(3);
+//// Alias + 2 holders
+//typedef py::class_<BreaksBase<-4>, std::unique_ptr<BreaksBase<-4>>, BreaksTramp<-4>, std::shared_ptr<BreaksBase<-4>>> Breaks4;
+//CHECK_BROKEN(4);
+//// Invalid option (not a subclass or holder)
+//typedef py::class_<BreaksBase<-5>, BreaksTramp<-4>> Breaks5;
+//CHECK_BROKEN(5);
+//// Invalid option: multiple inheritance not supported:
+//template <> struct BreaksBase<-8> : BreaksBase<-6>, BreaksBase<-7> {};
+//typedef py::class_<BreaksBase<-8>, BreaksBase<-6>, BreaksBase<-7>> Breaks8;
+//CHECK_BROKEN(8);
diff --git a/3rdparty/pybind11/tests/test_class.py b/3rdparty/pybind11/tests/test_class.py
new file mode 100644
index 00000000..ed63ca85
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_class.py
@@ -0,0 +1,281 @@
+import pytest
+
+from pybind11_tests import class_ as m
+from pybind11_tests import UserType, ConstructorStats
+
+
+def test_repr():
+ # In Python 3.3+, repr() accesses __qualname__
+ assert "pybind11_type" in repr(type(UserType))
+ assert "UserType" in repr(UserType)
+
+
+def test_instance(msg):
+ with pytest.raises(TypeError) as excinfo:
+ m.NoConstructor()
+ assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!"
+
+ instance = m.NoConstructor.new_instance()
+
+ cstats = ConstructorStats.get(m.NoConstructor)
+ assert cstats.alive() == 1
+ del instance
+ assert cstats.alive() == 0
+
+
+def test_docstrings(doc):
+ assert doc(UserType) == "A `py::class_` type for testing"
+ assert UserType.__name__ == "UserType"
+ assert UserType.__module__ == "pybind11_tests"
+ assert UserType.get_value.__name__ == "get_value"
+ assert UserType.get_value.__module__ == "pybind11_tests"
+
+ assert doc(UserType.get_value) == """
+ get_value(self: m.UserType) -> int
+
+ Get value using a method
+ """
+ assert doc(UserType.value) == "Get/set value using a property"
+
+ assert doc(m.NoConstructor.new_instance) == """
+ new_instance() -> m.class_.NoConstructor
+
+ Return an instance
+ """
+
+
+def test_qualname(doc):
+ """Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we
+ backport the attribute) and that generated docstrings properly use it and the module name"""
+ assert m.NestBase.__qualname__ == "NestBase"
+ assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
+
+ assert doc(m.NestBase.__init__) == """
+ __init__(self: m.class_.NestBase) -> None
+ """
+ assert doc(m.NestBase.g) == """
+ g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None
+ """
+ assert doc(m.NestBase.Nested.__init__) == """
+ __init__(self: m.class_.NestBase.Nested) -> None
+ """
+ assert doc(m.NestBase.Nested.fn) == """
+ fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
+ """ # noqa: E501 line too long
+ assert doc(m.NestBase.Nested.fa) == """
+ fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
+ """ # noqa: E501 line too long
+ assert m.NestBase.__module__ == "pybind11_tests.class_"
+ assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
+
+
+def test_inheritance(msg):
+ roger = m.Rabbit('Rabbit')
+ assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
+ assert m.pet_name_species(roger) == "Rabbit is a parrot"
+
+ polly = m.Pet('Polly', 'parrot')
+ assert polly.name() + " is a " + polly.species() == "Polly is a parrot"
+ assert m.pet_name_species(polly) == "Polly is a parrot"
+
+ molly = m.Dog('Molly')
+ assert molly.name() + " is a " + molly.species() == "Molly is a dog"
+ assert m.pet_name_species(molly) == "Molly is a dog"
+
+ fred = m.Hamster('Fred')
+ assert fred.name() + " is a " + fred.species() == "Fred is a rodent"
+
+ assert m.dog_bark(molly) == "Woof!"
+
+ with pytest.raises(TypeError) as excinfo:
+ m.dog_bark(polly)
+ assert msg(excinfo.value) == """
+ dog_bark(): incompatible function arguments. The following argument types are supported:
+ 1. (arg0: m.class_.Dog) -> str
+
+ Invoked with: <m.class_.Pet object at 0>
+ """
+
+ with pytest.raises(TypeError) as excinfo:
+ m.Chimera("lion", "goat")
+ assert "No constructor defined!" in str(excinfo.value)
+
+
+def test_automatic_upcasting():
+ assert type(m.return_class_1()).__name__ == "DerivedClass1"
+ assert type(m.return_class_2()).__name__ == "DerivedClass2"
+ assert type(m.return_none()).__name__ == "NoneType"
+ # Repeat these a few times in a random order to ensure no invalid caching is applied
+ assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
+ assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
+ assert type(m.return_class_n(0)).__name__ == "BaseClass"
+ assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
+ assert type(m.return_class_n(2)).__name__ == "DerivedClass2"
+ assert type(m.return_class_n(0)).__name__ == "BaseClass"
+ assert type(m.return_class_n(1)).__name__ == "DerivedClass1"
+
+
+def test_isinstance():
+ objects = [tuple(), dict(), m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4
+ expected = (True, True, True, True, True, False, False)
+ assert m.check_instances(objects) == expected
+
+
+def test_mismatched_holder():
+ import re
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.mismatched_holder_1()
+ assert re.match('generic_type: type ".*MismatchDerived1" does not have a non-default '
+ 'holder type while its base ".*MismatchBase1" does', str(excinfo.value))
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.mismatched_holder_2()
+ assert re.match('generic_type: type ".*MismatchDerived2" has a non-default holder type '
+ 'while its base ".*MismatchBase2" does not', str(excinfo.value))
+
+
+def test_override_static():
+ """#511: problem with inheritance + overwritten def_static"""
+ b = m.MyBase.make()
+ d1 = m.MyDerived.make2()
+ d2 = m.MyDerived.make()
+
+ assert isinstance(b, m.MyBase)
+ assert isinstance(d1, m.MyDerived)
+ assert isinstance(d2, m.MyDerived)
+
+
+def test_implicit_conversion_life_support():
+ """Ensure the lifetime of temporary objects created for implicit conversions"""
+ assert m.implicitly_convert_argument(UserType(5)) == 5
+ assert m.implicitly_convert_variable(UserType(5)) == 5
+
+ assert "outside a bound function" in m.implicitly_convert_variable_fail(UserType(5))
+
+
+def test_operator_new_delete(capture):
+ """Tests that class-specific operator new/delete functions are invoked"""
+
+ class SubAliased(m.AliasedHasOpNewDelSize):
+ pass
+
+ with capture:
+ a = m.HasOpNewDel()
+ b = m.HasOpNewDelSize()
+ d = m.HasOpNewDelBoth()
+ assert capture == """
+ A new 8
+ B new 4
+ D new 32
+ """
+ sz_alias = str(m.AliasedHasOpNewDelSize.size_alias)
+ sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias)
+ with capture:
+ c = m.AliasedHasOpNewDelSize()
+ c2 = SubAliased()
+ assert capture == (
+ "C new " + sz_noalias + "\n" +
+ "C new " + sz_alias + "\n"
+ )
+
+ with capture:
+ del a
+ pytest.gc_collect()
+ del b
+ pytest.gc_collect()
+ del d
+ pytest.gc_collect()
+ assert capture == """
+ A delete
+ B delete 4
+ D delete
+ """
+
+ with capture:
+ del c
+ pytest.gc_collect()
+ del c2
+ pytest.gc_collect()
+ assert capture == (
+ "C delete " + sz_noalias + "\n" +
+ "C delete " + sz_alias + "\n"
+ )
+
+
+def test_bind_protected_functions():
+ """Expose protected member functions to Python using a helper class"""
+ a = m.ProtectedA()
+ assert a.foo() == 42
+
+ b = m.ProtectedB()
+ assert b.foo() == 42
+
+ class C(m.ProtectedB):
+ def __init__(self):
+ m.ProtectedB.__init__(self)
+
+ def foo(self):
+ return 0
+
+ c = C()
+ assert c.foo() == 0
+
+
+def test_brace_initialization():
+ """ Tests that simple POD classes can be constructed using C++11 brace initialization """
+ a = m.BraceInitialization(123, "test")
+ assert a.field1 == 123
+ assert a.field2 == "test"
+
+ # Tests that a non-simple class doesn't get brace initialization (if the
+ # class defines an initializer_list constructor, in particular, it would
+ # win over the expected constructor).
+ b = m.NoBraceInitialization([123, 456])
+ assert b.vec == [123, 456]
+
+
+@pytest.unsupported_on_pypy
+def test_class_refcount():
+ """Instances must correctly increase/decrease the reference count of their types (#1029)"""
+ from sys import getrefcount
+
+ class PyDog(m.Dog):
+ pass
+
+ for cls in m.Dog, PyDog:
+ refcount_1 = getrefcount(cls)
+ molly = [cls("Molly") for _ in range(10)]
+ refcount_2 = getrefcount(cls)
+
+ del molly
+ pytest.gc_collect()
+ refcount_3 = getrefcount(cls)
+
+ assert refcount_1 == refcount_3
+ assert refcount_2 > refcount_1
+
+
+def test_reentrant_implicit_conversion_failure(msg):
+ # ensure that there is no runaway reentrant implicit conversion (#1035)
+ with pytest.raises(TypeError) as excinfo:
+ m.BogusImplicitConversion(0)
+ assert msg(excinfo.value) == '''
+ __init__(): incompatible constructor arguments. The following argument types are supported:
+ 1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
+
+ Invoked with: 0
+ '''
+
+
+def test_error_after_conversions():
+ with pytest.raises(TypeError) as exc_info:
+ m.test_error_after_conversions("hello")
+ assert str(exc_info.value).startswith(
+ "Unable to convert function return value to a Python type!")
+
+
+def test_aligned():
+ if hasattr(m, "Aligned"):
+ p = m.Aligned().ptr()
+ assert p % 1024 == 0
diff --git a/3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt
new file mode 100644
index 00000000..c9b5fcb2
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt
@@ -0,0 +1,58 @@
+add_custom_target(test_cmake_build)
+
+if(CMAKE_VERSION VERSION_LESS 3.1)
+ # 3.0 needed for interface library for subdirectory_target/installed_target
+ # 3.1 needed for cmake -E env for testing
+ return()
+endif()
+
+include(CMakeParseArguments)
+function(pybind11_add_build_test name)
+ cmake_parse_arguments(ARG "INSTALL" "" "" ${ARGN})
+
+ set(build_options "-DCMAKE_PREFIX_PATH=${PROJECT_BINARY_DIR}/mock_install"
+ "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
+ "-DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE}"
+ "-DPYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}")
+ if(NOT ARG_INSTALL)
+ list(APPEND build_options "-DPYBIND11_PROJECT_DIR=${PROJECT_SOURCE_DIR}")
+ endif()
+
+ add_custom_target(test_${name} ${CMAKE_CTEST_COMMAND}
+ --quiet --output-log ${name}.log
+ --build-and-test "${CMAKE_CURRENT_SOURCE_DIR}/${name}"
+ "${CMAKE_CURRENT_BINARY_DIR}/${name}"
+ --build-config Release
+ --build-noclean
+ --build-generator ${CMAKE_GENERATOR}
+ $<$<BOOL:${CMAKE_GENERATOR_PLATFORM}>:--build-generator-platform> ${CMAKE_GENERATOR_PLATFORM}
+ --build-makeprogram ${CMAKE_MAKE_PROGRAM}
+ --build-target check
+ --build-options ${build_options}
+ )
+ if(ARG_INSTALL)
+ add_dependencies(test_${name} mock_install)
+ endif()
+ add_dependencies(test_cmake_build test_${name})
+endfunction()
+
+pybind11_add_build_test(subdirectory_function)
+pybind11_add_build_test(subdirectory_target)
+if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy")
+ pybind11_add_build_test(subdirectory_embed)
+endif()
+
+if(PYBIND11_INSTALL)
+ add_custom_target(mock_install ${CMAKE_COMMAND}
+ "-DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}/mock_install"
+ -P "${PROJECT_BINARY_DIR}/cmake_install.cmake"
+ )
+
+ pybind11_add_build_test(installed_function INSTALL)
+ pybind11_add_build_test(installed_target INSTALL)
+ if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy")
+ pybind11_add_build_test(installed_embed INSTALL)
+ endif()
+endif()
+
+add_dependencies(check test_cmake_build)
diff --git a/3rdparty/pybind11/tests/test_cmake_build/embed.cpp b/3rdparty/pybind11/tests/test_cmake_build/embed.cpp
new file mode 100644
index 00000000..b9581d2f
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_cmake_build/embed.cpp
@@ -0,0 +1,21 @@
+#include <pybind11/embed.h>
+namespace py = pybind11;
+
+PYBIND11_EMBEDDED_MODULE(test_cmake_build, m) {
+ m.def("add", [](int i, int j) { return i + j; });
+}
+
+int main(int argc, char *argv[]) {
+ if (argc != 2)
+ throw std::runtime_error("Expected test.py file as the first argument");
+ auto test_py_file = argv[1];
+
+ py::scoped_interpreter guard{};
+
+ auto m = py::module::import("test_cmake_build");
+ if (m.attr("add")(1, 2).cast<int>() != 3)
+ throw std::runtime_error("embed.cpp failed");
+
+ py::module::import("sys").attr("argv") = py::make_tuple("test.py", "embed.cpp");
+ py::eval_file(test_py_file, py::globals());
+}
diff --git a/3rdparty/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt
new file mode 100644
index 00000000..f7fc09c2
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.0)
+project(test_installed_embed CXX)
+
+set(CMAKE_MODULE_PATH "")
+find_package(pybind11 CONFIG REQUIRED)
+message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
+
+add_executable(test_cmake_build ../embed.cpp)
+target_link_libraries(test_cmake_build PRIVATE pybind11::embed)
+
+# Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::embed).
+# This may be needed to resolve header conflicts, e.g. between Python release and debug headers.
+set_target_properties(test_cmake_build PROPERTIES NO_SYSTEM_FROM_IMPORTED ON)
+
+add_custom_target(check $<TARGET_FILE:test_cmake_build> ${PROJECT_SOURCE_DIR}/../test.py)
diff --git a/3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt
new file mode 100644
index 00000000..e0c20a8a
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(test_installed_module CXX)
+
+set(CMAKE_MODULE_PATH "")
+
+find_package(pybind11 CONFIG REQUIRED)
+message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
+
+pybind11_add_module(test_cmake_build SHARED NO_EXTRAS ../main.cpp)
+
+add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:test_cmake_build>
+ ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME})
diff --git a/3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt
new file mode 100644
index 00000000..cd3ae6f7
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.0)
+project(test_installed_target CXX)
+
+set(CMAKE_MODULE_PATH "")
+
+find_package(pybind11 CONFIG REQUIRED)
+message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
+
+add_library(test_cmake_build MODULE ../main.cpp)
+
+target_link_libraries(test_cmake_build PRIVATE pybind11::module)
+
+# make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib
+set_target_properties(test_cmake_build PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}"
+ SUFFIX "${PYTHON_MODULE_EXTENSION}")
+
+# Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::module).
+# This may be needed to resolve header conflicts, e.g. between Python release and debug headers.
+set_target_properties(test_cmake_build PROPERTIES NO_SYSTEM_FROM_IMPORTED ON)
+
+add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:test_cmake_build>
+ ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME})
diff --git a/3rdparty/pybind11/tests/test_cmake_build/main.cpp b/3rdparty/pybind11/tests/test_cmake_build/main.cpp
new file mode 100644
index 00000000..e30f2c4b
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_cmake_build/main.cpp
@@ -0,0 +1,6 @@
+#include <pybind11/pybind11.h>
+namespace py = pybind11;
+
+PYBIND11_MODULE(test_cmake_build, m) {
+ m.def("add", [](int i, int j) { return i + j; });
+}
diff --git a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt
new file mode 100644
index 00000000..88ba60dd
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt
@@ -0,0 +1,25 @@
+cmake_minimum_required(VERSION 3.0)
+project(test_subdirectory_embed CXX)
+
+set(PYBIND11_INSTALL ON CACHE BOOL "")
+set(PYBIND11_EXPORT_NAME test_export)
+
+add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11)
+
+# Test basic target functionality
+add_executable(test_cmake_build ../embed.cpp)
+target_link_libraries(test_cmake_build PRIVATE pybind11::embed)
+
+add_custom_target(check $<TARGET_FILE:test_cmake_build> ${PROJECT_SOURCE_DIR}/../test.py)
+
+# Test custom export group -- PYBIND11_EXPORT_NAME
+add_library(test_embed_lib ../embed.cpp)
+target_link_libraries(test_embed_lib PRIVATE pybind11::embed)
+
+install(TARGETS test_embed_lib
+ EXPORT test_export
+ ARCHIVE DESTINATION bin
+ LIBRARY DESTINATION lib
+ RUNTIME DESTINATION lib)
+install(EXPORT test_export
+ DESTINATION lib/cmake/test_export/test_export-Targets.cmake)
diff --git a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt
new file mode 100644
index 00000000..278007ae
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(test_subdirectory_module CXX)
+
+add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11)
+pybind11_add_module(test_cmake_build THIN_LTO ../main.cpp)
+
+add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:test_cmake_build>
+ ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME})
diff --git a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt
new file mode 100644
index 00000000..6b142d62
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.0)
+project(test_subdirectory_target CXX)
+
+add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11)
+
+add_library(test_cmake_build MODULE ../main.cpp)
+
+target_link_libraries(test_cmake_build PRIVATE pybind11::module)
+
+# make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib
+set_target_properties(test_cmake_build PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}"
+ SUFFIX "${PYTHON_MODULE_EXTENSION}")
+
+add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:test_cmake_build>
+ ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME})
diff --git a/3rdparty/pybind11/tests/test_cmake_build/test.py b/3rdparty/pybind11/tests/test_cmake_build/test.py
new file mode 100644
index 00000000..1467a61d
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_cmake_build/test.py
@@ -0,0 +1,5 @@
+import sys
+import test_cmake_build
+
+assert test_cmake_build.add(1, 2) == 3
+print("{} imports, runs, and adds: 1 + 2 = 3".format(sys.argv[1]))
diff --git a/3rdparty/pybind11/tests/test_constants_and_functions.cpp b/3rdparty/pybind11/tests/test_constants_and_functions.cpp
new file mode 100644
index 00000000..e8ec74b7
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_constants_and_functions.cpp
@@ -0,0 +1,127 @@
+/*
+ tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw byte strings
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+enum MyEnum { EFirstEntry = 1, ESecondEntry };
+
+std::string test_function1() {
+ return "test_function()";
+}
+
+std::string test_function2(MyEnum k) {
+ return "test_function(enum=" + std::to_string(k) + ")";
+}
+
+std::string test_function3(int i) {
+ return "test_function(" + std::to_string(i) + ")";
+}
+
+py::str test_function4() { return "test_function()"; }
+py::str test_function4(char *) { return "test_function(char *)"; }
+py::str test_function4(int, float) { return "test_function(int, float)"; }
+py::str test_function4(float, int) { return "test_function(float, int)"; }
+
+py::bytes return_bytes() {
+ const char *data = "\x01\x00\x02\x00";
+ return std::string(data, 4);
+}
+
+std::string print_bytes(py::bytes bytes) {
+ std::string ret = "bytes[";
+ const auto value = static_cast<std::string>(bytes);
+ for (size_t i = 0; i < value.length(); ++i) {
+ ret += std::to_string(static_cast<int>(value[i])) + " ";
+ }
+ ret.back() = ']';
+ return ret;
+}
+
+// Test that we properly handle C++17 exception specifiers (which are part of the function signature
+// in C++17). These should all still work before C++17, but don't affect the function signature.
+namespace test_exc_sp {
+int f1(int x) noexcept { return x+1; }
+int f2(int x) noexcept(true) { return x+2; }
+int f3(int x) noexcept(false) { return x+3; }
+#if defined(__GNUG__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated"
+#endif
+int f4(int x) throw() { return x+4; } // Deprecated equivalent to noexcept(true)
+#if defined(__GNUG__)
+# pragma GCC diagnostic pop
+#endif
+struct C {
+ int m1(int x) noexcept { return x-1; }
+ int m2(int x) const noexcept { return x-2; }
+ int m3(int x) noexcept(true) { return x-3; }
+ int m4(int x) const noexcept(true) { return x-4; }
+ int m5(int x) noexcept(false) { return x-5; }
+ int m6(int x) const noexcept(false) { return x-6; }
+#if defined(__GNUG__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated"
+#endif
+ int m7(int x) throw() { return x-7; }
+ int m8(int x) const throw() { return x-8; }
+#if defined(__GNUG__)
+# pragma GCC diagnostic pop
+#endif
+};
+}
+
+
+TEST_SUBMODULE(constants_and_functions, m) {
+ // test_constants
+ m.attr("some_constant") = py::int_(14);
+
+ // test_function_overloading
+ m.def("test_function", &test_function1);
+ m.def("test_function", &test_function2);
+ m.def("test_function", &test_function3);
+
+#if defined(PYBIND11_OVERLOAD_CAST)
+ m.def("test_function", py::overload_cast<>(&test_function4));
+ m.def("test_function", py::overload_cast<char *>(&test_function4));
+ m.def("test_function", py::overload_cast<int, float>(&test_function4));
+ m.def("test_function", py::overload_cast<float, int>(&test_function4));
+#else
+ m.def("test_function", static_cast<py::str (*)()>(&test_function4));
+ m.def("test_function", static_cast<py::str (*)(char *)>(&test_function4));
+ m.def("test_function", static_cast<py::str (*)(int, float)>(&test_function4));
+ m.def("test_function", static_cast<py::str (*)(float, int)>(&test_function4));
+#endif
+
+ py::enum_<MyEnum>(m, "MyEnum")
+ .value("EFirstEntry", EFirstEntry)
+ .value("ESecondEntry", ESecondEntry)
+ .export_values();
+
+ // test_bytes
+ m.def("return_bytes", &return_bytes);
+ m.def("print_bytes", &print_bytes);
+
+ // test_exception_specifiers
+ using namespace test_exc_sp;
+ py::class_<C>(m, "C")
+ .def(py::init<>())
+ .def("m1", &C::m1)
+ .def("m2", &C::m2)
+ .def("m3", &C::m3)
+ .def("m4", &C::m4)
+ .def("m5", &C::m5)
+ .def("m6", &C::m6)
+ .def("m7", &C::m7)
+ .def("m8", &C::m8)
+ ;
+ m.def("f1", f1);
+ m.def("f2", f2);
+ m.def("f3", f3);
+ m.def("f4", f4);
+}
diff --git a/3rdparty/pybind11/tests/test_constants_and_functions.py b/3rdparty/pybind11/tests/test_constants_and_functions.py
new file mode 100644
index 00000000..472682d6
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_constants_and_functions.py
@@ -0,0 +1,39 @@
+from pybind11_tests import constants_and_functions as m
+
+
+def test_constants():
+ assert m.some_constant == 14
+
+
+def test_function_overloading():
+ assert m.test_function() == "test_function()"
+ assert m.test_function(7) == "test_function(7)"
+ assert m.test_function(m.MyEnum.EFirstEntry) == "test_function(enum=1)"
+ assert m.test_function(m.MyEnum.ESecondEntry) == "test_function(enum=2)"
+
+ assert m.test_function() == "test_function()"
+ assert m.test_function("abcd") == "test_function(char *)"
+ assert m.test_function(1, 1.0) == "test_function(int, float)"
+ assert m.test_function(1, 1.0) == "test_function(int, float)"
+ assert m.test_function(2.0, 2) == "test_function(float, int)"
+
+
+def test_bytes():
+ assert m.print_bytes(m.return_bytes()) == "bytes[1 0 2 0]"
+
+
+def test_exception_specifiers():
+ c = m.C()
+ assert c.m1(2) == 1
+ assert c.m2(3) == 1
+ assert c.m3(5) == 2
+ assert c.m4(7) == 3
+ assert c.m5(10) == 5
+ assert c.m6(14) == 8
+ assert c.m7(20) == 13
+ assert c.m8(29) == 21
+
+ assert m.f1(33) == 34
+ assert m.f2(53) == 55
+ assert m.f3(86) == 89
+ assert m.f4(140) == 144
diff --git a/3rdparty/pybind11/tests/test_copy_move.cpp b/3rdparty/pybind11/tests/test_copy_move.cpp
new file mode 100644
index 00000000..98d5e0a0
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_copy_move.cpp
@@ -0,0 +1,213 @@
+/*
+ tests/test_copy_move_policies.cpp -- 'copy' and 'move' return value policies
+ and related tests
+
+ Copyright (c) 2016 Ben North <ben@redfrontdoor.org>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/stl.h>
+
+template <typename derived>
+struct empty {
+ static const derived& get_one() { return instance_; }
+ static derived instance_;
+};
+
+struct lacking_copy_ctor : public empty<lacking_copy_ctor> {
+ lacking_copy_ctor() {}
+ lacking_copy_ctor(const lacking_copy_ctor& other) = delete;
+};
+
+template <> lacking_copy_ctor empty<lacking_copy_ctor>::instance_ = {};
+
+struct lacking_move_ctor : public empty<lacking_move_ctor> {
+ lacking_move_ctor() {}
+ lacking_move_ctor(const lacking_move_ctor& other) = delete;
+ lacking_move_ctor(lacking_move_ctor&& other) = delete;
+};
+
+template <> lacking_move_ctor empty<lacking_move_ctor>::instance_ = {};
+
+/* Custom type caster move/copy test classes */
+class MoveOnlyInt {
+public:
+ MoveOnlyInt() { print_default_created(this); }
+ MoveOnlyInt(int v) : value{std::move(v)} { print_created(this, value); }
+ MoveOnlyInt(MoveOnlyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); }
+ MoveOnlyInt &operator=(MoveOnlyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; }
+ MoveOnlyInt(const MoveOnlyInt &) = delete;
+ MoveOnlyInt &operator=(const MoveOnlyInt &) = delete;
+ ~MoveOnlyInt() { print_destroyed(this); }
+
+ int value;
+};
+class MoveOrCopyInt {
+public:
+ MoveOrCopyInt() { print_default_created(this); }
+ MoveOrCopyInt(int v) : value{std::move(v)} { print_created(this, value); }
+ MoveOrCopyInt(MoveOrCopyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); }
+ MoveOrCopyInt &operator=(MoveOrCopyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; }
+ MoveOrCopyInt(const MoveOrCopyInt &c) { print_copy_created(this, c.value); value = c.value; }
+ MoveOrCopyInt &operator=(const MoveOrCopyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; }
+ ~MoveOrCopyInt() { print_destroyed(this); }
+
+ int value;
+};
+class CopyOnlyInt {
+public:
+ CopyOnlyInt() { print_default_created(this); }
+ CopyOnlyInt(int v) : value{std::move(v)} { print_created(this, value); }
+ CopyOnlyInt(const CopyOnlyInt &c) { print_copy_created(this, c.value); value = c.value; }
+ CopyOnlyInt &operator=(const CopyOnlyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; }
+ ~CopyOnlyInt() { print_destroyed(this); }
+
+ int value;
+};
+NAMESPACE_BEGIN(pybind11)
+NAMESPACE_BEGIN(detail)
+template <> struct type_caster<MoveOnlyInt> {
+ PYBIND11_TYPE_CASTER(MoveOnlyInt, _("MoveOnlyInt"));
+ bool load(handle src, bool) { value = MoveOnlyInt(src.cast<int>()); return true; }
+ static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); }
+};
+
+template <> struct type_caster<MoveOrCopyInt> {
+ PYBIND11_TYPE_CASTER(MoveOrCopyInt, _("MoveOrCopyInt"));
+ bool load(handle src, bool) { value = MoveOrCopyInt(src.cast<int>()); return true; }
+ static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); }
+};
+
+template <> struct type_caster<CopyOnlyInt> {
+protected:
+ CopyOnlyInt value;
+public:
+ static constexpr auto name = _("CopyOnlyInt");
+ bool load(handle src, bool) { value = CopyOnlyInt(src.cast<int>()); return true; }
+ static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); }
+ static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) {
+ if (!src) return none().release();
+ return cast(*src, policy, parent);
+ }
+ operator CopyOnlyInt*() { return &value; }
+ operator CopyOnlyInt&() { return value; }
+ template <typename T> using cast_op_type = pybind11::detail::cast_op_type<T>;
+};
+NAMESPACE_END(detail)
+NAMESPACE_END(pybind11)
+
+TEST_SUBMODULE(copy_move_policies, m) {
+ // test_lacking_copy_ctor
+ py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
+ .def_static("get_one", &lacking_copy_ctor::get_one,
+ py::return_value_policy::copy);
+ // test_lacking_move_ctor
+ py::class_<lacking_move_ctor>(m, "lacking_move_ctor")
+ .def_static("get_one", &lacking_move_ctor::get_one,
+ py::return_value_policy::move);
+
+ // test_move_and_copy_casts
+ m.def("move_and_copy_casts", [](py::object o) {
+ int r = 0;
+ r += py::cast<MoveOrCopyInt>(o).value; /* moves */
+ r += py::cast<MoveOnlyInt>(o).value; /* moves */
+ r += py::cast<CopyOnlyInt>(o).value; /* copies */
+ MoveOrCopyInt m1(py::cast<MoveOrCopyInt>(o)); /* moves */
+ MoveOnlyInt m2(py::cast<MoveOnlyInt>(o)); /* moves */
+ CopyOnlyInt m3(py::cast<CopyOnlyInt>(o)); /* copies */
+ r += m1.value + m2.value + m3.value;
+
+ return r;
+ });
+
+ // test_move_and_copy_loads
+ m.def("move_only", [](MoveOnlyInt m) { return m.value; });
+ m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; });
+ m.def("copy_only", [](CopyOnlyInt m) { return m.value; });
+ m.def("move_pair", [](std::pair<MoveOnlyInt, MoveOrCopyInt> p) {
+ return p.first.value + p.second.value;
+ });
+ m.def("move_tuple", [](std::tuple<MoveOnlyInt, MoveOrCopyInt, MoveOnlyInt> t) {
+ return std::get<0>(t).value + std::get<1>(t).value + std::get<2>(t).value;
+ });
+ m.def("copy_tuple", [](std::tuple<CopyOnlyInt, CopyOnlyInt> t) {
+ return std::get<0>(t).value + std::get<1>(t).value;
+ });
+ m.def("move_copy_nested", [](std::pair<MoveOnlyInt, std::pair<std::tuple<MoveOrCopyInt, CopyOnlyInt, std::tuple<MoveOnlyInt>>, MoveOrCopyInt>> x) {
+ return x.first.value + std::get<0>(x.second.first).value + std::get<1>(x.second.first).value +
+ std::get<0>(std::get<2>(x.second.first)).value + x.second.second.value;
+ });
+ m.def("move_and_copy_cstats", []() {
+ ConstructorStats::gc();
+ // Reset counts to 0 so that previous tests don't affect later ones:
+ auto &mc = ConstructorStats::get<MoveOrCopyInt>();
+ mc.move_assignments = mc.move_constructions = mc.copy_assignments = mc.copy_constructions = 0;
+ auto &mo = ConstructorStats::get<MoveOnlyInt>();
+ mo.move_assignments = mo.move_constructions = mo.copy_assignments = mo.copy_constructions = 0;
+ auto &co = ConstructorStats::get<CopyOnlyInt>();
+ co.move_assignments = co.move_constructions = co.copy_assignments = co.copy_constructions = 0;
+ py::dict d;
+ d["MoveOrCopyInt"] = py::cast(mc, py::return_value_policy::reference);
+ d["MoveOnlyInt"] = py::cast(mo, py::return_value_policy::reference);
+ d["CopyOnlyInt"] = py::cast(co, py::return_value_policy::reference);
+ return d;
+ });
+#ifdef PYBIND11_HAS_OPTIONAL
+ // test_move_and_copy_load_optional
+ m.attr("has_optional") = true;
+ m.def("move_optional", [](std::optional<MoveOnlyInt> o) {
+ return o->value;
+ });
+ m.def("move_or_copy_optional", [](std::optional<MoveOrCopyInt> o) {
+ return o->value;
+ });
+ m.def("copy_optional", [](std::optional<CopyOnlyInt> o) {
+ return o->value;
+ });
+ m.def("move_optional_tuple", [](std::optional<std::tuple<MoveOrCopyInt, MoveOnlyInt, CopyOnlyInt>> x) {
+ return std::get<0>(*x).value + std::get<1>(*x).value + std::get<2>(*x).value;
+ });
+#else
+ m.attr("has_optional") = false;
+#endif
+
+ // #70 compilation issue if operator new is not public
+ struct PrivateOpNew {
+ int value = 1;
+ private:
+#if defined(_MSC_VER)
+# pragma warning(disable: 4822) // warning C4822: local class member function does not have a body
+#endif
+ void *operator new(size_t bytes);
+ };
+ py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
+ m.def("private_op_new_value", []() { return PrivateOpNew(); });
+ m.def("private_op_new_reference", []() -> const PrivateOpNew & {
+ static PrivateOpNew x{};
+ return x;
+ }, py::return_value_policy::reference);
+
+ // test_move_fallback
+ // #389: rvp::move should fall-through to copy on non-movable objects
+ struct MoveIssue1 {
+ int v;
+ MoveIssue1(int v) : v{v} {}
+ MoveIssue1(const MoveIssue1 &c) = default;
+ MoveIssue1(MoveIssue1 &&) = delete;
+ };
+ py::class_<MoveIssue1>(m, "MoveIssue1").def(py::init<int>()).def_readwrite("value", &MoveIssue1::v);
+
+ struct MoveIssue2 {
+ int v;
+ MoveIssue2(int v) : v{v} {}
+ MoveIssue2(MoveIssue2 &&) = default;
+ };
+ py::class_<MoveIssue2>(m, "MoveIssue2").def(py::init<int>()).def_readwrite("value", &MoveIssue2::v);
+
+ m.def("get_moveissue1", [](int i) { return new MoveIssue1(i); }, py::return_value_policy::move);
+ m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
+}
diff --git a/3rdparty/pybind11/tests/test_copy_move.py b/3rdparty/pybind11/tests/test_copy_move.py
new file mode 100644
index 00000000..0e671d96
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_copy_move.py
@@ -0,0 +1,112 @@
+import pytest
+from pybind11_tests import copy_move_policies as m
+
+
+def test_lacking_copy_ctor():
+ with pytest.raises(RuntimeError) as excinfo:
+ m.lacking_copy_ctor.get_one()
+ assert "is non-copyable!" in str(excinfo.value)
+
+
+def test_lacking_move_ctor():
+ with pytest.raises(RuntimeError) as excinfo:
+ m.lacking_move_ctor.get_one()
+ assert "is neither movable nor copyable!" in str(excinfo.value)
+
+
+def test_move_and_copy_casts():
+ """Cast some values in C++ via custom type casters and count the number of moves/copies."""
+
+ cstats = m.move_and_copy_cstats()
+ c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"]
+
+ # The type move constructions/assignments below each get incremented: the move assignment comes
+ # from the type_caster load; the move construction happens when extracting that via a cast or
+ # loading into an argument.
+ assert m.move_and_copy_casts(3) == 18
+ assert c_m.copy_assignments + c_m.copy_constructions == 0
+ assert c_m.move_assignments == 2
+ assert c_m.move_constructions >= 2
+ assert c_mc.alive() == 0
+ assert c_mc.copy_assignments + c_mc.copy_constructions == 0
+ assert c_mc.move_assignments == 2
+ assert c_mc.move_constructions >= 2
+ assert c_c.alive() == 0
+ assert c_c.copy_assignments == 2
+ assert c_c.copy_constructions >= 2
+ assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
+
+
+def test_move_and_copy_loads():
+ """Call some functions that load arguments via custom type casters and count the number of
+ moves/copies."""
+
+ cstats = m.move_and_copy_cstats()
+ c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"]
+
+ assert m.move_only(10) == 10 # 1 move, c_m
+ assert m.move_or_copy(11) == 11 # 1 move, c_mc
+ assert m.copy_only(12) == 12 # 1 copy, c_c
+ assert m.move_pair((13, 14)) == 27 # 1 c_m move, 1 c_mc move
+ assert m.move_tuple((15, 16, 17)) == 48 # 2 c_m moves, 1 c_mc move
+ assert m.copy_tuple((18, 19)) == 37 # 2 c_c copies
+ # Direct constructions: 2 c_m moves, 2 c_mc moves, 1 c_c copy
+ # Extra moves/copies when moving pairs/tuples: 3 c_m, 3 c_mc, 2 c_c
+ assert m.move_copy_nested((1, ((2, 3, (4,)), 5))) == 15
+
+ assert c_m.copy_assignments + c_m.copy_constructions == 0
+ assert c_m.move_assignments == 6
+ assert c_m.move_constructions == 9
+ assert c_mc.copy_assignments + c_mc.copy_constructions == 0
+ assert c_mc.move_assignments == 5
+ assert c_mc.move_constructions == 8
+ assert c_c.copy_assignments == 4
+ assert c_c.copy_constructions == 6
+ assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
+
+
+@pytest.mark.skipif(not m.has_optional, reason='no <optional>')
+def test_move_and_copy_load_optional():
+ """Tests move/copy loads of std::optional arguments"""
+
+ cstats = m.move_and_copy_cstats()
+ c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"]
+
+ # The extra move/copy constructions below come from the std::optional move (which has to move
+ # its arguments):
+ assert m.move_optional(10) == 10 # c_m: 1 move assign, 2 move construct
+ assert m.move_or_copy_optional(11) == 11 # c_mc: 1 move assign, 2 move construct
+ assert m.copy_optional(12) == 12 # c_c: 1 copy assign, 2 copy construct
+ # 1 move assign + move construct moves each of c_m, c_mc, 1 c_c copy
+ # +1 move/copy construct each from moving the tuple
+ # +1 move/copy construct each from moving the optional (which moves the tuple again)
+ assert m.move_optional_tuple((3, 4, 5)) == 12
+
+ assert c_m.copy_assignments + c_m.copy_constructions == 0
+ assert c_m.move_assignments == 2
+ assert c_m.move_constructions == 5
+ assert c_mc.copy_assignments + c_mc.copy_constructions == 0
+ assert c_mc.move_assignments == 2
+ assert c_mc.move_constructions == 5
+ assert c_c.copy_assignments == 2
+ assert c_c.copy_constructions == 5
+ assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
+
+
+def test_private_op_new():
+ """An object with a private `operator new` cannot be returned by value"""
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.private_op_new_value()
+ assert "is neither movable nor copyable" in str(excinfo.value)
+
+ assert m.private_op_new_reference().value == 1
+
+
+def test_move_fallback():
+ """#389: rvp::move should fall-through to copy on non-movable objects"""
+
+ m2 = m.get_moveissue2(2)
+ assert m2.value == 2
+ m1 = m.get_moveissue1(1)
+ assert m1.value == 1
diff --git a/3rdparty/pybind11/tests/test_docstring_options.cpp b/3rdparty/pybind11/tests/test_docstring_options.cpp
new file mode 100644
index 00000000..8c8f79fd
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_docstring_options.cpp
@@ -0,0 +1,61 @@
+/*
+ tests/test_docstring_options.cpp -- generation of docstrings and signatures
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+TEST_SUBMODULE(docstring_options, m) {
+ // test_docstring_options
+ {
+ py::options options;
+ options.disable_function_signatures();
+
+ m.def("test_function1", [](int, int) {}, py::arg("a"), py::arg("b"));
+ m.def("test_function2", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
+
+ m.def("test_overloaded1", [](int) {}, py::arg("i"), "Overload docstring");
+ m.def("test_overloaded1", [](double) {}, py::arg("d"));
+
+ m.def("test_overloaded2", [](int) {}, py::arg("i"), "overload docstring 1");
+ m.def("test_overloaded2", [](double) {}, py::arg("d"), "overload docstring 2");
+
+ m.def("test_overloaded3", [](int) {}, py::arg("i"));
+ m.def("test_overloaded3", [](double) {}, py::arg("d"), "Overload docstr");
+
+ options.enable_function_signatures();
+
+ m.def("test_function3", [](int, int) {}, py::arg("a"), py::arg("b"));
+ m.def("test_function4", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
+
+ options.disable_function_signatures().disable_user_defined_docstrings();
+
+ m.def("test_function5", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
+
+ {
+ py::options nested_options;
+ nested_options.enable_user_defined_docstrings();
+ m.def("test_function6", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
+ }
+ }
+
+ m.def("test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
+
+ {
+ py::options options;
+ options.disable_user_defined_docstrings();
+
+ struct DocstringTestFoo {
+ int value;
+ void setValue(int v) { value = v; }
+ int getValue() const { return value; }
+ };
+ py::class_<DocstringTestFoo>(m, "DocstringTestFoo", "This is a class docstring")
+ .def_property("value_prop", &DocstringTestFoo::getValue, &DocstringTestFoo::setValue, "This is a property docstring")
+ ;
+ }
+}
diff --git a/3rdparty/pybind11/tests/test_docstring_options.py b/3rdparty/pybind11/tests/test_docstring_options.py
new file mode 100644
index 00000000..0dbca609
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_docstring_options.py
@@ -0,0 +1,38 @@
+from pybind11_tests import docstring_options as m
+
+
+def test_docstring_options():
+ # options.disable_function_signatures()
+ assert not m.test_function1.__doc__
+
+ assert m.test_function2.__doc__ == "A custom docstring"
+
+ # docstring specified on just the first overload definition:
+ assert m.test_overloaded1.__doc__ == "Overload docstring"
+
+ # docstring on both overloads:
+ assert m.test_overloaded2.__doc__ == "overload docstring 1\noverload docstring 2"
+
+ # docstring on only second overload:
+ assert m.test_overloaded3.__doc__ == "Overload docstr"
+
+ # options.enable_function_signatures()
+ assert m.test_function3.__doc__ .startswith("test_function3(a: int, b: int) -> None")
+
+ assert m.test_function4.__doc__ .startswith("test_function4(a: int, b: int) -> None")
+ assert m.test_function4.__doc__ .endswith("A custom docstring\n")
+
+ # options.disable_function_signatures()
+ # options.disable_user_defined_docstrings()
+ assert not m.test_function5.__doc__
+
+ # nested options.enable_user_defined_docstrings()
+ assert m.test_function6.__doc__ == "A custom docstring"
+
+ # RAII destructor
+ assert m.test_function7.__doc__ .startswith("test_function7(a: int, b: int) -> None")
+ assert m.test_function7.__doc__ .endswith("A custom docstring\n")
+
+ # Suppression of user-defined docstrings for non-function objects
+ assert not m.DocstringTestFoo.__doc__
+ assert not m.DocstringTestFoo.value_prop.__doc__
diff --git a/3rdparty/pybind11/tests/test_eigen.cpp b/3rdparty/pybind11/tests/test_eigen.cpp
new file mode 100644
index 00000000..aba088d7
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_eigen.cpp
@@ -0,0 +1,329 @@
+/*
+ tests/eigen.cpp -- automatic conversion of Eigen types
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/eigen.h>
+#include <pybind11/stl.h>
+
+#if defined(_MSC_VER)
+# pragma warning(disable: 4996) // C4996: std::unary_negation is deprecated
+#endif
+
+#include <Eigen/Cholesky>
+
+using MatrixXdR = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
+
+
+
+// Sets/resets a testing reference matrix to have values of 10*r + c, where r and c are the
+// (1-based) row/column number.
+template <typename M> void reset_ref(M &x) {
+ for (int i = 0; i < x.rows(); i++) for (int j = 0; j < x.cols(); j++)
+ x(i, j) = 11 + 10*i + j;
+}
+
+// Returns a static, column-major matrix
+Eigen::MatrixXd &get_cm() {
+ static Eigen::MatrixXd *x;
+ if (!x) {
+ x = new Eigen::MatrixXd(3, 3);
+ reset_ref(*x);
+ }
+ return *x;
+}
+// Likewise, but row-major
+MatrixXdR &get_rm() {
+ static MatrixXdR *x;
+ if (!x) {
+ x = new MatrixXdR(3, 3);
+ reset_ref(*x);
+ }
+ return *x;
+}
+// Resets the values of the static matrices returned by get_cm()/get_rm()
+void reset_refs() {
+ reset_ref(get_cm());
+ reset_ref(get_rm());
+}
+
+// Returns element 2,1 from a matrix (used to test copy/nocopy)
+double get_elem(Eigen::Ref<const Eigen::MatrixXd> m) { return m(2, 1); };
+
+
+// Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix
+// reference is referencing rows/columns correctly).
+template <typename MatrixArgType> Eigen::MatrixXd adjust_matrix(MatrixArgType m) {
+ Eigen::MatrixXd ret(m);
+ for (int c = 0; c < m.cols(); c++) for (int r = 0; r < m.rows(); r++)
+ ret(r, c) += 10*r + 100*c;
+ return ret;
+}
+
+struct CustomOperatorNew {
+ CustomOperatorNew() = default;
+
+ Eigen::Matrix4d a = Eigen::Matrix4d::Zero();
+ Eigen::Matrix4d b = Eigen::Matrix4d::Identity();
+
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
+};
+
+TEST_SUBMODULE(eigen, m) {
+ using FixedMatrixR = Eigen::Matrix<float, 5, 6, Eigen::RowMajor>;
+ using FixedMatrixC = Eigen::Matrix<float, 5, 6>;
+ using DenseMatrixR = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
+ using DenseMatrixC = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic>;
+ using FourRowMatrixC = Eigen::Matrix<float, 4, Eigen::Dynamic>;
+ using FourColMatrixC = Eigen::Matrix<float, Eigen::Dynamic, 4>;
+ using FourRowMatrixR = Eigen::Matrix<float, 4, Eigen::Dynamic>;
+ using FourColMatrixR = Eigen::Matrix<float, Eigen::Dynamic, 4>;
+ using SparseMatrixR = Eigen::SparseMatrix<float, Eigen::RowMajor>;
+ using SparseMatrixC = Eigen::SparseMatrix<float>;
+
+ m.attr("have_eigen") = true;
+
+ // various tests
+ m.def("double_col", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2.0f * x; });
+ m.def("double_row", [](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2.0f * x; });
+ m.def("double_complex", [](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; });
+ m.def("double_threec", [](py::EigenDRef<Eigen::Vector3f> x) { x *= 2; });
+ m.def("double_threer", [](py::EigenDRef<Eigen::RowVector3f> x) { x *= 2; });
+ m.def("double_mat_cm", [](Eigen::MatrixXf x) -> Eigen::MatrixXf { return 2.0f * x; });
+ m.def("double_mat_rm", [](DenseMatrixR x) -> DenseMatrixR { return 2.0f * x; });
+
+ // test_eigen_ref_to_python
+ // Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended
+ m.def("cholesky1", [](Eigen::Ref<MatrixXdR> x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
+ m.def("cholesky2", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
+ m.def("cholesky3", [](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
+ m.def("cholesky4", [](Eigen::Ref<const MatrixXdR> x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
+
+ // test_eigen_ref_mutators
+ // Mutators: these add some value to the given element using Eigen, but Eigen should be mapping into
+ // the numpy array data and so the result should show up there. There are three versions: one that
+ // works on a contiguous-row matrix (numpy's default), one for a contiguous-column matrix, and one
+ // for any matrix.
+ auto add_rm = [](Eigen::Ref<MatrixXdR> x, int r, int c, double v) { x(r,c) += v; };
+ auto add_cm = [](Eigen::Ref<Eigen::MatrixXd> x, int r, int c, double v) { x(r,c) += v; };
+
+ // Mutators (Eigen maps into numpy variables):
+ m.def("add_rm", add_rm); // Only takes row-contiguous
+ m.def("add_cm", add_cm); // Only takes column-contiguous
+ // Overloaded versions that will accept either row or column contiguous:
+ m.def("add1", add_rm);
+ m.def("add1", add_cm);
+ m.def("add2", add_cm);
+ m.def("add2", add_rm);
+ // This one accepts a matrix of any stride:
+ m.def("add_any", [](py::EigenDRef<Eigen::MatrixXd> x, int r, int c, double v) { x(r,c) += v; });
+
+ // Return mutable references (numpy maps into eigen variables)
+ m.def("get_cm_ref", []() { return Eigen::Ref<Eigen::MatrixXd>(get_cm()); });
+ m.def("get_rm_ref", []() { return Eigen::Ref<MatrixXdR>(get_rm()); });
+ // The same references, but non-mutable (numpy maps into eigen variables, but is !writeable)
+ m.def("get_cm_const_ref", []() { return Eigen::Ref<const Eigen::MatrixXd>(get_cm()); });
+ m.def("get_rm_const_ref", []() { return Eigen::Ref<const MatrixXdR>(get_rm()); });
+
+ m.def("reset_refs", reset_refs); // Restores get_{cm,rm}_ref to original values
+
+ // Increments and returns ref to (same) matrix
+ m.def("incr_matrix", [](Eigen::Ref<Eigen::MatrixXd> m, double v) {
+ m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v);
+ return m;
+ }, py::return_value_policy::reference);
+
+ // Same, but accepts a matrix of any strides
+ m.def("incr_matrix_any", [](py::EigenDRef<Eigen::MatrixXd> m, double v) {
+ m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v);
+ return m;
+ }, py::return_value_policy::reference);
+
+ // Returns an eigen slice of even rows
+ m.def("even_rows", [](py::EigenDRef<Eigen::MatrixXd> m) {
+ return py::EigenDMap<Eigen::MatrixXd>(
+ m.data(), (m.rows() + 1) / 2, m.cols(),
+ py::EigenDStride(m.outerStride(), 2 * m.innerStride()));
+ }, py::return_value_policy::reference);
+
+ // Returns an eigen slice of even columns
+ m.def("even_cols", [](py::EigenDRef<Eigen::MatrixXd> m) {
+ return py::EigenDMap<Eigen::MatrixXd>(
+ m.data(), m.rows(), (m.cols() + 1) / 2,
+ py::EigenDStride(2 * m.outerStride(), m.innerStride()));
+ }, py::return_value_policy::reference);
+
+ // Returns diagonals: a vector-like object with an inner stride != 1
+ m.def("diagonal", [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal(); });
+ m.def("diagonal_1", [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal<1>(); });
+ m.def("diagonal_n", [](const Eigen::Ref<const Eigen::MatrixXd> &x, int index) { return x.diagonal(index); });
+
+ // Return a block of a matrix (gives non-standard strides)
+ m.def("block", [](const Eigen::Ref<const Eigen::MatrixXd> &x, int start_row, int start_col, int block_rows, int block_cols) {
+ return x.block(start_row, start_col, block_rows, block_cols);
+ });
+
+ // test_eigen_return_references, test_eigen_keepalive
+ // return value referencing/copying tests:
+ class ReturnTester {
+ Eigen::MatrixXd mat = create();
+ public:
+ ReturnTester() { print_created(this); }
+ ~ReturnTester() { print_destroyed(this); }
+ static Eigen::MatrixXd create() { return Eigen::MatrixXd::Ones(10, 10); }
+ static const Eigen::MatrixXd createConst() { return Eigen::MatrixXd::Ones(10, 10); }
+ Eigen::MatrixXd &get() { return mat; }
+ Eigen::MatrixXd *getPtr() { return &mat; }
+ const Eigen::MatrixXd &view() { return mat; }
+ const Eigen::MatrixXd *viewPtr() { return &mat; }
+ Eigen::Ref<Eigen::MatrixXd> ref() { return mat; }
+ Eigen::Ref<const Eigen::MatrixXd> refConst() { return mat; }
+ Eigen::Block<Eigen::MatrixXd> block(int r, int c, int nrow, int ncol) { return mat.block(r, c, nrow, ncol); }
+ Eigen::Block<const Eigen::MatrixXd> blockConst(int r, int c, int nrow, int ncol) const { return mat.block(r, c, nrow, ncol); }
+ py::EigenDMap<Eigen::Matrix2d> corners() { return py::EigenDMap<Eigen::Matrix2d>(mat.data(),
+ py::EigenDStride(mat.outerStride() * (mat.outerSize()-1), mat.innerStride() * (mat.innerSize()-1))); }
+ py::EigenDMap<const Eigen::Matrix2d> cornersConst() const { return py::EigenDMap<const Eigen::Matrix2d>(mat.data(),
+ py::EigenDStride(mat.outerStride() * (mat.outerSize()-1), mat.innerStride() * (mat.innerSize()-1))); }
+ };
+ using rvp = py::return_value_policy;
+ py::class_<ReturnTester>(m, "ReturnTester")
+ .def(py::init<>())
+ .def_static("create", &ReturnTester::create)
+ .def_static("create_const", &ReturnTester::createConst)
+ .def("get", &ReturnTester::get, rvp::reference_internal)
+ .def("get_ptr", &ReturnTester::getPtr, rvp::reference_internal)
+ .def("view", &ReturnTester::view, rvp::reference_internal)
+ .def("view_ptr", &ReturnTester::view, rvp::reference_internal)
+ .def("copy_get", &ReturnTester::get) // Default rvp: copy
+ .def("copy_view", &ReturnTester::view) // "
+ .def("ref", &ReturnTester::ref) // Default for Ref is to reference
+ .def("ref_const", &ReturnTester::refConst) // Likewise, but const
+ .def("ref_safe", &ReturnTester::ref, rvp::reference_internal)
+ .def("ref_const_safe", &ReturnTester::refConst, rvp::reference_internal)
+ .def("copy_ref", &ReturnTester::ref, rvp::copy)
+ .def("copy_ref_const", &ReturnTester::refConst, rvp::copy)
+ .def("block", &ReturnTester::block)
+ .def("block_safe", &ReturnTester::block, rvp::reference_internal)
+ .def("block_const", &ReturnTester::blockConst, rvp::reference_internal)
+ .def("copy_block", &ReturnTester::block, rvp::copy)
+ .def("corners", &ReturnTester::corners, rvp::reference_internal)
+ .def("corners_const", &ReturnTester::cornersConst, rvp::reference_internal)
+ ;
+
+ // test_special_matrix_objects
+ // Returns a DiagonalMatrix with diagonal (1,2,3,...)
+ m.def("incr_diag", [](int k) {
+ Eigen::DiagonalMatrix<int, Eigen::Dynamic> m(k);
+ for (int i = 0; i < k; i++) m.diagonal()[i] = i+1;
+ return m;
+ });
+
+ // Returns a SelfAdjointView referencing the lower triangle of m
+ m.def("symmetric_lower", [](const Eigen::MatrixXi &m) {
+ return m.selfadjointView<Eigen::Lower>();
+ });
+ // Returns a SelfAdjointView referencing the lower triangle of m
+ m.def("symmetric_upper", [](const Eigen::MatrixXi &m) {
+ return m.selfadjointView<Eigen::Upper>();
+ });
+
+ // Test matrix for various functions below.
+ Eigen::MatrixXf mat(5, 6);
+ mat << 0, 3, 0, 0, 0, 11,
+ 22, 0, 0, 0, 17, 11,
+ 7, 5, 0, 1, 0, 11,
+ 0, 0, 0, 0, 0, 11,
+ 0, 0, 14, 0, 8, 11;
+
+ // test_fixed, and various other tests
+ m.def("fixed_r", [mat]() -> FixedMatrixR { return FixedMatrixR(mat); });
+ m.def("fixed_r_const", [mat]() -> const FixedMatrixR { return FixedMatrixR(mat); });
+ m.def("fixed_c", [mat]() -> FixedMatrixC { return FixedMatrixC(mat); });
+ m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; });
+ m.def("fixed_copy_c", [](const FixedMatrixC &m) -> FixedMatrixC { return m; });
+ // test_mutator_descriptors
+ m.def("fixed_mutator_r", [](Eigen::Ref<FixedMatrixR>) {});
+ m.def("fixed_mutator_c", [](Eigen::Ref<FixedMatrixC>) {});
+ m.def("fixed_mutator_a", [](py::EigenDRef<FixedMatrixC>) {});
+ // test_dense
+ m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); });
+ m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); });
+ m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; });
+ m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; });
+ // test_sparse, test_sparse_signature
+ m.def("sparse_r", [mat]() -> SparseMatrixR { return Eigen::SparseView<Eigen::MatrixXf>(mat); });
+ m.def("sparse_c", [mat]() -> SparseMatrixC { return Eigen::SparseView<Eigen::MatrixXf>(mat); });
+ m.def("sparse_copy_r", [](const SparseMatrixR &m) -> SparseMatrixR { return m; });
+ m.def("sparse_copy_c", [](const SparseMatrixC &m) -> SparseMatrixC { return m; });
+ // test_partially_fixed
+ m.def("partial_copy_four_rm_r", [](const FourRowMatrixR &m) -> FourRowMatrixR { return m; });
+ m.def("partial_copy_four_rm_c", [](const FourColMatrixR &m) -> FourColMatrixR { return m; });
+ m.def("partial_copy_four_cm_r", [](const FourRowMatrixC &m) -> FourRowMatrixC { return m; });
+ m.def("partial_copy_four_cm_c", [](const FourColMatrixC &m) -> FourColMatrixC { return m; });
+
+ // test_cpp_casting
+ // Test that we can cast a numpy object to a Eigen::MatrixXd explicitly
+ m.def("cpp_copy", [](py::handle m) { return m.cast<Eigen::MatrixXd>()(1, 0); });
+ m.def("cpp_ref_c", [](py::handle m) { return m.cast<Eigen::Ref<Eigen::MatrixXd>>()(1, 0); });
+ m.def("cpp_ref_r", [](py::handle m) { return m.cast<Eigen::Ref<MatrixXdR>>()(1, 0); });
+ m.def("cpp_ref_any", [](py::handle m) { return m.cast<py::EigenDRef<Eigen::MatrixXd>>()(1, 0); });
+
+
+ // test_nocopy_wrapper
+ // Test that we can prevent copying into an argument that would normally copy: First a version
+ // that would allow copying (if types or strides don't match) for comparison:
+ m.def("get_elem", &get_elem);
+ // Now this alternative that calls the tells pybind to fail rather than copy:
+ m.def("get_elem_nocopy", [](Eigen::Ref<const Eigen::MatrixXd> m) -> double { return get_elem(m); },
+ py::arg().noconvert());
+ // Also test a row-major-only no-copy const ref:
+ m.def("get_elem_rm_nocopy", [](Eigen::Ref<const Eigen::Matrix<long, -1, -1, Eigen::RowMajor>> &m) -> long { return m(2, 1); },
+ py::arg().noconvert());
+
+ // test_issue738
+ // Issue #738: 1xN or Nx1 2D matrices were neither accepted nor properly copied with an
+ // incompatible stride value on the length-1 dimension--but that should be allowed (without
+ // requiring a copy!) because the stride value can be safely ignored on a size-1 dimension.
+ m.def("iss738_f1", &adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>, py::arg().noconvert());
+ m.def("iss738_f2", &adjust_matrix<const Eigen::Ref<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>> &>, py::arg().noconvert());
+
+ // test_issue1105
+ // Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense
+ // eigen Vector or RowVector, the argument would fail to load because the numpy copy would fail:
+ // numpy won't broadcast a Nx1 into a 1-dimensional vector.
+ m.def("iss1105_col", [](Eigen::VectorXd) { return true; });
+ m.def("iss1105_row", [](Eigen::RowVectorXd) { return true; });
+
+ // test_named_arguments
+ // Make sure named arguments are working properly:
+ m.def("matrix_multiply", [](const py::EigenDRef<const Eigen::MatrixXd> A, const py::EigenDRef<const Eigen::MatrixXd> B)
+ -> Eigen::MatrixXd {
+ if (A.cols() != B.rows()) throw std::domain_error("Nonconformable matrices!");
+ return A * B;
+ }, py::arg("A"), py::arg("B"));
+
+ // test_custom_operator_new
+ py::class_<CustomOperatorNew>(m, "CustomOperatorNew")
+ .def(py::init<>())
+ .def_readonly("a", &CustomOperatorNew::a)
+ .def_readonly("b", &CustomOperatorNew::b);
+
+ // test_eigen_ref_life_support
+ // In case of a failure (the caster's temp array does not live long enough), creating
+ // a new array (np.ones(10)) increases the chances that the temp array will be garbage
+ // collected and/or that its memory will be overridden with different values.
+ m.def("get_elem_direct", [](Eigen::Ref<const Eigen::VectorXd> v) {
+ py::module::import("numpy").attr("ones")(10);
+ return v(5);
+ });
+ m.def("get_elem_indirect", [](std::vector<Eigen::Ref<const Eigen::VectorXd>> v) {
+ py::module::import("numpy").attr("ones")(10);
+ return v[0](5);
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_eigen.py b/3rdparty/pybind11/tests/test_eigen.py
new file mode 100644
index 00000000..55d93517
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_eigen.py
@@ -0,0 +1,694 @@
+import pytest
+from pybind11_tests import ConstructorStats
+
+pytestmark = pytest.requires_eigen_and_numpy
+
+with pytest.suppress(ImportError):
+ from pybind11_tests import eigen as m
+ import numpy as np
+
+ ref = np.array([[ 0., 3, 0, 0, 0, 11],
+ [22, 0, 0, 0, 17, 11],
+ [ 7, 5, 0, 1, 0, 11],
+ [ 0, 0, 0, 0, 0, 11],
+ [ 0, 0, 14, 0, 8, 11]])
+
+
+def assert_equal_ref(mat):
+ np.testing.assert_array_equal(mat, ref)
+
+
+def assert_sparse_equal_ref(sparse_mat):
+ assert_equal_ref(sparse_mat.toarray())
+
+
+def test_fixed():
+ assert_equal_ref(m.fixed_c())
+ assert_equal_ref(m.fixed_r())
+ assert_equal_ref(m.fixed_copy_r(m.fixed_r()))
+ assert_equal_ref(m.fixed_copy_c(m.fixed_c()))
+ assert_equal_ref(m.fixed_copy_r(m.fixed_c()))
+ assert_equal_ref(m.fixed_copy_c(m.fixed_r()))
+
+
+def test_dense():
+ assert_equal_ref(m.dense_r())
+ assert_equal_ref(m.dense_c())
+ assert_equal_ref(m.dense_copy_r(m.dense_r()))
+ assert_equal_ref(m.dense_copy_c(m.dense_c()))
+ assert_equal_ref(m.dense_copy_r(m.dense_c()))
+ assert_equal_ref(m.dense_copy_c(m.dense_r()))
+
+
+def test_partially_fixed():
+ ref2 = np.array([[0., 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]])
+ np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2), ref2)
+ np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2), ref2)
+ np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, 1]), ref2[:, [1]])
+ np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2[0, :]), ref2[[0], :])
+ np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)])
+ np.testing.assert_array_equal(
+ m.partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :])
+
+ np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2), ref2)
+ np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2), ref2)
+ np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, 1]), ref2[:, [1]])
+ np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2[0, :]), ref2[[0], :])
+ np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)])
+ np.testing.assert_array_equal(
+ m.partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :])
+
+ # TypeError should be raise for a shape mismatch
+ functions = [m.partial_copy_four_rm_r, m.partial_copy_four_rm_c,
+ m.partial_copy_four_cm_r, m.partial_copy_four_cm_c]
+ matrix_with_wrong_shape = [[1, 2],
+ [3, 4]]
+ for f in functions:
+ with pytest.raises(TypeError) as excinfo:
+ f(matrix_with_wrong_shape)
+ assert "incompatible function arguments" in str(excinfo.value)
+
+
+def test_mutator_descriptors():
+ zr = np.arange(30, dtype='float32').reshape(5, 6) # row-major
+ zc = zr.reshape(6, 5).transpose() # column-major
+
+ m.fixed_mutator_r(zr)
+ m.fixed_mutator_c(zc)
+ m.fixed_mutator_a(zr)
+ m.fixed_mutator_a(zc)
+ with pytest.raises(TypeError) as excinfo:
+ m.fixed_mutator_r(zc)
+ assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.c_contiguous]) -> None'
+ in str(excinfo.value))
+ with pytest.raises(TypeError) as excinfo:
+ m.fixed_mutator_c(zr)
+ assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.f_contiguous]) -> None'
+ in str(excinfo.value))
+ with pytest.raises(TypeError) as excinfo:
+ m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype='float32'))
+ assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable]) -> None'
+ in str(excinfo.value))
+ zr.flags.writeable = False
+ with pytest.raises(TypeError):
+ m.fixed_mutator_r(zr)
+ with pytest.raises(TypeError):
+ m.fixed_mutator_a(zr)
+
+
+def test_cpp_casting():
+ assert m.cpp_copy(m.fixed_r()) == 22.
+ assert m.cpp_copy(m.fixed_c()) == 22.
+ z = np.array([[5., 6], [7, 8]])
+ assert m.cpp_copy(z) == 7.
+ assert m.cpp_copy(m.get_cm_ref()) == 21.
+ assert m.cpp_copy(m.get_rm_ref()) == 21.
+ assert m.cpp_ref_c(m.get_cm_ref()) == 21.
+ assert m.cpp_ref_r(m.get_rm_ref()) == 21.
+ with pytest.raises(RuntimeError) as excinfo:
+ # Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles
+ m.cpp_ref_any(m.fixed_c())
+ assert 'Unable to cast Python instance' in str(excinfo.value)
+ with pytest.raises(RuntimeError) as excinfo:
+ # Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles
+ m.cpp_ref_any(m.fixed_r())
+ assert 'Unable to cast Python instance' in str(excinfo.value)
+ assert m.cpp_ref_any(m.ReturnTester.create()) == 1.
+
+ assert m.cpp_ref_any(m.get_cm_ref()) == 21.
+ assert m.cpp_ref_any(m.get_cm_ref()) == 21.
+
+
+def test_pass_readonly_array():
+ z = np.full((5, 6), 42.0)
+ z.flags.writeable = False
+ np.testing.assert_array_equal(z, m.fixed_copy_r(z))
+ np.testing.assert_array_equal(m.fixed_r_const(), m.fixed_r())
+ assert not m.fixed_r_const().flags.writeable
+ np.testing.assert_array_equal(m.fixed_copy_r(m.fixed_r_const()), m.fixed_r_const())
+
+
+def test_nonunit_stride_from_python():
+ counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
+ second_row = counting_mat[1, :]
+ second_col = counting_mat[:, 1]
+ np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row)
+ np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row)
+ np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row)
+ np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col)
+ np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col)
+ np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col)
+
+ counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
+ slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
+ for slice_idx, ref_mat in enumerate(slices):
+ np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)
+ np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)
+
+ # Mutator:
+ m.double_threer(second_row)
+ m.double_threec(second_col)
+ np.testing.assert_array_equal(counting_mat, [[0., 2, 2], [6, 16, 10], [6, 14, 8]])
+
+
+def test_negative_stride_from_python(msg):
+ """Eigen doesn't support (as of yet) negative strides. When a function takes an Eigen matrix by
+ copy or const reference, we can pass a numpy array that has negative strides. Otherwise, an
+ exception will be thrown as Eigen will not be able to map the numpy array."""
+
+ counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
+ counting_mat = counting_mat[::-1, ::-1]
+ second_row = counting_mat[1, :]
+ second_col = counting_mat[:, 1]
+ np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row)
+ np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row)
+ np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row)
+ np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col)
+ np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col)
+ np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col)
+
+ counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
+ counting_3d = counting_3d[::-1, ::-1, ::-1]
+ slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
+ for slice_idx, ref_mat in enumerate(slices):
+ np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)
+ np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)
+
+ # Mutator:
+ with pytest.raises(TypeError) as excinfo:
+ m.double_threer(second_row)
+ assert msg(excinfo.value) == """
+ double_threer(): incompatible function arguments. The following argument types are supported:
+ 1. (arg0: numpy.ndarray[float32[1, 3], flags.writeable]) -> None
+
+ Invoked with: """ + repr(np.array([ 5., 4., 3.], dtype='float32')) # noqa: E501 line too long
+
+ with pytest.raises(TypeError) as excinfo:
+ m.double_threec(second_col)
+ assert msg(excinfo.value) == """
+ double_threec(): incompatible function arguments. The following argument types are supported:
+ 1. (arg0: numpy.ndarray[float32[3, 1], flags.writeable]) -> None
+
+ Invoked with: """ + repr(np.array([ 7., 4., 1.], dtype='float32')) # noqa: E501 line too long
+
+
+def test_nonunit_stride_to_python():
+ assert np.all(m.diagonal(ref) == ref.diagonal())
+ assert np.all(m.diagonal_1(ref) == ref.diagonal(1))
+ for i in range(-5, 7):
+ assert np.all(m.diagonal_n(ref, i) == ref.diagonal(i)), "m.diagonal_n({})".format(i)
+
+ assert np.all(m.block(ref, 2, 1, 3, 3) == ref[2:5, 1:4])
+ assert np.all(m.block(ref, 1, 4, 4, 2) == ref[1:, 4:])
+ assert np.all(m.block(ref, 1, 4, 3, 2) == ref[1:4, 4:])
+
+
+def test_eigen_ref_to_python():
+ chols = [m.cholesky1, m.cholesky2, m.cholesky3, m.cholesky4]
+ for i, chol in enumerate(chols, start=1):
+ mymat = chol(np.array([[1., 2, 4], [2, 13, 23], [4, 23, 77]]))
+ assert np.all(mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])), "cholesky{}".format(i)
+
+
+def assign_both(a1, a2, r, c, v):
+ a1[r, c] = v
+ a2[r, c] = v
+
+
+def array_copy_but_one(a, r, c, v):
+ z = np.array(a, copy=True)
+ z[r, c] = v
+ return z
+
+
+def test_eigen_return_references():
+ """Tests various ways of returning references and non-referencing copies"""
+
+ master = np.ones((10, 10))
+ a = m.ReturnTester()
+ a_get1 = a.get()
+ assert not a_get1.flags.owndata and a_get1.flags.writeable
+ assign_both(a_get1, master, 3, 3, 5)
+ a_get2 = a.get_ptr()
+ assert not a_get2.flags.owndata and a_get2.flags.writeable
+ assign_both(a_get1, master, 2, 3, 6)
+
+ a_view1 = a.view()
+ assert not a_view1.flags.owndata and not a_view1.flags.writeable
+ with pytest.raises(ValueError):
+ a_view1[2, 3] = 4
+ a_view2 = a.view_ptr()
+ assert not a_view2.flags.owndata and not a_view2.flags.writeable
+ with pytest.raises(ValueError):
+ a_view2[2, 3] = 4
+
+ a_copy1 = a.copy_get()
+ assert a_copy1.flags.owndata and a_copy1.flags.writeable
+ np.testing.assert_array_equal(a_copy1, master)
+ a_copy1[7, 7] = -44 # Shouldn't affect anything else
+ c1want = array_copy_but_one(master, 7, 7, -44)
+ a_copy2 = a.copy_view()
+ assert a_copy2.flags.owndata and a_copy2.flags.writeable
+ np.testing.assert_array_equal(a_copy2, master)
+ a_copy2[4, 4] = -22 # Shouldn't affect anything else
+ c2want = array_copy_but_one(master, 4, 4, -22)
+
+ a_ref1 = a.ref()
+ assert not a_ref1.flags.owndata and a_ref1.flags.writeable
+ assign_both(a_ref1, master, 1, 1, 15)
+ a_ref2 = a.ref_const()
+ assert not a_ref2.flags.owndata and not a_ref2.flags.writeable
+ with pytest.raises(ValueError):
+ a_ref2[5, 5] = 33
+ a_ref3 = a.ref_safe()
+ assert not a_ref3.flags.owndata and a_ref3.flags.writeable
+ assign_both(a_ref3, master, 0, 7, 99)
+ a_ref4 = a.ref_const_safe()
+ assert not a_ref4.flags.owndata and not a_ref4.flags.writeable
+ with pytest.raises(ValueError):
+ a_ref4[7, 0] = 987654321
+
+ a_copy3 = a.copy_ref()
+ assert a_copy3.flags.owndata and a_copy3.flags.writeable
+ np.testing.assert_array_equal(a_copy3, master)
+ a_copy3[8, 1] = 11
+ c3want = array_copy_but_one(master, 8, 1, 11)
+ a_copy4 = a.copy_ref_const()
+ assert a_copy4.flags.owndata and a_copy4.flags.writeable
+ np.testing.assert_array_equal(a_copy4, master)
+ a_copy4[8, 4] = 88
+ c4want = array_copy_but_one(master, 8, 4, 88)
+
+ a_block1 = a.block(3, 3, 2, 2)
+ assert not a_block1.flags.owndata and a_block1.flags.writeable
+ a_block1[0, 0] = 55
+ master[3, 3] = 55
+ a_block2 = a.block_safe(2, 2, 3, 2)
+ assert not a_block2.flags.owndata and a_block2.flags.writeable
+ a_block2[2, 1] = -123
+ master[4, 3] = -123
+ a_block3 = a.block_const(6, 7, 4, 3)
+ assert not a_block3.flags.owndata and not a_block3.flags.writeable
+ with pytest.raises(ValueError):
+ a_block3[2, 2] = -44444
+
+ a_copy5 = a.copy_block(2, 2, 2, 3)
+ assert a_copy5.flags.owndata and a_copy5.flags.writeable
+ np.testing.assert_array_equal(a_copy5, master[2:4, 2:5])
+ a_copy5[1, 1] = 777
+ c5want = array_copy_but_one(master[2:4, 2:5], 1, 1, 777)
+
+ a_corn1 = a.corners()
+ assert not a_corn1.flags.owndata and a_corn1.flags.writeable
+ a_corn1 *= 50
+ a_corn1[1, 1] = 999
+ master[0, 0] = 50
+ master[0, 9] = 50
+ master[9, 0] = 50
+ master[9, 9] = 999
+ a_corn2 = a.corners_const()
+ assert not a_corn2.flags.owndata and not a_corn2.flags.writeable
+ with pytest.raises(ValueError):
+ a_corn2[1, 0] = 51
+
+ # All of the changes made all the way along should be visible everywhere
+ # now (except for the copies, of course)
+ np.testing.assert_array_equal(a_get1, master)
+ np.testing.assert_array_equal(a_get2, master)
+ np.testing.assert_array_equal(a_view1, master)
+ np.testing.assert_array_equal(a_view2, master)
+ np.testing.assert_array_equal(a_ref1, master)
+ np.testing.assert_array_equal(a_ref2, master)
+ np.testing.assert_array_equal(a_ref3, master)
+ np.testing.assert_array_equal(a_ref4, master)
+ np.testing.assert_array_equal(a_block1, master[3:5, 3:5])
+ np.testing.assert_array_equal(a_block2, master[2:5, 2:4])
+ np.testing.assert_array_equal(a_block3, master[6:10, 7:10])
+ np.testing.assert_array_equal(a_corn1, master[0::master.shape[0] - 1, 0::master.shape[1] - 1])
+ np.testing.assert_array_equal(a_corn2, master[0::master.shape[0] - 1, 0::master.shape[1] - 1])
+
+ np.testing.assert_array_equal(a_copy1, c1want)
+ np.testing.assert_array_equal(a_copy2, c2want)
+ np.testing.assert_array_equal(a_copy3, c3want)
+ np.testing.assert_array_equal(a_copy4, c4want)
+ np.testing.assert_array_equal(a_copy5, c5want)
+
+
+def assert_keeps_alive(cl, method, *args):
+ cstats = ConstructorStats.get(cl)
+ start_with = cstats.alive()
+ a = cl()
+ assert cstats.alive() == start_with + 1
+ z = method(a, *args)
+ assert cstats.alive() == start_with + 1
+ del a
+ # Here's the keep alive in action:
+ assert cstats.alive() == start_with + 1
+ del z
+ # Keep alive should have expired:
+ assert cstats.alive() == start_with
+
+
+def test_eigen_keepalive():
+ a = m.ReturnTester()
+ cstats = ConstructorStats.get(m.ReturnTester)
+ assert cstats.alive() == 1
+ unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)]
+ copies = [a.copy_get(), a.copy_view(), a.copy_ref(), a.copy_ref_const(),
+ a.copy_block(4, 3, 2, 1)]
+ del a
+ assert cstats.alive() == 0
+ del unsafe
+ del copies
+
+ for meth in [m.ReturnTester.get, m.ReturnTester.get_ptr, m.ReturnTester.view,
+ m.ReturnTester.view_ptr, m.ReturnTester.ref_safe, m.ReturnTester.ref_const_safe,
+ m.ReturnTester.corners, m.ReturnTester.corners_const]:
+ assert_keeps_alive(m.ReturnTester, meth)
+
+ for meth in [m.ReturnTester.block_safe, m.ReturnTester.block_const]:
+ assert_keeps_alive(m.ReturnTester, meth, 4, 3, 2, 1)
+
+
+def test_eigen_ref_mutators():
+ """Tests Eigen's ability to mutate numpy values"""
+
+ orig = np.array([[1., 2, 3], [4, 5, 6], [7, 8, 9]])
+ zr = np.array(orig)
+ zc = np.array(orig, order='F')
+ m.add_rm(zr, 1, 0, 100)
+ assert np.all(zr == np.array([[1., 2, 3], [104, 5, 6], [7, 8, 9]]))
+ m.add_cm(zc, 1, 0, 200)
+ assert np.all(zc == np.array([[1., 2, 3], [204, 5, 6], [7, 8, 9]]))
+
+ m.add_any(zr, 1, 0, 20)
+ assert np.all(zr == np.array([[1., 2, 3], [124, 5, 6], [7, 8, 9]]))
+ m.add_any(zc, 1, 0, 10)
+ assert np.all(zc == np.array([[1., 2, 3], [214, 5, 6], [7, 8, 9]]))
+
+ # Can't reference a col-major array with a row-major Ref, and vice versa:
+ with pytest.raises(TypeError):
+ m.add_rm(zc, 1, 0, 1)
+ with pytest.raises(TypeError):
+ m.add_cm(zr, 1, 0, 1)
+
+ # Overloads:
+ m.add1(zr, 1, 0, -100)
+ m.add2(zr, 1, 0, -20)
+ assert np.all(zr == orig)
+ m.add1(zc, 1, 0, -200)
+ m.add2(zc, 1, 0, -10)
+ assert np.all(zc == orig)
+
+ # a non-contiguous slice (this won't work on either the row- or
+ # column-contiguous refs, but should work for the any)
+ cornersr = zr[0::2, 0::2]
+ cornersc = zc[0::2, 0::2]
+
+ assert np.all(cornersr == np.array([[1., 3], [7, 9]]))
+ assert np.all(cornersc == np.array([[1., 3], [7, 9]]))
+
+ with pytest.raises(TypeError):
+ m.add_rm(cornersr, 0, 1, 25)
+ with pytest.raises(TypeError):
+ m.add_cm(cornersr, 0, 1, 25)
+ with pytest.raises(TypeError):
+ m.add_rm(cornersc, 0, 1, 25)
+ with pytest.raises(TypeError):
+ m.add_cm(cornersc, 0, 1, 25)
+ m.add_any(cornersr, 0, 1, 25)
+ m.add_any(cornersc, 0, 1, 44)
+ assert np.all(zr == np.array([[1., 2, 28], [4, 5, 6], [7, 8, 9]]))
+ assert np.all(zc == np.array([[1., 2, 47], [4, 5, 6], [7, 8, 9]]))
+
+ # You shouldn't be allowed to pass a non-writeable array to a mutating Eigen method:
+ zro = zr[0:4, 0:4]
+ zro.flags.writeable = False
+ with pytest.raises(TypeError):
+ m.add_rm(zro, 0, 0, 0)
+ with pytest.raises(TypeError):
+ m.add_any(zro, 0, 0, 0)
+ with pytest.raises(TypeError):
+ m.add1(zro, 0, 0, 0)
+ with pytest.raises(TypeError):
+ m.add2(zro, 0, 0, 0)
+
+ # integer array shouldn't be passable to a double-matrix-accepting mutating func:
+ zi = np.array([[1, 2], [3, 4]])
+ with pytest.raises(TypeError):
+ m.add_rm(zi)
+
+
+def test_numpy_ref_mutators():
+ """Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)"""
+
+ m.reset_refs() # In case another test already changed it
+
+ zc = m.get_cm_ref()
+ zcro = m.get_cm_const_ref()
+ zr = m.get_rm_ref()
+ zrro = m.get_rm_const_ref()
+
+ assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4
+
+ assert not zc.flags.owndata and zc.flags.writeable
+ assert not zr.flags.owndata and zr.flags.writeable
+ assert not zcro.flags.owndata and not zcro.flags.writeable
+ assert not zrro.flags.owndata and not zrro.flags.writeable
+
+ zc[1, 2] = 99
+ expect = np.array([[11., 12, 13], [21, 22, 99], [31, 32, 33]])
+ # We should have just changed zc, of course, but also zcro and the original eigen matrix
+ assert np.all(zc == expect)
+ assert np.all(zcro == expect)
+ assert np.all(m.get_cm_ref() == expect)
+
+ zr[1, 2] = 99
+ assert np.all(zr == expect)
+ assert np.all(zrro == expect)
+ assert np.all(m.get_rm_ref() == expect)
+
+ # Make sure the readonly ones are numpy-readonly:
+ with pytest.raises(ValueError):
+ zcro[1, 2] = 6
+ with pytest.raises(ValueError):
+ zrro[1, 2] = 6
+
+ # We should be able to explicitly copy like this (and since we're copying,
+ # the const should drop away)
+ y1 = np.array(m.get_cm_const_ref())
+
+ assert y1.flags.owndata and y1.flags.writeable
+ # We should get copies of the eigen data, which was modified above:
+ assert y1[1, 2] == 99
+ y1[1, 2] += 12
+ assert y1[1, 2] == 111
+ assert zc[1, 2] == 99 # Make sure we aren't referencing the original
+
+
+def test_both_ref_mutators():
+ """Tests a complex chain of nested eigen/numpy references"""
+
+ m.reset_refs() # In case another test already changed it
+
+ z = m.get_cm_ref() # numpy -> eigen
+ z[0, 2] -= 3
+ z2 = m.incr_matrix(z, 1) # numpy -> eigen -> numpy -> eigen
+ z2[1, 1] += 6
+ z3 = m.incr_matrix(z, 2) # (numpy -> eigen)^3
+ z3[2, 2] += -5
+ z4 = m.incr_matrix(z, 3) # (numpy -> eigen)^4
+ z4[1, 1] -= 1
+ z5 = m.incr_matrix(z, 4) # (numpy -> eigen)^5
+ z5[0, 0] = 0
+ assert np.all(z == z2)
+ assert np.all(z == z3)
+ assert np.all(z == z4)
+ assert np.all(z == z5)
+ expect = np.array([[0., 22, 20], [31, 37, 33], [41, 42, 38]])
+ assert np.all(z == expect)
+
+ y = np.array(range(100), dtype='float64').reshape(10, 10)
+ y2 = m.incr_matrix_any(y, 10) # np -> eigen -> np
+ y3 = m.incr_matrix_any(y2[0::2, 0::2], -33) # np -> eigen -> np slice -> np -> eigen -> np
+ y4 = m.even_rows(y3) # numpy -> eigen slice -> (... y3)
+ y5 = m.even_cols(y4) # numpy -> eigen slice -> (... y4)
+ y6 = m.incr_matrix_any(y5, 1000) # numpy -> eigen -> (... y5)
+
+ # Apply same mutations using just numpy:
+ yexpect = np.array(range(100), dtype='float64').reshape(10, 10)
+ yexpect += 10
+ yexpect[0::2, 0::2] -= 33
+ yexpect[0::4, 0::4] += 1000
+ assert np.all(y6 == yexpect[0::4, 0::4])
+ assert np.all(y5 == yexpect[0::4, 0::4])
+ assert np.all(y4 == yexpect[0::4, 0::2])
+ assert np.all(y3 == yexpect[0::2, 0::2])
+ assert np.all(y2 == yexpect)
+ assert np.all(y == yexpect)
+
+
+def test_nocopy_wrapper():
+ # get_elem requires a column-contiguous matrix reference, but should be
+ # callable with other types of matrix (via copying):
+ int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order='F')
+ dbl_matrix_colmajor = np.array(int_matrix_colmajor, dtype='double', order='F', copy=True)
+ int_matrix_rowmajor = np.array(int_matrix_colmajor, order='C', copy=True)
+ dbl_matrix_rowmajor = np.array(int_matrix_rowmajor, dtype='double', order='C', copy=True)
+
+ # All should be callable via get_elem:
+ assert m.get_elem(int_matrix_colmajor) == 8
+ assert m.get_elem(dbl_matrix_colmajor) == 8
+ assert m.get_elem(int_matrix_rowmajor) == 8
+ assert m.get_elem(dbl_matrix_rowmajor) == 8
+
+ # All but the second should fail with m.get_elem_nocopy:
+ with pytest.raises(TypeError) as excinfo:
+ m.get_elem_nocopy(int_matrix_colmajor)
+ assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and
+ ', flags.f_contiguous' in str(excinfo.value))
+ assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8
+ with pytest.raises(TypeError) as excinfo:
+ m.get_elem_nocopy(int_matrix_rowmajor)
+ assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and
+ ', flags.f_contiguous' in str(excinfo.value))
+ with pytest.raises(TypeError) as excinfo:
+ m.get_elem_nocopy(dbl_matrix_rowmajor)
+ assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and
+ ', flags.f_contiguous' in str(excinfo.value))
+
+ # For the row-major test, we take a long matrix in row-major, so only the third is allowed:
+ with pytest.raises(TypeError) as excinfo:
+ m.get_elem_rm_nocopy(int_matrix_colmajor)
+ assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and
+ ', flags.c_contiguous' in str(excinfo.value))
+ with pytest.raises(TypeError) as excinfo:
+ m.get_elem_rm_nocopy(dbl_matrix_colmajor)
+ assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and
+ ', flags.c_contiguous' in str(excinfo.value))
+ assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8
+ with pytest.raises(TypeError) as excinfo:
+ m.get_elem_rm_nocopy(dbl_matrix_rowmajor)
+ assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and
+ ', flags.c_contiguous' in str(excinfo.value))
+
+
+def test_eigen_ref_life_support():
+ """Ensure the lifetime of temporary arrays created by the `Ref` caster
+
+ The `Ref` caster sometimes creates a copy which needs to stay alive. This needs to
+ happen both for directs casts (just the array) or indirectly (e.g. list of arrays).
+ """
+
+ a = np.full(shape=10, fill_value=8, dtype=np.int8)
+ assert m.get_elem_direct(a) == 8
+
+ list_of_a = [a]
+ assert m.get_elem_indirect(list_of_a) == 8
+
+
+def test_special_matrix_objects():
+ assert np.all(m.incr_diag(7) == np.diag([1., 2, 3, 4, 5, 6, 7]))
+
+ asymm = np.array([[ 1., 2, 3, 4],
+ [ 5, 6, 7, 8],
+ [ 9, 10, 11, 12],
+ [13, 14, 15, 16]])
+ symm_lower = np.array(asymm)
+ symm_upper = np.array(asymm)
+ for i in range(4):
+ for j in range(i + 1, 4):
+ symm_lower[i, j] = symm_lower[j, i]
+ symm_upper[j, i] = symm_upper[i, j]
+
+ assert np.all(m.symmetric_lower(asymm) == symm_lower)
+ assert np.all(m.symmetric_upper(asymm) == symm_upper)
+
+
+def test_dense_signature(doc):
+ assert doc(m.double_col) == """
+ double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]]
+ """
+ assert doc(m.double_row) == """
+ double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]]
+ """
+ assert doc(m.double_complex) == """
+ double_complex(arg0: numpy.ndarray[complex64[m, 1]]) -> numpy.ndarray[complex64[m, 1]]
+ """
+ assert doc(m.double_mat_rm) == """
+ double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]]
+ """
+
+
+def test_named_arguments():
+ a = np.array([[1.0, 2], [3, 4], [5, 6]])
+ b = np.ones((2, 1))
+
+ assert np.all(m.matrix_multiply(a, b) == np.array([[3.], [7], [11]]))
+ assert np.all(m.matrix_multiply(A=a, B=b) == np.array([[3.], [7], [11]]))
+ assert np.all(m.matrix_multiply(B=b, A=a) == np.array([[3.], [7], [11]]))
+
+ with pytest.raises(ValueError) as excinfo:
+ m.matrix_multiply(b, a)
+ assert str(excinfo.value) == 'Nonconformable matrices!'
+
+ with pytest.raises(ValueError) as excinfo:
+ m.matrix_multiply(A=b, B=a)
+ assert str(excinfo.value) == 'Nonconformable matrices!'
+
+ with pytest.raises(ValueError) as excinfo:
+ m.matrix_multiply(B=a, A=b)
+ assert str(excinfo.value) == 'Nonconformable matrices!'
+
+
+@pytest.requires_eigen_and_scipy
+def test_sparse():
+ assert_sparse_equal_ref(m.sparse_r())
+ assert_sparse_equal_ref(m.sparse_c())
+ assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_r()))
+ assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_c()))
+ assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_c()))
+ assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_r()))
+
+
+@pytest.requires_eigen_and_scipy
+def test_sparse_signature(doc):
+ assert doc(m.sparse_copy_r) == """
+ sparse_copy_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32]
+ """ # noqa: E501 line too long
+ assert doc(m.sparse_copy_c) == """
+ sparse_copy_c(arg0: scipy.sparse.csc_matrix[float32]) -> scipy.sparse.csc_matrix[float32]
+ """ # noqa: E501 line too long
+
+
+def test_issue738():
+ """Ignore strides on a length-1 dimension (even if they would be incompatible length > 1)"""
+ assert np.all(m.iss738_f1(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]]))
+ assert np.all(m.iss738_f1(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]]))
+
+ assert np.all(m.iss738_f2(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]]))
+ assert np.all(m.iss738_f2(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]]))
+
+
+def test_issue1105():
+ """Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen
+ compile-time row vectors or column vector"""
+ assert m.iss1105_row(np.ones((1, 7)))
+ assert m.iss1105_col(np.ones((7, 1)))
+
+ # These should still fail (incompatible dimensions):
+ with pytest.raises(TypeError) as excinfo:
+ m.iss1105_row(np.ones((7, 1)))
+ assert "incompatible function arguments" in str(excinfo.value)
+ with pytest.raises(TypeError) as excinfo:
+ m.iss1105_col(np.ones((1, 7)))
+ assert "incompatible function arguments" in str(excinfo.value)
+
+
+def test_custom_operator_new():
+ """Using Eigen types as member variables requires a class-specific
+ operator new with proper alignment"""
+
+ o = m.CustomOperatorNew()
+ np.testing.assert_allclose(o.a, 0.0)
+ np.testing.assert_allclose(o.b.diagonal(), 1.0)
diff --git a/3rdparty/pybind11/tests/test_embed/CMakeLists.txt b/3rdparty/pybind11/tests/test_embed/CMakeLists.txt
new file mode 100644
index 00000000..8b4f1f84
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_embed/CMakeLists.txt
@@ -0,0 +1,41 @@
+if(${PYTHON_MODULE_EXTENSION} MATCHES "pypy")
+ add_custom_target(cpptest) # Dummy target on PyPy. Embedding is not supported.
+ set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}")
+ return()
+endif()
+
+find_package(Catch 1.9.3)
+if(CATCH_FOUND)
+ message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}")
+else()
+ message(STATUS "Catch not detected. Interpreter tests will be skipped. Install Catch headers"
+ " manually or use `cmake -DDOWNLOAD_CATCH=1` to fetch them automatically.")
+ return()
+endif()
+
+add_executable(test_embed
+ catch.cpp
+ test_interpreter.cpp
+)
+target_include_directories(test_embed PRIVATE ${CATCH_INCLUDE_DIR})
+pybind11_enable_warnings(test_embed)
+
+if(NOT CMAKE_VERSION VERSION_LESS 3.0)
+ target_link_libraries(test_embed PRIVATE pybind11::embed)
+else()
+ target_include_directories(test_embed PRIVATE ${PYBIND11_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS})
+ target_compile_options(test_embed PRIVATE ${PYBIND11_CPP_STANDARD})
+ target_link_libraries(test_embed PRIVATE ${PYTHON_LIBRARIES})
+endif()
+
+find_package(Threads REQUIRED)
+target_link_libraries(test_embed PUBLIC ${CMAKE_THREAD_LIBS_INIT})
+
+add_custom_target(cpptest COMMAND $<TARGET_FILE:test_embed>
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+
+pybind11_add_module(external_module THIN_LTO external_module.cpp)
+set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+add_dependencies(cpptest external_module)
+
+add_dependencies(check cpptest)
diff --git a/3rdparty/pybind11/tests/test_embed/catch.cpp b/3rdparty/pybind11/tests/test_embed/catch.cpp
new file mode 100644
index 00000000..dd137385
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_embed/catch.cpp
@@ -0,0 +1,22 @@
+// The Catch implementation is compiled here. This is a standalone
+// translation unit to avoid recompiling it for every test change.
+
+#include <pybind11/embed.h>
+
+#ifdef _MSC_VER
+// Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to catch
+// 2.0.1; this should be fixed in the next catch release after 2.0.1).
+# pragma warning(disable: 4996)
+#endif
+
+#define CATCH_CONFIG_RUNNER
+#include <catch.hpp>
+
+namespace py = pybind11;
+
+int main(int argc, char *argv[]) {
+ py::scoped_interpreter guard{};
+ auto result = Catch::Session().run(argc, argv);
+
+ return result < 0xff ? result : 0xff;
+}
diff --git a/3rdparty/pybind11/tests/test_embed/external_module.cpp b/3rdparty/pybind11/tests/test_embed/external_module.cpp
new file mode 100644
index 00000000..e9a6058b
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_embed/external_module.cpp
@@ -0,0 +1,23 @@
+#include <pybind11/pybind11.h>
+
+namespace py = pybind11;
+
+/* Simple test module/test class to check that the referenced internals data of external pybind11
+ * modules aren't preserved over a finalize/initialize.
+ */
+
+PYBIND11_MODULE(external_module, m) {
+ class A {
+ public:
+ A(int value) : v{value} {};
+ int v;
+ };
+
+ py::class_<A>(m, "A")
+ .def(py::init<int>())
+ .def_readwrite("value", &A::v);
+
+ m.def("internals_at", []() {
+ return reinterpret_cast<uintptr_t>(&py::detail::get_internals());
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_embed/test_interpreter.cpp b/3rdparty/pybind11/tests/test_embed/test_interpreter.cpp
new file mode 100644
index 00000000..222bd565
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_embed/test_interpreter.cpp
@@ -0,0 +1,284 @@
+#include <pybind11/embed.h>
+
+#ifdef _MSC_VER
+// Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to catch
+// 2.0.1; this should be fixed in the next catch release after 2.0.1).
+# pragma warning(disable: 4996)
+#endif
+
+#include <catch.hpp>
+
+#include <thread>
+#include <fstream>
+#include <functional>
+
+namespace py = pybind11;
+using namespace py::literals;
+
+class Widget {
+public:
+ Widget(std::string message) : message(message) { }
+ virtual ~Widget() = default;
+
+ std::string the_message() const { return message; }
+ virtual int the_answer() const = 0;
+
+private:
+ std::string message;
+};
+
+class PyWidget final : public Widget {
+ using Widget::Widget;
+
+ int the_answer() const override { PYBIND11_OVERLOAD_PURE(int, Widget, the_answer); }
+};
+
+PYBIND11_EMBEDDED_MODULE(widget_module, m) {
+ py::class_<Widget, PyWidget>(m, "Widget")
+ .def(py::init<std::string>())
+ .def_property_readonly("the_message", &Widget::the_message);
+
+ m.def("add", [](int i, int j) { return i + j; });
+}
+
+PYBIND11_EMBEDDED_MODULE(throw_exception, ) {
+ throw std::runtime_error("C++ Error");
+}
+
+PYBIND11_EMBEDDED_MODULE(throw_error_already_set, ) {
+ auto d = py::dict();
+ d["missing"].cast<py::object>();
+}
+
+TEST_CASE("Pass classes and data between modules defined in C++ and Python") {
+ auto module = py::module::import("test_interpreter");
+ REQUIRE(py::hasattr(module, "DerivedWidget"));
+
+ auto locals = py::dict("hello"_a="Hello, World!", "x"_a=5, **module.attr("__dict__"));
+ py::exec(R"(
+ widget = DerivedWidget("{} - {}".format(hello, x))
+ message = widget.the_message
+ )", py::globals(), locals);
+ REQUIRE(locals["message"].cast<std::string>() == "Hello, World! - 5");
+
+ auto py_widget = module.attr("DerivedWidget")("The question");
+ auto message = py_widget.attr("the_message");
+ REQUIRE(message.cast<std::string>() == "The question");
+
+ const auto &cpp_widget = py_widget.cast<const Widget &>();
+ REQUIRE(cpp_widget.the_answer() == 42);
+}
+
+TEST_CASE("Import error handling") {
+ REQUIRE_NOTHROW(py::module::import("widget_module"));
+ REQUIRE_THROWS_WITH(py::module::import("throw_exception"),
+ "ImportError: C++ Error");
+ REQUIRE_THROWS_WITH(py::module::import("throw_error_already_set"),
+ Catch::Contains("ImportError: KeyError"));
+}
+
+TEST_CASE("There can be only one interpreter") {
+ static_assert(std::is_move_constructible<py::scoped_interpreter>::value, "");
+ static_assert(!std::is_move_assignable<py::scoped_interpreter>::value, "");
+ static_assert(!std::is_copy_constructible<py::scoped_interpreter>::value, "");
+ static_assert(!std::is_copy_assignable<py::scoped_interpreter>::value, "");
+
+ REQUIRE_THROWS_WITH(py::initialize_interpreter(), "The interpreter is already running");
+ REQUIRE_THROWS_WITH(py::scoped_interpreter(), "The interpreter is already running");
+
+ py::finalize_interpreter();
+ REQUIRE_NOTHROW(py::scoped_interpreter());
+ {
+ auto pyi1 = py::scoped_interpreter();
+ auto pyi2 = std::move(pyi1);
+ }
+ py::initialize_interpreter();
+}
+
+bool has_pybind11_internals_builtin() {
+ auto builtins = py::handle(PyEval_GetBuiltins());
+ return builtins.contains(PYBIND11_INTERNALS_ID);
+};
+
+bool has_pybind11_internals_static() {
+ auto **&ipp = py::detail::get_internals_pp();
+ return ipp && *ipp;
+}
+
+TEST_CASE("Restart the interpreter") {
+ // Verify pre-restart state.
+ REQUIRE(py::module::import("widget_module").attr("add")(1, 2).cast<int>() == 3);
+ REQUIRE(has_pybind11_internals_builtin());
+ REQUIRE(has_pybind11_internals_static());
+ REQUIRE(py::module::import("external_module").attr("A")(123).attr("value").cast<int>() == 123);
+
+ // local and foreign module internals should point to the same internals:
+ REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp()) ==
+ py::module::import("external_module").attr("internals_at")().cast<uintptr_t>());
+
+ // Restart the interpreter.
+ py::finalize_interpreter();
+ REQUIRE(Py_IsInitialized() == 0);
+
+ py::initialize_interpreter();
+ REQUIRE(Py_IsInitialized() == 1);
+
+ // Internals are deleted after a restart.
+ REQUIRE_FALSE(has_pybind11_internals_builtin());
+ REQUIRE_FALSE(has_pybind11_internals_static());
+ pybind11::detail::get_internals();
+ REQUIRE(has_pybind11_internals_builtin());
+ REQUIRE(has_pybind11_internals_static());
+ REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp()) ==
+ py::module::import("external_module").attr("internals_at")().cast<uintptr_t>());
+
+ // Make sure that an interpreter with no get_internals() created until finalize still gets the
+ // internals destroyed
+ py::finalize_interpreter();
+ py::initialize_interpreter();
+ bool ran = false;
+ py::module::import("__main__").attr("internals_destroy_test") =
+ py::capsule(&ran, [](void *ran) { py::detail::get_internals(); *static_cast<bool *>(ran) = true; });
+ REQUIRE_FALSE(has_pybind11_internals_builtin());
+ REQUIRE_FALSE(has_pybind11_internals_static());
+ REQUIRE_FALSE(ran);
+ py::finalize_interpreter();
+ REQUIRE(ran);
+ py::initialize_interpreter();
+ REQUIRE_FALSE(has_pybind11_internals_builtin());
+ REQUIRE_FALSE(has_pybind11_internals_static());
+
+ // C++ modules can be reloaded.
+ auto cpp_module = py::module::import("widget_module");
+ REQUIRE(cpp_module.attr("add")(1, 2).cast<int>() == 3);
+
+ // C++ type information is reloaded and can be used in python modules.
+ auto py_module = py::module::import("test_interpreter");
+ auto py_widget = py_module.attr("DerivedWidget")("Hello after restart");
+ REQUIRE(py_widget.attr("the_message").cast<std::string>() == "Hello after restart");
+}
+
+TEST_CASE("Subinterpreter") {
+ // Add tags to the modules in the main interpreter and test the basics.
+ py::module::import("__main__").attr("main_tag") = "main interpreter";
+ {
+ auto m = py::module::import("widget_module");
+ m.attr("extension_module_tag") = "added to module in main interpreter";
+
+ REQUIRE(m.attr("add")(1, 2).cast<int>() == 3);
+ }
+ REQUIRE(has_pybind11_internals_builtin());
+ REQUIRE(has_pybind11_internals_static());
+
+ /// Create and switch to a subinterpreter.
+ auto main_tstate = PyThreadState_Get();
+ auto sub_tstate = Py_NewInterpreter();
+
+ // Subinterpreters get their own copy of builtins. detail::get_internals() still
+ // works by returning from the static variable, i.e. all interpreters share a single
+ // global pybind11::internals;
+ REQUIRE_FALSE(has_pybind11_internals_builtin());
+ REQUIRE(has_pybind11_internals_static());
+
+ // Modules tags should be gone.
+ REQUIRE_FALSE(py::hasattr(py::module::import("__main__"), "tag"));
+ {
+ auto m = py::module::import("widget_module");
+ REQUIRE_FALSE(py::hasattr(m, "extension_module_tag"));
+
+ // Function bindings should still work.
+ REQUIRE(m.attr("add")(1, 2).cast<int>() == 3);
+ }
+
+ // Restore main interpreter.
+ Py_EndInterpreter(sub_tstate);
+ PyThreadState_Swap(main_tstate);
+
+ REQUIRE(py::hasattr(py::module::import("__main__"), "main_tag"));
+ REQUIRE(py::hasattr(py::module::import("widget_module"), "extension_module_tag"));
+}
+
+TEST_CASE("Execution frame") {
+ // When the interpreter is embedded, there is no execution frame, but `py::exec`
+ // should still function by using reasonable globals: `__main__.__dict__`.
+ py::exec("var = dict(number=42)");
+ REQUIRE(py::globals()["var"]["number"].cast<int>() == 42);
+}
+
+TEST_CASE("Threads") {
+ // Restart interpreter to ensure threads are not initialized
+ py::finalize_interpreter();
+ py::initialize_interpreter();
+ REQUIRE_FALSE(has_pybind11_internals_static());
+
+ constexpr auto num_threads = 10;
+ auto locals = py::dict("count"_a=0);
+
+ {
+ py::gil_scoped_release gil_release{};
+ REQUIRE(has_pybind11_internals_static());
+
+ auto threads = std::vector<std::thread>();
+ for (auto i = 0; i < num_threads; ++i) {
+ threads.emplace_back([&]() {
+ py::gil_scoped_acquire gil{};
+ locals["count"] = locals["count"].cast<int>() + 1;
+ });
+ }
+
+ for (auto &thread : threads) {
+ thread.join();
+ }
+ }
+
+ REQUIRE(locals["count"].cast<int>() == num_threads);
+}
+
+// Scope exit utility https://stackoverflow.com/a/36644501/7255855
+struct scope_exit {
+ std::function<void()> f_;
+ explicit scope_exit(std::function<void()> f) noexcept : f_(std::move(f)) {}
+ ~scope_exit() { if (f_) f_(); }
+};
+
+TEST_CASE("Reload module from file") {
+ // Disable generation of cached bytecode (.pyc files) for this test, otherwise
+ // Python might pick up an old version from the cache instead of the new versions
+ // of the .py files generated below
+ auto sys = py::module::import("sys");
+ bool dont_write_bytecode = sys.attr("dont_write_bytecode").cast<bool>();
+ sys.attr("dont_write_bytecode") = true;
+ // Reset the value at scope exit
+ scope_exit reset_dont_write_bytecode([&]() {
+ sys.attr("dont_write_bytecode") = dont_write_bytecode;
+ });
+
+ std::string module_name = "test_module_reload";
+ std::string module_file = module_name + ".py";
+
+ // Create the module .py file
+ std::ofstream test_module(module_file);
+ test_module << "def test():\n";
+ test_module << " return 1\n";
+ test_module.close();
+ // Delete the file at scope exit
+ scope_exit delete_module_file([&]() {
+ std::remove(module_file.c_str());
+ });
+
+ // Import the module from file
+ auto module = py::module::import(module_name.c_str());
+ int result = module.attr("test")().cast<int>();
+ REQUIRE(result == 1);
+
+ // Update the module .py file with a small change
+ test_module.open(module_file);
+ test_module << "def test():\n";
+ test_module << " return 2\n";
+ test_module.close();
+
+ // Reload the module
+ module.reload();
+ result = module.attr("test")().cast<int>();
+ REQUIRE(result == 2);
+}
diff --git a/3rdparty/pybind11/tests/test_embed/test_interpreter.py b/3rdparty/pybind11/tests/test_embed/test_interpreter.py
new file mode 100644
index 00000000..26a04792
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_embed/test_interpreter.py
@@ -0,0 +1,9 @@
+from widget_module import Widget
+
+
+class DerivedWidget(Widget):
+ def __init__(self, message):
+ super(DerivedWidget, self).__init__(message)
+
+ def the_answer(self):
+ return 42
diff --git a/3rdparty/pybind11/tests/test_enum.cpp b/3rdparty/pybind11/tests/test_enum.cpp
new file mode 100644
index 00000000..31530892
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_enum.cpp
@@ -0,0 +1,87 @@
+/*
+ tests/test_enums.cpp -- enumerations
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+TEST_SUBMODULE(enums, m) {
+ // test_unscoped_enum
+ enum UnscopedEnum {
+ EOne = 1,
+ ETwo,
+ EThree
+ };
+ py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration")
+ .value("EOne", EOne, "Docstring for EOne")
+ .value("ETwo", ETwo, "Docstring for ETwo")
+ .value("EThree", EThree, "Docstring for EThree")
+ .export_values();
+
+ // test_scoped_enum
+ enum class ScopedEnum {
+ Two = 2,
+ Three
+ };
+ py::enum_<ScopedEnum>(m, "ScopedEnum", py::arithmetic())
+ .value("Two", ScopedEnum::Two)
+ .value("Three", ScopedEnum::Three);
+
+ m.def("test_scoped_enum", [](ScopedEnum z) {
+ return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three");
+ });
+
+ // test_binary_operators
+ enum Flags {
+ Read = 4,
+ Write = 2,
+ Execute = 1
+ };
+ py::enum_<Flags>(m, "Flags", py::arithmetic())
+ .value("Read", Flags::Read)
+ .value("Write", Flags::Write)
+ .value("Execute", Flags::Execute)
+ .export_values();
+
+ // test_implicit_conversion
+ class ClassWithUnscopedEnum {
+ public:
+ enum EMode {
+ EFirstMode = 1,
+ ESecondMode
+ };
+
+ static EMode test_function(EMode mode) {
+ return mode;
+ }
+ };
+ py::class_<ClassWithUnscopedEnum> exenum_class(m, "ClassWithUnscopedEnum");
+ exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function);
+ py::enum_<ClassWithUnscopedEnum::EMode>(exenum_class, "EMode")
+ .value("EFirstMode", ClassWithUnscopedEnum::EFirstMode)
+ .value("ESecondMode", ClassWithUnscopedEnum::ESecondMode)
+ .export_values();
+
+ // test_enum_to_int
+ m.def("test_enum_to_int", [](int) { });
+ m.def("test_enum_to_uint", [](uint32_t) { });
+ m.def("test_enum_to_long_long", [](long long) { });
+
+ // test_duplicate_enum_name
+ enum SimpleEnum
+ {
+ ONE, TWO, THREE
+ };
+
+ m.def("register_bad_enum", [m]() {
+ py::enum_<SimpleEnum>(m, "SimpleEnum")
+ .value("ONE", SimpleEnum::ONE) //NOTE: all value function calls are called with the same first parameter value
+ .value("ONE", SimpleEnum::TWO)
+ .value("ONE", SimpleEnum::THREE)
+ .export_values();
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_enum.py b/3rdparty/pybind11/tests/test_enum.py
new file mode 100644
index 00000000..7fe9b618
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_enum.py
@@ -0,0 +1,206 @@
+import pytest
+from pybind11_tests import enums as m
+
+
+def test_unscoped_enum():
+ assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne"
+ assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
+ assert str(m.EOne) == "UnscopedEnum.EOne"
+
+ # name property
+ assert m.UnscopedEnum.EOne.name == "EOne"
+ assert m.UnscopedEnum.ETwo.name == "ETwo"
+ assert m.EOne.name == "EOne"
+ # name readonly
+ with pytest.raises(AttributeError):
+ m.UnscopedEnum.EOne.name = ""
+ # name returns a copy
+ foo = m.UnscopedEnum.EOne.name
+ foo = "bar"
+ assert m.UnscopedEnum.EOne.name == "EOne"
+
+ # __members__ property
+ assert m.UnscopedEnum.__members__ == \
+ {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo, "EThree": m.UnscopedEnum.EThree}
+ # __members__ readonly
+ with pytest.raises(AttributeError):
+ m.UnscopedEnum.__members__ = {}
+ # __members__ returns a copy
+ foo = m.UnscopedEnum.__members__
+ foo["bar"] = "baz"
+ assert m.UnscopedEnum.__members__ == \
+ {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo, "EThree": m.UnscopedEnum.EThree}
+
+ for docstring_line in '''An unscoped enumeration
+
+Members:
+
+ EOne : Docstring for EOne
+
+ ETwo : Docstring for ETwo
+
+ EThree : Docstring for EThree'''.split('\n'):
+ assert docstring_line in m.UnscopedEnum.__doc__
+
+ # Unscoped enums will accept ==/!= int comparisons
+ y = m.UnscopedEnum.ETwo
+ assert y == 2
+ assert 2 == y
+ assert y != 3
+ assert 3 != y
+ # Compare with None
+ assert (y != None) # noqa: E711
+ assert not (y == None) # noqa: E711
+ # Compare with an object
+ assert (y != object())
+ assert not (y == object())
+ # Compare with string
+ assert y != "2"
+ assert "2" != y
+ assert not ("2" == y)
+ assert not (y == "2")
+
+ with pytest.raises(TypeError):
+ y < object()
+
+ with pytest.raises(TypeError):
+ y <= object()
+
+ with pytest.raises(TypeError):
+ y > object()
+
+ with pytest.raises(TypeError):
+ y >= object()
+
+ with pytest.raises(TypeError):
+ y | object()
+
+ with pytest.raises(TypeError):
+ y & object()
+
+ with pytest.raises(TypeError):
+ y ^ object()
+
+ assert int(m.UnscopedEnum.ETwo) == 2
+ assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo"
+
+ # order
+ assert m.UnscopedEnum.EOne < m.UnscopedEnum.ETwo
+ assert m.UnscopedEnum.EOne < 2
+ assert m.UnscopedEnum.ETwo > m.UnscopedEnum.EOne
+ assert m.UnscopedEnum.ETwo > 1
+ assert m.UnscopedEnum.ETwo <= 2
+ assert m.UnscopedEnum.ETwo >= 2
+ assert m.UnscopedEnum.EOne <= m.UnscopedEnum.ETwo
+ assert m.UnscopedEnum.EOne <= 2
+ assert m.UnscopedEnum.ETwo >= m.UnscopedEnum.EOne
+ assert m.UnscopedEnum.ETwo >= 1
+ assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne)
+ assert not (2 < m.UnscopedEnum.EOne)
+
+ # arithmetic
+ assert m.UnscopedEnum.EOne & m.UnscopedEnum.EThree == m.UnscopedEnum.EOne
+ assert m.UnscopedEnum.EOne | m.UnscopedEnum.ETwo == m.UnscopedEnum.EThree
+ assert m.UnscopedEnum.EOne ^ m.UnscopedEnum.EThree == m.UnscopedEnum.ETwo
+
+
+def test_scoped_enum():
+ assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three"
+ z = m.ScopedEnum.Two
+ assert m.test_scoped_enum(z) == "ScopedEnum::Two"
+
+ # Scoped enums will *NOT* accept ==/!= int comparisons (Will always return False)
+ assert not z == 3
+ assert not 3 == z
+ assert z != 3
+ assert 3 != z
+ # Compare with None
+ assert (z != None) # noqa: E711
+ assert not (z == None) # noqa: E711
+ # Compare with an object
+ assert (z != object())
+ assert not (z == object())
+ # Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions)
+ with pytest.raises(TypeError):
+ z > 3
+ with pytest.raises(TypeError):
+ z < 3
+ with pytest.raises(TypeError):
+ z >= 3
+ with pytest.raises(TypeError):
+ z <= 3
+
+ # order
+ assert m.ScopedEnum.Two < m.ScopedEnum.Three
+ assert m.ScopedEnum.Three > m.ScopedEnum.Two
+ assert m.ScopedEnum.Two <= m.ScopedEnum.Three
+ assert m.ScopedEnum.Two <= m.ScopedEnum.Two
+ assert m.ScopedEnum.Two >= m.ScopedEnum.Two
+ assert m.ScopedEnum.Three >= m.ScopedEnum.Two
+
+
+def test_implicit_conversion():
+ assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"
+ assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
+
+ f = m.ClassWithUnscopedEnum.test_function
+ first = m.ClassWithUnscopedEnum.EFirstMode
+ second = m.ClassWithUnscopedEnum.ESecondMode
+
+ assert f(first) == 1
+
+ assert f(first) == f(first)
+ assert not f(first) != f(first)
+
+ assert f(first) != f(second)
+ assert not f(first) == f(second)
+
+ assert f(first) == int(f(first))
+ assert not f(first) != int(f(first))
+
+ assert f(first) != int(f(second))
+ assert not f(first) == int(f(second))
+
+ # noinspection PyDictCreation
+ x = {f(first): 1, f(second): 2}
+ x[f(first)] = 3
+ x[f(second)] = 4
+ # Hashing test
+ assert str(x) == "{EMode.EFirstMode: 3, EMode.ESecondMode: 4}"
+
+
+def test_binary_operators():
+ assert int(m.Flags.Read) == 4
+ assert int(m.Flags.Write) == 2
+ assert int(m.Flags.Execute) == 1
+ assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7
+ assert int(m.Flags.Read | m.Flags.Write) == 6
+ assert int(m.Flags.Read | m.Flags.Execute) == 5
+ assert int(m.Flags.Write | m.Flags.Execute) == 3
+ assert int(m.Flags.Write | 1) == 3
+ assert ~m.Flags.Write == -3
+
+ state = m.Flags.Read | m.Flags.Write
+ assert (state & m.Flags.Read) != 0
+ assert (state & m.Flags.Write) != 0
+ assert (state & m.Flags.Execute) == 0
+ assert (state & 1) == 0
+
+ state2 = ~state
+ assert state2 == -7
+ assert int(state ^ state2) == -1
+
+
+def test_enum_to_int():
+ m.test_enum_to_int(m.Flags.Read)
+ m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode)
+ m.test_enum_to_uint(m.Flags.Read)
+ m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode)
+ m.test_enum_to_long_long(m.Flags.Read)
+ m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode)
+
+
+def test_duplicate_enum_name():
+ with pytest.raises(ValueError) as excinfo:
+ m.register_bad_enum()
+ assert str(excinfo.value) == 'SimpleEnum: element "ONE" already exists!'
diff --git a/3rdparty/pybind11/tests/test_eval.cpp b/3rdparty/pybind11/tests/test_eval.cpp
new file mode 100644
index 00000000..e0948219
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_eval.cpp
@@ -0,0 +1,91 @@
+/*
+ tests/test_eval.cpp -- Usage of eval() and eval_file()
+
+ Copyright (c) 2016 Klemens D. Morgenstern
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+
+#include <pybind11/eval.h>
+#include "pybind11_tests.h"
+
+TEST_SUBMODULE(eval_, m) {
+ // test_evals
+
+ auto global = py::dict(py::module::import("__main__").attr("__dict__"));
+
+ m.def("test_eval_statements", [global]() {
+ auto local = py::dict();
+ local["call_test"] = py::cpp_function([&]() -> int {
+ return 42;
+ });
+
+ // Regular string literal
+ py::exec(
+ "message = 'Hello World!'\n"
+ "x = call_test()",
+ global, local
+ );
+
+ // Multi-line raw string literal
+ py::exec(R"(
+ if x == 42:
+ print(message)
+ else:
+ raise RuntimeError
+ )", global, local
+ );
+ auto x = local["x"].cast<int>();
+
+ return x == 42;
+ });
+
+ m.def("test_eval", [global]() {
+ auto local = py::dict();
+ local["x"] = py::int_(42);
+ auto x = py::eval("x", global, local);
+ return x.cast<int>() == 42;
+ });
+
+ m.def("test_eval_single_statement", []() {
+ auto local = py::dict();
+ local["call_test"] = py::cpp_function([&]() -> int {
+ return 42;
+ });
+
+ auto result = py::eval<py::eval_single_statement>("x = call_test()", py::dict(), local);
+ auto x = local["x"].cast<int>();
+ return result.is_none() && x == 42;
+ });
+
+ m.def("test_eval_file", [global](py::str filename) {
+ auto local = py::dict();
+ local["y"] = py::int_(43);
+
+ int val_out;
+ local["call_test2"] = py::cpp_function([&](int value) { val_out = value; });
+
+ auto result = py::eval_file(filename, global, local);
+ return val_out == 43 && result.is_none();
+ });
+
+ m.def("test_eval_failure", []() {
+ try {
+ py::eval("nonsense code ...");
+ } catch (py::error_already_set &) {
+ return true;
+ }
+ return false;
+ });
+
+ m.def("test_eval_file_failure", []() {
+ try {
+ py::eval_file("non-existing file");
+ } catch (std::exception &) {
+ return true;
+ }
+ return false;
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_eval.py b/3rdparty/pybind11/tests/test_eval.py
new file mode 100644
index 00000000..bda4ef6b
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_eval.py
@@ -0,0 +1,17 @@
+import os
+from pybind11_tests import eval_ as m
+
+
+def test_evals(capture):
+ with capture:
+ assert m.test_eval_statements()
+ assert capture == "Hello World!"
+
+ assert m.test_eval()
+ assert m.test_eval_single_statement()
+
+ filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
+ assert m.test_eval_file(filename)
+
+ assert m.test_eval_failure()
+ assert m.test_eval_file_failure()
diff --git a/3rdparty/pybind11/tests/test_eval_call.py b/3rdparty/pybind11/tests/test_eval_call.py
new file mode 100644
index 00000000..53c7e721
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_eval_call.py
@@ -0,0 +1,4 @@
+# This file is called from 'test_eval.py'
+
+if 'call_test2' in locals():
+ call_test2(y) # noqa: F821 undefined name
diff --git a/3rdparty/pybind11/tests/test_exceptions.cpp b/3rdparty/pybind11/tests/test_exceptions.cpp
new file mode 100644
index 00000000..56cd9bc4
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_exceptions.cpp
@@ -0,0 +1,197 @@
+/*
+ tests/test_custom-exceptions.cpp -- exception translation
+
+ Copyright (c) 2016 Pim Schellart <P.Schellart@princeton.edu>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+// A type that should be raised as an exception in Python
+class MyException : public std::exception {
+public:
+ explicit MyException(const char * m) : message{m} {}
+ virtual const char * what() const noexcept override {return message.c_str();}
+private:
+ std::string message = "";
+};
+
+// A type that should be translated to a standard Python exception
+class MyException2 : public std::exception {
+public:
+ explicit MyException2(const char * m) : message{m} {}
+ virtual const char * what() const noexcept override {return message.c_str();}
+private:
+ std::string message = "";
+};
+
+// A type that is not derived from std::exception (and is thus unknown)
+class MyException3 {
+public:
+ explicit MyException3(const char * m) : message{m} {}
+ virtual const char * what() const noexcept {return message.c_str();}
+private:
+ std::string message = "";
+};
+
+// A type that should be translated to MyException
+// and delegated to its exception translator
+class MyException4 : public std::exception {
+public:
+ explicit MyException4(const char * m) : message{m} {}
+ virtual const char * what() const noexcept override {return message.c_str();}
+private:
+ std::string message = "";
+};
+
+
+// Like the above, but declared via the helper function
+class MyException5 : public std::logic_error {
+public:
+ explicit MyException5(const std::string &what) : std::logic_error(what) {}
+};
+
+// Inherits from MyException5
+class MyException5_1 : public MyException5 {
+ using MyException5::MyException5;
+};
+
+struct PythonCallInDestructor {
+ PythonCallInDestructor(const py::dict &d) : d(d) {}
+ ~PythonCallInDestructor() { d["good"] = true; }
+
+ py::dict d;
+};
+
+TEST_SUBMODULE(exceptions, m) {
+ m.def("throw_std_exception", []() {
+ throw std::runtime_error("This exception was intentionally thrown.");
+ });
+
+ // make a new custom exception and use it as a translation target
+ static py::exception<MyException> ex(m, "MyException");
+ py::register_exception_translator([](std::exception_ptr p) {
+ try {
+ if (p) std::rethrow_exception(p);
+ } catch (const MyException &e) {
+ // Set MyException as the active python error
+ ex(e.what());
+ }
+ });
+
+ // register new translator for MyException2
+ // no need to store anything here because this type will
+ // never by visible from Python
+ py::register_exception_translator([](std::exception_ptr p) {
+ try {
+ if (p) std::rethrow_exception(p);
+ } catch (const MyException2 &e) {
+ // Translate this exception to a standard RuntimeError
+ PyErr_SetString(PyExc_RuntimeError, e.what());
+ }
+ });
+
+ // register new translator for MyException4
+ // which will catch it and delegate to the previously registered
+ // translator for MyException by throwing a new exception
+ py::register_exception_translator([](std::exception_ptr p) {
+ try {
+ if (p) std::rethrow_exception(p);
+ } catch (const MyException4 &e) {
+ throw MyException(e.what());
+ }
+ });
+
+ // A simple exception translation:
+ auto ex5 = py::register_exception<MyException5>(m, "MyException5");
+ // A slightly more complicated one that declares MyException5_1 as a subclass of MyException5
+ py::register_exception<MyException5_1>(m, "MyException5_1", ex5.ptr());
+
+ m.def("throws1", []() { throw MyException("this error should go to a custom type"); });
+ m.def("throws2", []() { throw MyException2("this error should go to a standard Python exception"); });
+ m.def("throws3", []() { throw MyException3("this error cannot be translated"); });
+ m.def("throws4", []() { throw MyException4("this error is rethrown"); });
+ m.def("throws5", []() { throw MyException5("this is a helper-defined translated exception"); });
+ m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); });
+ m.def("throws_logic_error", []() { throw std::logic_error("this error should fall through to the standard handler"); });
+ m.def("throws_overflow_error", []() {throw std::overflow_error(""); });
+ m.def("exception_matches", []() {
+ py::dict foo;
+ try {
+ // Assign to a py::object to force read access of nonexistent dict entry
+ py::object o = foo["bar"];
+ }
+ catch (py::error_already_set& ex) {
+ if (!ex.matches(PyExc_KeyError)) throw;
+ return true;
+ }
+ return false;
+ });
+ m.def("exception_matches_base", []() {
+ py::dict foo;
+ try {
+ // Assign to a py::object to force read access of nonexistent dict entry
+ py::object o = foo["bar"];
+ }
+ catch (py::error_already_set &ex) {
+ if (!ex.matches(PyExc_Exception)) throw;
+ return true;
+ }
+ return false;
+ });
+ m.def("modulenotfound_exception_matches_base", []() {
+ try {
+ // On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError
+ py::module::import("nonexistent");
+ }
+ catch (py::error_already_set &ex) {
+ if (!ex.matches(PyExc_ImportError)) throw;
+ return true;
+ }
+ return false;
+ });
+
+ m.def("throw_already_set", [](bool err) {
+ if (err)
+ PyErr_SetString(PyExc_ValueError, "foo");
+ try {
+ throw py::error_already_set();
+ } catch (const std::runtime_error& e) {
+ if ((err && e.what() != std::string("ValueError: foo")) ||
+ (!err && e.what() != std::string("Unknown internal error occurred")))
+ {
+ PyErr_Clear();
+ throw std::runtime_error("error message mismatch");
+ }
+ }
+ PyErr_Clear();
+ if (err)
+ PyErr_SetString(PyExc_ValueError, "foo");
+ throw py::error_already_set();
+ });
+
+ m.def("python_call_in_destructor", [](py::dict d) {
+ try {
+ PythonCallInDestructor set_dict_in_destructor(d);
+ PyErr_SetString(PyExc_ValueError, "foo");
+ throw py::error_already_set();
+ } catch (const py::error_already_set&) {
+ return true;
+ }
+ return false;
+ });
+
+ // test_nested_throws
+ m.def("try_catch", [m](py::object exc_type, py::function f, py::args args) {
+ try { f(*args); }
+ catch (py::error_already_set &ex) {
+ if (ex.matches(exc_type))
+ py::print(ex.what());
+ else
+ throw;
+ }
+ });
+
+}
diff --git a/3rdparty/pybind11/tests/test_exceptions.py b/3rdparty/pybind11/tests/test_exceptions.py
new file mode 100644
index 00000000..ac2b3603
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_exceptions.py
@@ -0,0 +1,150 @@
+import pytest
+
+from pybind11_tests import exceptions as m
+import pybind11_cross_module_tests as cm
+
+
+def test_std_exception(msg):
+ with pytest.raises(RuntimeError) as excinfo:
+ m.throw_std_exception()
+ assert msg(excinfo.value) == "This exception was intentionally thrown."
+
+
+def test_error_already_set(msg):
+ with pytest.raises(RuntimeError) as excinfo:
+ m.throw_already_set(False)
+ assert msg(excinfo.value) == "Unknown internal error occurred"
+
+ with pytest.raises(ValueError) as excinfo:
+ m.throw_already_set(True)
+ assert msg(excinfo.value) == "foo"
+
+
+def test_cross_module_exceptions():
+ with pytest.raises(RuntimeError) as excinfo:
+ cm.raise_runtime_error()
+ assert str(excinfo.value) == "My runtime error"
+
+ with pytest.raises(ValueError) as excinfo:
+ cm.raise_value_error()
+ assert str(excinfo.value) == "My value error"
+
+ with pytest.raises(ValueError) as excinfo:
+ cm.throw_pybind_value_error()
+ assert str(excinfo.value) == "pybind11 value error"
+
+ with pytest.raises(TypeError) as excinfo:
+ cm.throw_pybind_type_error()
+ assert str(excinfo.value) == "pybind11 type error"
+
+ with pytest.raises(StopIteration) as excinfo:
+ cm.throw_stop_iteration()
+
+
+def test_python_call_in_catch():
+ d = {}
+ assert m.python_call_in_destructor(d) is True
+ assert d["good"] is True
+
+
+def test_exception_matches():
+ assert m.exception_matches()
+ assert m.exception_matches_base()
+ assert m.modulenotfound_exception_matches_base()
+
+
+def test_custom(msg):
+ # Can we catch a MyException?
+ with pytest.raises(m.MyException) as excinfo:
+ m.throws1()
+ assert msg(excinfo.value) == "this error should go to a custom type"
+
+ # Can we translate to standard Python exceptions?
+ with pytest.raises(RuntimeError) as excinfo:
+ m.throws2()
+ assert msg(excinfo.value) == "this error should go to a standard Python exception"
+
+ # Can we handle unknown exceptions?
+ with pytest.raises(RuntimeError) as excinfo:
+ m.throws3()
+ assert msg(excinfo.value) == "Caught an unknown exception!"
+
+ # Can we delegate to another handler by rethrowing?
+ with pytest.raises(m.MyException) as excinfo:
+ m.throws4()
+ assert msg(excinfo.value) == "this error is rethrown"
+
+ # Can we fall-through to the default handler?
+ with pytest.raises(RuntimeError) as excinfo:
+ m.throws_logic_error()
+ assert msg(excinfo.value) == "this error should fall through to the standard handler"
+
+ # OverFlow error translation.
+ with pytest.raises(OverflowError) as excinfo:
+ m.throws_overflow_error()
+
+ # Can we handle a helper-declared exception?
+ with pytest.raises(m.MyException5) as excinfo:
+ m.throws5()
+ assert msg(excinfo.value) == "this is a helper-defined translated exception"
+
+ # Exception subclassing:
+ with pytest.raises(m.MyException5) as excinfo:
+ m.throws5_1()
+ assert msg(excinfo.value) == "MyException5 subclass"
+ assert isinstance(excinfo.value, m.MyException5_1)
+
+ with pytest.raises(m.MyException5_1) as excinfo:
+ m.throws5_1()
+ assert msg(excinfo.value) == "MyException5 subclass"
+
+ with pytest.raises(m.MyException5) as excinfo:
+ try:
+ m.throws5()
+ except m.MyException5_1:
+ raise RuntimeError("Exception error: caught child from parent")
+ assert msg(excinfo.value) == "this is a helper-defined translated exception"
+
+
+def test_nested_throws(capture):
+ """Tests nested (e.g. C++ -> Python -> C++) exception handling"""
+
+ def throw_myex():
+ raise m.MyException("nested error")
+
+ def throw_myex5():
+ raise m.MyException5("nested error 5")
+
+ # In the comments below, the exception is caught in the first step, thrown in the last step
+
+ # C++ -> Python
+ with capture:
+ m.try_catch(m.MyException5, throw_myex5)
+ assert str(capture).startswith("MyException5: nested error 5")
+
+ # Python -> C++ -> Python
+ with pytest.raises(m.MyException) as excinfo:
+ m.try_catch(m.MyException5, throw_myex)
+ assert str(excinfo.value) == "nested error"
+
+ def pycatch(exctype, f, *args):
+ try:
+ f(*args)
+ except m.MyException as e:
+ print(e)
+
+ # C++ -> Python -> C++ -> Python
+ with capture:
+ m.try_catch(
+ m.MyException5, pycatch, m.MyException, m.try_catch, m.MyException, throw_myex5)
+ assert str(capture).startswith("MyException5: nested error 5")
+
+ # C++ -> Python -> C++
+ with capture:
+ m.try_catch(m.MyException, pycatch, m.MyException5, m.throws4)
+ assert capture == "this error is rethrown"
+
+ # Python -> C++ -> Python -> C++
+ with pytest.raises(m.MyException5) as excinfo:
+ m.try_catch(m.MyException, pycatch, m.MyException, m.throws5)
+ assert str(excinfo.value) == "this is a helper-defined translated exception"
diff --git a/3rdparty/pybind11/tests/test_factory_constructors.cpp b/3rdparty/pybind11/tests/test_factory_constructors.cpp
new file mode 100644
index 00000000..5cfbfdc3
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_factory_constructors.cpp
@@ -0,0 +1,338 @@
+/*
+ tests/test_factory_constructors.cpp -- tests construction from a factory function
+ via py::init_factory()
+
+ Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <cmath>
+
+// Classes for testing python construction via C++ factory function:
+// Not publicly constructible, copyable, or movable:
+class TestFactory1 {
+ friend class TestFactoryHelper;
+ TestFactory1() : value("(empty)") { print_default_created(this); }
+ TestFactory1(int v) : value(std::to_string(v)) { print_created(this, value); }
+ TestFactory1(std::string v) : value(std::move(v)) { print_created(this, value); }
+ TestFactory1(TestFactory1 &&) = delete;
+ TestFactory1(const TestFactory1 &) = delete;
+ TestFactory1 &operator=(TestFactory1 &&) = delete;
+ TestFactory1 &operator=(const TestFactory1 &) = delete;
+public:
+ std::string value;
+ ~TestFactory1() { print_destroyed(this); }
+};
+// Non-public construction, but moveable:
+class TestFactory2 {
+ friend class TestFactoryHelper;
+ TestFactory2() : value("(empty2)") { print_default_created(this); }
+ TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); }
+ TestFactory2(std::string v) : value(std::move(v)) { print_created(this, value); }
+public:
+ TestFactory2(TestFactory2 &&m) { value = std::move(m.value); print_move_created(this); }
+ TestFactory2 &operator=(TestFactory2 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; }
+ std::string value;
+ ~TestFactory2() { print_destroyed(this); }
+};
+// Mixed direct/factory construction:
+class TestFactory3 {
+protected:
+ friend class TestFactoryHelper;
+ TestFactory3() : value("(empty3)") { print_default_created(this); }
+ TestFactory3(int v) : value(std::to_string(v)) { print_created(this, value); }
+public:
+ TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); }
+ TestFactory3(TestFactory3 &&m) { value = std::move(m.value); print_move_created(this); }
+ TestFactory3 &operator=(TestFactory3 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; }
+ std::string value;
+ virtual ~TestFactory3() { print_destroyed(this); }
+};
+// Inheritance test
+class TestFactory4 : public TestFactory3 {
+public:
+ TestFactory4() : TestFactory3() { print_default_created(this); }
+ TestFactory4(int v) : TestFactory3(v) { print_created(this, v); }
+ virtual ~TestFactory4() { print_destroyed(this); }
+};
+// Another class for an invalid downcast test
+class TestFactory5 : public TestFactory3 {
+public:
+ TestFactory5(int i) : TestFactory3(i) { print_created(this, i); }
+ virtual ~TestFactory5() { print_destroyed(this); }
+};
+
+class TestFactory6 {
+protected:
+ int value;
+ bool alias = false;
+public:
+ TestFactory6(int i) : value{i} { print_created(this, i); }
+ TestFactory6(TestFactory6 &&f) { print_move_created(this); value = f.value; alias = f.alias; }
+ TestFactory6(const TestFactory6 &f) { print_copy_created(this); value = f.value; alias = f.alias; }
+ virtual ~TestFactory6() { print_destroyed(this); }
+ virtual int get() { return value; }
+ bool has_alias() { return alias; }
+};
+class PyTF6 : public TestFactory6 {
+public:
+ // Special constructor that allows the factory to construct a PyTF6 from a TestFactory6 only
+ // when an alias is needed:
+ PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) { alias = true; print_created(this, "move", value); }
+ PyTF6(int i) : TestFactory6(i) { alias = true; print_created(this, i); }
+ PyTF6(PyTF6 &&f) : TestFactory6(std::move(f)) { print_move_created(this); }
+ PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); }
+ PyTF6(std::string s) : TestFactory6((int) s.size()) { alias = true; print_created(this, s); }
+ virtual ~PyTF6() { print_destroyed(this); }
+ int get() override { PYBIND11_OVERLOAD(int, TestFactory6, get, /*no args*/); }
+};
+
+class TestFactory7 {
+protected:
+ int value;
+ bool alias = false;
+public:
+ TestFactory7(int i) : value{i} { print_created(this, i); }
+ TestFactory7(TestFactory7 &&f) { print_move_created(this); value = f.value; alias = f.alias; }
+ TestFactory7(const TestFactory7 &f) { print_copy_created(this); value = f.value; alias = f.alias; }
+ virtual ~TestFactory7() { print_destroyed(this); }
+ virtual int get() { return value; }
+ bool has_alias() { return alias; }
+};
+class PyTF7 : public TestFactory7 {
+public:
+ PyTF7(int i) : TestFactory7(i) { alias = true; print_created(this, i); }
+ PyTF7(PyTF7 &&f) : TestFactory7(std::move(f)) { print_move_created(this); }
+ PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); }
+ virtual ~PyTF7() { print_destroyed(this); }
+ int get() override { PYBIND11_OVERLOAD(int, TestFactory7, get, /*no args*/); }
+};
+
+
+class TestFactoryHelper {
+public:
+ // Non-movable, non-copyable type:
+ // Return via pointer:
+ static TestFactory1 *construct1() { return new TestFactory1(); }
+ // Holder:
+ static std::unique_ptr<TestFactory1> construct1(int a) { return std::unique_ptr<TestFactory1>(new TestFactory1(a)); }
+ // pointer again
+ static TestFactory1 *construct1_string(std::string a) { return new TestFactory1(a); }
+
+ // Moveable type:
+ // pointer:
+ static TestFactory2 *construct2() { return new TestFactory2(); }
+ // holder:
+ static std::unique_ptr<TestFactory2> construct2(int a) { return std::unique_ptr<TestFactory2>(new TestFactory2(a)); }
+ // by value moving:
+ static TestFactory2 construct2(std::string a) { return TestFactory2(a); }
+
+ // shared_ptr holder type:
+ // pointer:
+ static TestFactory3 *construct3() { return new TestFactory3(); }
+ // holder:
+ static std::shared_ptr<TestFactory3> construct3(int a) { return std::shared_ptr<TestFactory3>(new TestFactory3(a)); }
+};
+
+TEST_SUBMODULE(factory_constructors, m) {
+
+ // Define various trivial types to allow simpler overload resolution:
+ py::module m_tag = m.def_submodule("tag");
+#define MAKE_TAG_TYPE(Name) \
+ struct Name##_tag {}; \
+ py::class_<Name##_tag>(m_tag, #Name "_tag").def(py::init<>()); \
+ m_tag.attr(#Name) = py::cast(Name##_tag{})
+ MAKE_TAG_TYPE(pointer);
+ MAKE_TAG_TYPE(unique_ptr);
+ MAKE_TAG_TYPE(move);
+ MAKE_TAG_TYPE(shared_ptr);
+ MAKE_TAG_TYPE(derived);
+ MAKE_TAG_TYPE(TF4);
+ MAKE_TAG_TYPE(TF5);
+ MAKE_TAG_TYPE(null_ptr);
+ MAKE_TAG_TYPE(base);
+ MAKE_TAG_TYPE(invalid_base);
+ MAKE_TAG_TYPE(alias);
+ MAKE_TAG_TYPE(unaliasable);
+ MAKE_TAG_TYPE(mixed);
+
+ // test_init_factory_basic, test_bad_type
+ py::class_<TestFactory1>(m, "TestFactory1")
+ .def(py::init([](unique_ptr_tag, int v) { return TestFactoryHelper::construct1(v); }))
+ .def(py::init(&TestFactoryHelper::construct1_string)) // raw function pointer
+ .def(py::init([](pointer_tag) { return TestFactoryHelper::construct1(); }))
+ .def(py::init([](py::handle, int v, py::handle) { return TestFactoryHelper::construct1(v); }))
+ .def_readwrite("value", &TestFactory1::value)
+ ;
+ py::class_<TestFactory2>(m, "TestFactory2")
+ .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); }))
+ .def(py::init([](unique_ptr_tag, std::string v) { return TestFactoryHelper::construct2(v); }))
+ .def(py::init([](move_tag) { return TestFactoryHelper::construct2(); }))
+ .def_readwrite("value", &TestFactory2::value)
+ ;
+
+ // Stateful & reused:
+ int c = 1;
+ auto c4a = [c](pointer_tag, TF4_tag, int a) { (void) c; return new TestFactory4(a);};
+
+ // test_init_factory_basic, test_init_factory_casting
+ py::class_<TestFactory3, std::shared_ptr<TestFactory3>>(m, "TestFactory3")
+ .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); }))
+ .def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); }))
+ .def("__init__", [](TestFactory3 &self, std::string v) { new (&self) TestFactory3(v); }) // placement-new ctor
+
+ // factories returning a derived type:
+ .def(py::init(c4a)) // derived ptr
+ .def(py::init([](pointer_tag, TF5_tag, int a) { return new TestFactory5(a); }))
+ // derived shared ptr:
+ .def(py::init([](shared_ptr_tag, TF4_tag, int a) { return std::make_shared<TestFactory4>(a); }))
+ .def(py::init([](shared_ptr_tag, TF5_tag, int a) { return std::make_shared<TestFactory5>(a); }))
+
+ // Returns nullptr:
+ .def(py::init([](null_ptr_tag) { return (TestFactory3 *) nullptr; }))
+
+ .def_readwrite("value", &TestFactory3::value)
+ ;
+
+ // test_init_factory_casting
+ py::class_<TestFactory4, TestFactory3, std::shared_ptr<TestFactory4>>(m, "TestFactory4")
+ .def(py::init(c4a)) // pointer
+ ;
+
+ // Doesn't need to be registered, but registering makes getting ConstructorStats easier:
+ py::class_<TestFactory5, TestFactory3, std::shared_ptr<TestFactory5>>(m, "TestFactory5");
+
+ // test_init_factory_alias
+ // Alias testing
+ py::class_<TestFactory6, PyTF6>(m, "TestFactory6")
+ .def(py::init([](base_tag, int i) { return TestFactory6(i); }))
+ .def(py::init([](alias_tag, int i) { return PyTF6(i); }))
+ .def(py::init([](alias_tag, std::string s) { return PyTF6(s); }))
+ .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); }))
+ .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); }))
+ .def(py::init([](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); }))
+
+ .def("get", &TestFactory6::get)
+ .def("has_alias", &TestFactory6::has_alias)
+
+ .def_static("get_cstats", &ConstructorStats::get<TestFactory6>, py::return_value_policy::reference)
+ .def_static("get_alias_cstats", &ConstructorStats::get<PyTF6>, py::return_value_policy::reference)
+ ;
+
+ // test_init_factory_dual
+ // Separate alias constructor testing
+ py::class_<TestFactory7, PyTF7, std::shared_ptr<TestFactory7>>(m, "TestFactory7")
+ .def(py::init(
+ [](int i) { return TestFactory7(i); },
+ [](int i) { return PyTF7(i); }))
+ .def(py::init(
+ [](pointer_tag, int i) { return new TestFactory7(i); },
+ [](pointer_tag, int i) { return new PyTF7(i); }))
+ .def(py::init(
+ [](mixed_tag, int i) { return new TestFactory7(i); },
+ [](mixed_tag, int i) { return PyTF7(i); }))
+ .def(py::init(
+ [](mixed_tag, std::string s) { return TestFactory7((int) s.size()); },
+ [](mixed_tag, std::string s) { return new PyTF7((int) s.size()); }))
+ .def(py::init(
+ [](base_tag, pointer_tag, int i) { return new TestFactory7(i); },
+ [](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); }))
+ .def(py::init(
+ [](alias_tag, pointer_tag, int i) { return new PyTF7(i); },
+ [](alias_tag, pointer_tag, int i) { return new PyTF7(10*i); }))
+ .def(py::init(
+ [](shared_ptr_tag, base_tag, int i) { return std::make_shared<TestFactory7>(i); },
+ [](shared_ptr_tag, base_tag, int i) { auto *p = new PyTF7(i); return std::shared_ptr<TestFactory7>(p); }))
+ .def(py::init(
+ [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared<TestFactory7>(i); },
+ [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared<TestFactory7>(i); })) // <-- invalid alias factory
+
+ .def("get", &TestFactory7::get)
+ .def("has_alias", &TestFactory7::has_alias)
+
+ .def_static("get_cstats", &ConstructorStats::get<TestFactory7>, py::return_value_policy::reference)
+ .def_static("get_alias_cstats", &ConstructorStats::get<PyTF7>, py::return_value_policy::reference)
+ ;
+
+ // test_placement_new_alternative
+ // Class with a custom new operator but *without* a placement new operator (issue #948)
+ class NoPlacementNew {
+ public:
+ NoPlacementNew(int i) : i(i) { }
+ static void *operator new(std::size_t s) {
+ auto *p = ::operator new(s);
+ py::print("operator new called, returning", reinterpret_cast<uintptr_t>(p));
+ return p;
+ }
+ static void operator delete(void *p) {
+ py::print("operator delete called on", reinterpret_cast<uintptr_t>(p));
+ ::operator delete(p);
+ }
+ int i;
+ };
+ // As of 2.2, `py::init<args>` no longer requires placement new
+ py::class_<NoPlacementNew>(m, "NoPlacementNew")
+ .def(py::init<int>())
+ .def(py::init([]() { return new NoPlacementNew(100); }))
+ .def_readwrite("i", &NoPlacementNew::i)
+ ;
+
+
+ // test_reallocations
+ // Class that has verbose operator_new/operator_delete calls
+ struct NoisyAlloc {
+ NoisyAlloc(const NoisyAlloc &) = default;
+ NoisyAlloc(int i) { py::print(py::str("NoisyAlloc(int {})").format(i)); }
+ NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); }
+ ~NoisyAlloc() { py::print("~NoisyAlloc()"); }
+
+ static void *operator new(size_t s) { py::print("noisy new"); return ::operator new(s); }
+ static void *operator new(size_t, void *p) { py::print("noisy placement new"); return p; }
+ static void operator delete(void *p, size_t) { py::print("noisy delete"); ::operator delete(p); }
+ static void operator delete(void *, void *) { py::print("noisy placement delete"); }
+#if defined(_MSC_VER) && _MSC_VER < 1910
+ // MSVC 2015 bug: the above "noisy delete" isn't invoked (fixed in MSVC 2017)
+ static void operator delete(void *p) { py::print("noisy delete"); ::operator delete(p); }
+#endif
+ };
+ py::class_<NoisyAlloc>(m, "NoisyAlloc")
+ // Since these overloads have the same number of arguments, the dispatcher will try each of
+ // them until the arguments convert. Thus we can get a pre-allocation here when passing a
+ // single non-integer:
+ .def("__init__", [](NoisyAlloc *a, int i) { new (a) NoisyAlloc(i); }) // Regular constructor, runs first, requires preallocation
+ .def(py::init([](double d) { return new NoisyAlloc(d); }))
+
+ // The two-argument version: first the factory pointer overload.
+ .def(py::init([](int i, int) { return new NoisyAlloc(i); }))
+ // Return-by-value:
+ .def(py::init([](double d, int) { return NoisyAlloc(d); }))
+ // Old-style placement new init; requires preallocation
+ .def("__init__", [](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); })
+ // Requires deallocation of previous overload preallocated value:
+ .def(py::init([](int i, double) { return new NoisyAlloc(i); }))
+ // Regular again: requires yet another preallocation
+ .def("__init__", [](NoisyAlloc &a, int i, std::string) { new (&a) NoisyAlloc(i); })
+ ;
+
+
+
+
+ // static_assert testing (the following def's should all fail with appropriate compilation errors):
+#if 0
+ struct BadF1Base {};
+ struct BadF1 : BadF1Base {};
+ struct PyBadF1 : BadF1 {};
+ py::class_<BadF1, PyBadF1, std::shared_ptr<BadF1>> bf1(m, "BadF1");
+ // wrapped factory function must return a compatible pointer, holder, or value
+ bf1.def(py::init([]() { return 3; }));
+ // incompatible factory function pointer return type
+ bf1.def(py::init([]() { static int three = 3; return &three; }));
+ // incompatible factory function std::shared_ptr<T> return type: cannot convert shared_ptr<T> to holder
+ // (non-polymorphic base)
+ bf1.def(py::init([]() { return std::shared_ptr<BadF1Base>(new BadF1()); }));
+#endif
+}
diff --git a/3rdparty/pybind11/tests/test_factory_constructors.py b/3rdparty/pybind11/tests/test_factory_constructors.py
new file mode 100644
index 00000000..78a3910a
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_factory_constructors.py
@@ -0,0 +1,459 @@
+import pytest
+import re
+
+from pybind11_tests import factory_constructors as m
+from pybind11_tests.factory_constructors import tag
+from pybind11_tests import ConstructorStats
+
+
+def test_init_factory_basic():
+ """Tests py::init_factory() wrapper around various ways of returning the object"""
+
+ cstats = [ConstructorStats.get(c) for c in [m.TestFactory1, m.TestFactory2, m.TestFactory3]]
+ cstats[0].alive() # force gc
+ n_inst = ConstructorStats.detail_reg_inst()
+
+ x1 = m.TestFactory1(tag.unique_ptr, 3)
+ assert x1.value == "3"
+ y1 = m.TestFactory1(tag.pointer)
+ assert y1.value == "(empty)"
+ z1 = m.TestFactory1("hi!")
+ assert z1.value == "hi!"
+
+ assert ConstructorStats.detail_reg_inst() == n_inst + 3
+
+ x2 = m.TestFactory2(tag.move)
+ assert x2.value == "(empty2)"
+ y2 = m.TestFactory2(tag.pointer, 7)
+ assert y2.value == "7"
+ z2 = m.TestFactory2(tag.unique_ptr, "hi again")
+ assert z2.value == "hi again"
+
+ assert ConstructorStats.detail_reg_inst() == n_inst + 6
+
+ x3 = m.TestFactory3(tag.shared_ptr)
+ assert x3.value == "(empty3)"
+ y3 = m.TestFactory3(tag.pointer, 42)
+ assert y3.value == "42"
+ z3 = m.TestFactory3("bye")
+ assert z3.value == "bye"
+
+ with pytest.raises(TypeError) as excinfo:
+ m.TestFactory3(tag.null_ptr)
+ assert str(excinfo.value) == "pybind11::init(): factory function returned nullptr"
+
+ assert [i.alive() for i in cstats] == [3, 3, 3]
+ assert ConstructorStats.detail_reg_inst() == n_inst + 9
+
+ del x1, y2, y3, z3
+ assert [i.alive() for i in cstats] == [2, 2, 1]
+ assert ConstructorStats.detail_reg_inst() == n_inst + 5
+ del x2, x3, y1, z1, z2
+ assert [i.alive() for i in cstats] == [0, 0, 0]
+ assert ConstructorStats.detail_reg_inst() == n_inst
+
+ assert [i.values() for i in cstats] == [
+ ["3", "hi!"],
+ ["7", "hi again"],
+ ["42", "bye"]
+ ]
+ assert [i.default_constructions for i in cstats] == [1, 1, 1]
+
+
+def test_init_factory_signature(msg):
+ with pytest.raises(TypeError) as excinfo:
+ m.TestFactory1("invalid", "constructor", "arguments")
+ assert msg(excinfo.value) == """
+ __init__(): incompatible constructor arguments. The following argument types are supported:
+ 1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int)
+ 2. m.factory_constructors.TestFactory1(arg0: str)
+ 3. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.pointer_tag)
+ 4. m.factory_constructors.TestFactory1(arg0: handle, arg1: int, arg2: handle)
+
+ Invoked with: 'invalid', 'constructor', 'arguments'
+ """ # noqa: E501 line too long
+
+ assert msg(m.TestFactory1.__init__.__doc__) == """
+ __init__(*args, **kwargs)
+ Overloaded function.
+
+ 1. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) -> None
+
+ 2. __init__(self: m.factory_constructors.TestFactory1, arg0: str) -> None
+
+ 3. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.pointer_tag) -> None
+
+ 4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None
+ """ # noqa: E501 line too long
+
+
+def test_init_factory_casting():
+ """Tests py::init_factory() wrapper with various upcasting and downcasting returns"""
+
+ cstats = [ConstructorStats.get(c) for c in [m.TestFactory3, m.TestFactory4, m.TestFactory5]]
+ cstats[0].alive() # force gc
+ n_inst = ConstructorStats.detail_reg_inst()
+
+ # Construction from derived references:
+ a = m.TestFactory3(tag.pointer, tag.TF4, 4)
+ assert a.value == "4"
+ b = m.TestFactory3(tag.shared_ptr, tag.TF4, 5)
+ assert b.value == "5"
+ c = m.TestFactory3(tag.pointer, tag.TF5, 6)
+ assert c.value == "6"
+ d = m.TestFactory3(tag.shared_ptr, tag.TF5, 7)
+ assert d.value == "7"
+
+ assert ConstructorStats.detail_reg_inst() == n_inst + 4
+
+ # Shared a lambda with TF3:
+ e = m.TestFactory4(tag.pointer, tag.TF4, 8)
+ assert e.value == "8"
+
+ assert ConstructorStats.detail_reg_inst() == n_inst + 5
+ assert [i.alive() for i in cstats] == [5, 3, 2]
+
+ del a
+ assert [i.alive() for i in cstats] == [4, 2, 2]
+ assert ConstructorStats.detail_reg_inst() == n_inst + 4
+
+ del b, c, e
+ assert [i.alive() for i in cstats] == [1, 0, 1]
+ assert ConstructorStats.detail_reg_inst() == n_inst + 1
+
+ del d
+ assert [i.alive() for i in cstats] == [0, 0, 0]
+ assert ConstructorStats.detail_reg_inst() == n_inst
+
+ assert [i.values() for i in cstats] == [
+ ["4", "5", "6", "7", "8"],
+ ["4", "5", "8"],
+ ["6", "7"]
+ ]
+
+
+def test_init_factory_alias():
+ """Tests py::init_factory() wrapper with value conversions and alias types"""
+
+ cstats = [m.TestFactory6.get_cstats(), m.TestFactory6.get_alias_cstats()]
+ cstats[0].alive() # force gc
+ n_inst = ConstructorStats.detail_reg_inst()
+
+ a = m.TestFactory6(tag.base, 1)
+ assert a.get() == 1
+ assert not a.has_alias()
+ b = m.TestFactory6(tag.alias, "hi there")
+ assert b.get() == 8
+ assert b.has_alias()
+ c = m.TestFactory6(tag.alias, 3)
+ assert c.get() == 3
+ assert c.has_alias()
+ d = m.TestFactory6(tag.alias, tag.pointer, 4)
+ assert d.get() == 4
+ assert d.has_alias()
+ e = m.TestFactory6(tag.base, tag.pointer, 5)
+ assert e.get() == 5
+ assert not e.has_alias()
+ f = m.TestFactory6(tag.base, tag.alias, tag.pointer, 6)
+ assert f.get() == 6
+ assert f.has_alias()
+
+ assert ConstructorStats.detail_reg_inst() == n_inst + 6
+ assert [i.alive() for i in cstats] == [6, 4]
+
+ del a, b, e
+ assert [i.alive() for i in cstats] == [3, 3]
+ assert ConstructorStats.detail_reg_inst() == n_inst + 3
+ del f, c, d
+ assert [i.alive() for i in cstats] == [0, 0]
+ assert ConstructorStats.detail_reg_inst() == n_inst
+
+ class MyTest(m.TestFactory6):
+ def __init__(self, *args):
+ m.TestFactory6.__init__(self, *args)
+
+ def get(self):
+ return -5 + m.TestFactory6.get(self)
+
+ # Return Class by value, moved into new alias:
+ z = MyTest(tag.base, 123)
+ assert z.get() == 118
+ assert z.has_alias()
+
+ # Return alias by value, moved into new alias:
+ y = MyTest(tag.alias, "why hello!")
+ assert y.get() == 5
+ assert y.has_alias()
+
+ # Return Class by pointer, moved into new alias then original destroyed:
+ x = MyTest(tag.base, tag.pointer, 47)
+ assert x.get() == 42
+ assert x.has_alias()
+
+ assert ConstructorStats.detail_reg_inst() == n_inst + 3
+ assert [i.alive() for i in cstats] == [3, 3]
+ del x, y, z
+ assert [i.alive() for i in cstats] == [0, 0]
+ assert ConstructorStats.detail_reg_inst() == n_inst
+
+ assert [i.values() for i in cstats] == [
+ ["1", "8", "3", "4", "5", "6", "123", "10", "47"],
+ ["hi there", "3", "4", "6", "move", "123", "why hello!", "move", "47"]
+ ]
+
+
+def test_init_factory_dual():
+ """Tests init factory functions with dual main/alias factory functions"""
+ from pybind11_tests.factory_constructors import TestFactory7
+
+ cstats = [TestFactory7.get_cstats(), TestFactory7.get_alias_cstats()]
+ cstats[0].alive() # force gc
+ n_inst = ConstructorStats.detail_reg_inst()
+
+ class PythFactory7(TestFactory7):
+ def get(self):
+ return 100 + TestFactory7.get(self)
+
+ a1 = TestFactory7(1)
+ a2 = PythFactory7(2)
+ assert a1.get() == 1
+ assert a2.get() == 102
+ assert not a1.has_alias()
+ assert a2.has_alias()
+
+ b1 = TestFactory7(tag.pointer, 3)
+ b2 = PythFactory7(tag.pointer, 4)
+ assert b1.get() == 3
+ assert b2.get() == 104
+ assert not b1.has_alias()
+ assert b2.has_alias()
+
+ c1 = TestFactory7(tag.mixed, 5)
+ c2 = PythFactory7(tag.mixed, 6)
+ assert c1.get() == 5
+ assert c2.get() == 106
+ assert not c1.has_alias()
+ assert c2.has_alias()
+
+ d1 = TestFactory7(tag.base, tag.pointer, 7)
+ d2 = PythFactory7(tag.base, tag.pointer, 8)
+ assert d1.get() == 7
+ assert d2.get() == 108
+ assert not d1.has_alias()
+ assert d2.has_alias()
+
+ # Both return an alias; the second multiplies the value by 10:
+ e1 = TestFactory7(tag.alias, tag.pointer, 9)
+ e2 = PythFactory7(tag.alias, tag.pointer, 10)
+ assert e1.get() == 9
+ assert e2.get() == 200
+ assert e1.has_alias()
+ assert e2.has_alias()
+
+ f1 = TestFactory7(tag.shared_ptr, tag.base, 11)
+ f2 = PythFactory7(tag.shared_ptr, tag.base, 12)
+ assert f1.get() == 11
+ assert f2.get() == 112
+ assert not f1.has_alias()
+ assert f2.has_alias()
+
+ g1 = TestFactory7(tag.shared_ptr, tag.invalid_base, 13)
+ assert g1.get() == 13
+ assert not g1.has_alias()
+ with pytest.raises(TypeError) as excinfo:
+ PythFactory7(tag.shared_ptr, tag.invalid_base, 14)
+ assert (str(excinfo.value) ==
+ "pybind11::init(): construction failed: returned holder-wrapped instance is not an "
+ "alias instance")
+
+ assert [i.alive() for i in cstats] == [13, 7]
+ assert ConstructorStats.detail_reg_inst() == n_inst + 13
+
+ del a1, a2, b1, d1, e1, e2
+ assert [i.alive() for i in cstats] == [7, 4]
+ assert ConstructorStats.detail_reg_inst() == n_inst + 7
+ del b2, c1, c2, d2, f1, f2, g1
+ assert [i.alive() for i in cstats] == [0, 0]
+ assert ConstructorStats.detail_reg_inst() == n_inst
+
+ assert [i.values() for i in cstats] == [
+ ["1", "2", "3", "4", "5", "6", "7", "8", "9", "100", "11", "12", "13", "14"],
+ ["2", "4", "6", "8", "9", "100", "12"]
+ ]
+
+
+def test_no_placement_new(capture):
+ """Prior to 2.2, `py::init<...>` relied on the type supporting placement
+ new; this tests a class without placement new support."""
+ with capture:
+ a = m.NoPlacementNew(123)
+
+ found = re.search(r'^operator new called, returning (\d+)\n$', str(capture))
+ assert found
+ assert a.i == 123
+ with capture:
+ del a
+ pytest.gc_collect()
+ assert capture == "operator delete called on " + found.group(1)
+
+ with capture:
+ b = m.NoPlacementNew()
+
+ found = re.search(r'^operator new called, returning (\d+)\n$', str(capture))
+ assert found
+ assert b.i == 100
+ with capture:
+ del b
+ pytest.gc_collect()
+ assert capture == "operator delete called on " + found.group(1)
+
+
+def test_multiple_inheritance():
+ class MITest(m.TestFactory1, m.TestFactory2):
+ def __init__(self):
+ m.TestFactory1.__init__(self, tag.unique_ptr, 33)
+ m.TestFactory2.__init__(self, tag.move)
+
+ a = MITest()
+ assert m.TestFactory1.value.fget(a) == "33"
+ assert m.TestFactory2.value.fget(a) == "(empty2)"
+
+
+def create_and_destroy(*args):
+ a = m.NoisyAlloc(*args)
+ print("---")
+ del a
+ pytest.gc_collect()
+
+
+def strip_comments(s):
+ return re.sub(r'\s+#.*', '', s)
+
+
+def test_reallocations(capture, msg):
+ """When the constructor is overloaded, previous overloads can require a preallocated value.
+ This test makes sure that such preallocated values only happen when they might be necessary,
+ and that they are deallocated properly"""
+
+ pytest.gc_collect()
+
+ with capture:
+ create_and_destroy(1)
+ assert msg(capture) == """
+ noisy new
+ noisy placement new
+ NoisyAlloc(int 1)
+ ---
+ ~NoisyAlloc()
+ noisy delete
+ """
+ with capture:
+ create_and_destroy(1.5)
+ assert msg(capture) == strip_comments("""
+ noisy new # allocation required to attempt first overload
+ noisy delete # have to dealloc before considering factory init overload
+ noisy new # pointer factory calling "new", part 1: allocation
+ NoisyAlloc(double 1.5) # ... part two, invoking constructor
+ ---
+ ~NoisyAlloc() # Destructor
+ noisy delete # operator delete
+ """)
+
+ with capture:
+ create_and_destroy(2, 3)
+ assert msg(capture) == strip_comments("""
+ noisy new # pointer factory calling "new", allocation
+ NoisyAlloc(int 2) # constructor
+ ---
+ ~NoisyAlloc() # Destructor
+ noisy delete # operator delete
+ """)
+
+ with capture:
+ create_and_destroy(2.5, 3)
+ assert msg(capture) == strip_comments("""
+ NoisyAlloc(double 2.5) # construction (local func variable: operator_new not called)
+ noisy new # return-by-value "new" part 1: allocation
+ ~NoisyAlloc() # moved-away local func variable destruction
+ ---
+ ~NoisyAlloc() # Destructor
+ noisy delete # operator delete
+ """)
+
+ with capture:
+ create_and_destroy(3.5, 4.5)
+ assert msg(capture) == strip_comments("""
+ noisy new # preallocation needed before invoking placement-new overload
+ noisy placement new # Placement new
+ NoisyAlloc(double 3.5) # construction
+ ---
+ ~NoisyAlloc() # Destructor
+ noisy delete # operator delete
+ """)
+
+ with capture:
+ create_and_destroy(4, 0.5)
+ assert msg(capture) == strip_comments("""
+ noisy new # preallocation needed before invoking placement-new overload
+ noisy delete # deallocation of preallocated storage
+ noisy new # Factory pointer allocation
+ NoisyAlloc(int 4) # factory pointer construction
+ ---
+ ~NoisyAlloc() # Destructor
+ noisy delete # operator delete
+ """)
+
+ with capture:
+ create_and_destroy(5, "hi")
+ assert msg(capture) == strip_comments("""
+ noisy new # preallocation needed before invoking first placement new
+ noisy delete # delete before considering new-style constructor
+ noisy new # preallocation for second placement new
+ noisy placement new # Placement new in the second placement new overload
+ NoisyAlloc(int 5) # construction
+ ---
+ ~NoisyAlloc() # Destructor
+ noisy delete # operator delete
+ """)
+
+
+@pytest.unsupported_on_py2
+def test_invalid_self():
+ """Tests invocation of the pybind-registered base class with an invalid `self` argument. You
+ can only actually do this on Python 3: Python 2 raises an exception itself if you try."""
+ class NotPybindDerived(object):
+ pass
+
+ # Attempts to initialize with an invalid type passed as `self`:
+ class BrokenTF1(m.TestFactory1):
+ def __init__(self, bad):
+ if bad == 1:
+ a = m.TestFactory2(tag.pointer, 1)
+ m.TestFactory1.__init__(a, tag.pointer)
+ elif bad == 2:
+ a = NotPybindDerived()
+ m.TestFactory1.__init__(a, tag.pointer)
+
+ # Same as above, but for a class with an alias:
+ class BrokenTF6(m.TestFactory6):
+ def __init__(self, bad):
+ if bad == 1:
+ a = m.TestFactory2(tag.pointer, 1)
+ m.TestFactory6.__init__(a, tag.base, 1)
+ elif bad == 2:
+ a = m.TestFactory2(tag.pointer, 1)
+ m.TestFactory6.__init__(a, tag.alias, 1)
+ elif bad == 3:
+ m.TestFactory6.__init__(NotPybindDerived.__new__(NotPybindDerived), tag.base, 1)
+ elif bad == 4:
+ m.TestFactory6.__init__(NotPybindDerived.__new__(NotPybindDerived), tag.alias, 1)
+
+ for arg in (1, 2):
+ with pytest.raises(TypeError) as excinfo:
+ BrokenTF1(arg)
+ assert str(excinfo.value) == "__init__(self, ...) called with invalid `self` argument"
+
+ for arg in (1, 2, 3, 4):
+ with pytest.raises(TypeError) as excinfo:
+ BrokenTF6(arg)
+ assert str(excinfo.value) == "__init__(self, ...) called with invalid `self` argument"
diff --git a/3rdparty/pybind11/tests/test_gil_scoped.cpp b/3rdparty/pybind11/tests/test_gil_scoped.cpp
new file mode 100644
index 00000000..76c17fdc
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_gil_scoped.cpp
@@ -0,0 +1,52 @@
+/*
+ tests/test_gil_scoped.cpp -- acquire and release gil
+
+ Copyright (c) 2017 Borja Zarco (Google LLC) <bzarco@google.com>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include <pybind11/functional.h>
+
+
+class VirtClass {
+public:
+ virtual ~VirtClass() {}
+ virtual void virtual_func() {}
+ virtual void pure_virtual_func() = 0;
+};
+
+class PyVirtClass : public VirtClass {
+ void virtual_func() override {
+ PYBIND11_OVERLOAD(void, VirtClass, virtual_func,);
+ }
+ void pure_virtual_func() override {
+ PYBIND11_OVERLOAD_PURE(void, VirtClass, pure_virtual_func,);
+ }
+};
+
+TEST_SUBMODULE(gil_scoped, m) {
+ py::class_<VirtClass, PyVirtClass>(m, "VirtClass")
+ .def(py::init<>())
+ .def("virtual_func", &VirtClass::virtual_func)
+ .def("pure_virtual_func", &VirtClass::pure_virtual_func);
+
+ m.def("test_callback_py_obj",
+ [](py::object func) { func(); });
+ m.def("test_callback_std_func",
+ [](const std::function<void()> &func) { func(); });
+ m.def("test_callback_virtual_func",
+ [](VirtClass &virt) { virt.virtual_func(); });
+ m.def("test_callback_pure_virtual_func",
+ [](VirtClass &virt) { virt.pure_virtual_func(); });
+ m.def("test_cross_module_gil",
+ []() {
+ auto cm = py::module::import("cross_module_gil_utils");
+ auto gil_acquire = reinterpret_cast<void (*)()>(
+ PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr()));
+ py::gil_scoped_release gil_release;
+ gil_acquire();
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_gil_scoped.py b/3rdparty/pybind11/tests/test_gil_scoped.py
new file mode 100644
index 00000000..1548337c
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_gil_scoped.py
@@ -0,0 +1,85 @@
+import multiprocessing
+import threading
+from pybind11_tests import gil_scoped as m
+
+
+def _run_in_process(target, *args, **kwargs):
+ """Runs target in process and returns its exitcode after 10s (None if still alive)."""
+ process = multiprocessing.Process(target=target, args=args, kwargs=kwargs)
+ process.daemon = True
+ try:
+ process.start()
+ # Do not need to wait much, 10s should be more than enough.
+ process.join(timeout=10)
+ return process.exitcode
+ finally:
+ if process.is_alive():
+ process.terminate()
+
+
+def _python_to_cpp_to_python():
+ """Calls different C++ functions that come back to Python."""
+ class ExtendedVirtClass(m.VirtClass):
+ def virtual_func(self):
+ pass
+
+ def pure_virtual_func(self):
+ pass
+
+ extended = ExtendedVirtClass()
+ m.test_callback_py_obj(lambda: None)
+ m.test_callback_std_func(lambda: None)
+ m.test_callback_virtual_func(extended)
+ m.test_callback_pure_virtual_func(extended)
+
+
+def _python_to_cpp_to_python_from_threads(num_threads, parallel=False):
+ """Calls different C++ functions that come back to Python, from Python threads."""
+ threads = []
+ for _ in range(num_threads):
+ thread = threading.Thread(target=_python_to_cpp_to_python)
+ thread.daemon = True
+ thread.start()
+ if parallel:
+ threads.append(thread)
+ else:
+ thread.join()
+ for thread in threads:
+ thread.join()
+
+
+def test_python_to_cpp_to_python_from_thread():
+ """Makes sure there is no GIL deadlock when running in a thread.
+
+ It runs in a separate process to be able to stop and assert if it deadlocks.
+ """
+ assert _run_in_process(_python_to_cpp_to_python_from_threads, 1) == 0
+
+
+def test_python_to_cpp_to_python_from_thread_multiple_parallel():
+ """Makes sure there is no GIL deadlock when running in a thread multiple times in parallel.
+
+ It runs in a separate process to be able to stop and assert if it deadlocks.
+ """
+ assert _run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=True) == 0
+
+
+def test_python_to_cpp_to_python_from_thread_multiple_sequential():
+ """Makes sure there is no GIL deadlock when running in a thread multiple times sequentially.
+
+ It runs in a separate process to be able to stop and assert if it deadlocks.
+ """
+ assert _run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=False) == 0
+
+
+def test_python_to_cpp_to_python_from_process():
+ """Makes sure there is no GIL deadlock when using processes.
+
+ This test is for completion, but it was never an issue.
+ """
+ assert _run_in_process(_python_to_cpp_to_python) == 0
+
+
+def test_cross_module_gil():
+ """Makes sure that the GIL can be acquired by another module from a GIL-released state."""
+ m.test_cross_module_gil() # Should not raise a SIGSEGV
diff --git a/3rdparty/pybind11/tests/test_iostream.cpp b/3rdparty/pybind11/tests/test_iostream.cpp
new file mode 100644
index 00000000..e67f88af
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_iostream.cpp
@@ -0,0 +1,73 @@
+/*
+ tests/test_iostream.cpp -- Usage of scoped_output_redirect
+
+ Copyright (c) 2017 Henry F. Schreiner
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+
+#include <pybind11/iostream.h>
+#include "pybind11_tests.h"
+#include <iostream>
+
+
+void noisy_function(std::string msg, bool flush) {
+
+ std::cout << msg;
+ if (flush)
+ std::cout << std::flush;
+}
+
+void noisy_funct_dual(std::string msg, std::string emsg) {
+ std::cout << msg;
+ std::cerr << emsg;
+}
+
+TEST_SUBMODULE(iostream, m) {
+
+ add_ostream_redirect(m);
+
+ // test_evals
+
+ m.def("captured_output_default", [](std::string msg) {
+ py::scoped_ostream_redirect redir;
+ std::cout << msg << std::flush;
+ });
+
+ m.def("captured_output", [](std::string msg) {
+ py::scoped_ostream_redirect redir(std::cout, py::module::import("sys").attr("stdout"));
+ std::cout << msg << std::flush;
+ });
+
+ m.def("guard_output", &noisy_function,
+ py::call_guard<py::scoped_ostream_redirect>(),
+ py::arg("msg"), py::arg("flush")=true);
+
+ m.def("captured_err", [](std::string msg) {
+ py::scoped_ostream_redirect redir(std::cerr, py::module::import("sys").attr("stderr"));
+ std::cerr << msg << std::flush;
+ });
+
+ m.def("noisy_function", &noisy_function, py::arg("msg"), py::arg("flush") = true);
+
+ m.def("dual_guard", &noisy_funct_dual,
+ py::call_guard<py::scoped_ostream_redirect, py::scoped_estream_redirect>(),
+ py::arg("msg"), py::arg("emsg"));
+
+ m.def("raw_output", [](std::string msg) {
+ std::cout << msg << std::flush;
+ });
+
+ m.def("raw_err", [](std::string msg) {
+ std::cerr << msg << std::flush;
+ });
+
+ m.def("captured_dual", [](std::string msg, std::string emsg) {
+ py::scoped_ostream_redirect redirout(std::cout, py::module::import("sys").attr("stdout"));
+ py::scoped_ostream_redirect redirerr(std::cerr, py::module::import("sys").attr("stderr"));
+ std::cout << msg << std::flush;
+ std::cerr << emsg << std::flush;
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_iostream.py b/3rdparty/pybind11/tests/test_iostream.py
new file mode 100644
index 00000000..27095b27
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_iostream.py
@@ -0,0 +1,214 @@
+from pybind11_tests import iostream as m
+import sys
+
+from contextlib import contextmanager
+
+try:
+ # Python 3
+ from io import StringIO
+except ImportError:
+ # Python 2
+ try:
+ from cStringIO import StringIO
+ except ImportError:
+ from StringIO import StringIO
+
+try:
+ # Python 3.4
+ from contextlib import redirect_stdout
+except ImportError:
+ @contextmanager
+ def redirect_stdout(target):
+ original = sys.stdout
+ sys.stdout = target
+ yield
+ sys.stdout = original
+
+try:
+ # Python 3.5
+ from contextlib import redirect_stderr
+except ImportError:
+ @contextmanager
+ def redirect_stderr(target):
+ original = sys.stderr
+ sys.stderr = target
+ yield
+ sys.stderr = original
+
+
+def test_captured(capsys):
+ msg = "I've been redirected to Python, I hope!"
+ m.captured_output(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == msg
+ assert stderr == ''
+
+ m.captured_output_default(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == msg
+ assert stderr == ''
+
+ m.captured_err(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == ''
+ assert stderr == msg
+
+
+def test_captured_large_string(capsys):
+ # Make this bigger than the buffer used on the C++ side: 1024 chars
+ msg = "I've been redirected to Python, I hope!"
+ msg = msg * (1024 // len(msg) + 1)
+
+ m.captured_output_default(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == msg
+ assert stderr == ''
+
+
+def test_guard_capture(capsys):
+ msg = "I've been redirected to Python, I hope!"
+ m.guard_output(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == msg
+ assert stderr == ''
+
+
+def test_series_captured(capture):
+ with capture:
+ m.captured_output("a")
+ m.captured_output("b")
+ assert capture == "ab"
+
+
+def test_flush(capfd):
+ msg = "(not flushed)"
+ msg2 = "(flushed)"
+
+ with m.ostream_redirect():
+ m.noisy_function(msg, flush=False)
+ stdout, stderr = capfd.readouterr()
+ assert stdout == ''
+
+ m.noisy_function(msg2, flush=True)
+ stdout, stderr = capfd.readouterr()
+ assert stdout == msg + msg2
+
+ m.noisy_function(msg, flush=False)
+
+ stdout, stderr = capfd.readouterr()
+ assert stdout == msg
+
+
+def test_not_captured(capfd):
+ msg = "Something that should not show up in log"
+ stream = StringIO()
+ with redirect_stdout(stream):
+ m.raw_output(msg)
+ stdout, stderr = capfd.readouterr()
+ assert stdout == msg
+ assert stderr == ''
+ assert stream.getvalue() == ''
+
+ stream = StringIO()
+ with redirect_stdout(stream):
+ m.captured_output(msg)
+ stdout, stderr = capfd.readouterr()
+ assert stdout == ''
+ assert stderr == ''
+ assert stream.getvalue() == msg
+
+
+def test_err(capfd):
+ msg = "Something that should not show up in log"
+ stream = StringIO()
+ with redirect_stderr(stream):
+ m.raw_err(msg)
+ stdout, stderr = capfd.readouterr()
+ assert stdout == ''
+ assert stderr == msg
+ assert stream.getvalue() == ''
+
+ stream = StringIO()
+ with redirect_stderr(stream):
+ m.captured_err(msg)
+ stdout, stderr = capfd.readouterr()
+ assert stdout == ''
+ assert stderr == ''
+ assert stream.getvalue() == msg
+
+
+def test_multi_captured(capfd):
+ stream = StringIO()
+ with redirect_stdout(stream):
+ m.captured_output("a")
+ m.raw_output("b")
+ m.captured_output("c")
+ m.raw_output("d")
+ stdout, stderr = capfd.readouterr()
+ assert stdout == 'bd'
+ assert stream.getvalue() == 'ac'
+
+
+def test_dual(capsys):
+ m.captured_dual("a", "b")
+ stdout, stderr = capsys.readouterr()
+ assert stdout == "a"
+ assert stderr == "b"
+
+
+def test_redirect(capfd):
+ msg = "Should not be in log!"
+ stream = StringIO()
+ with redirect_stdout(stream):
+ m.raw_output(msg)
+ stdout, stderr = capfd.readouterr()
+ assert stdout == msg
+ assert stream.getvalue() == ''
+
+ stream = StringIO()
+ with redirect_stdout(stream):
+ with m.ostream_redirect():
+ m.raw_output(msg)
+ stdout, stderr = capfd.readouterr()
+ assert stdout == ''
+ assert stream.getvalue() == msg
+
+ stream = StringIO()
+ with redirect_stdout(stream):
+ m.raw_output(msg)
+ stdout, stderr = capfd.readouterr()
+ assert stdout == msg
+ assert stream.getvalue() == ''
+
+
+def test_redirect_err(capfd):
+ msg = "StdOut"
+ msg2 = "StdErr"
+
+ stream = StringIO()
+ with redirect_stderr(stream):
+ with m.ostream_redirect(stdout=False):
+ m.raw_output(msg)
+ m.raw_err(msg2)
+ stdout, stderr = capfd.readouterr()
+ assert stdout == msg
+ assert stderr == ''
+ assert stream.getvalue() == msg2
+
+
+def test_redirect_both(capfd):
+ msg = "StdOut"
+ msg2 = "StdErr"
+
+ stream = StringIO()
+ stream2 = StringIO()
+ with redirect_stdout(stream):
+ with redirect_stderr(stream2):
+ with m.ostream_redirect():
+ m.raw_output(msg)
+ m.raw_err(msg2)
+ stdout, stderr = capfd.readouterr()
+ assert stdout == ''
+ assert stderr == ''
+ assert stream.getvalue() == msg
+ assert stream2.getvalue() == msg2
diff --git a/3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp b/3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp
new file mode 100644
index 00000000..6563fb9a
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp
@@ -0,0 +1,102 @@
+/*
+ tests/test_kwargs_and_defaults.cpp -- keyword arguments and default values
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/stl.h>
+
+TEST_SUBMODULE(kwargs_and_defaults, m) {
+ auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); };
+
+ // test_named_arguments
+ m.def("kw_func0", kw_func);
+ m.def("kw_func1", kw_func, py::arg("x"), py::arg("y"));
+ m.def("kw_func2", kw_func, py::arg("x") = 100, py::arg("y") = 200);
+ m.def("kw_func3", [](const char *) { }, py::arg("data") = std::string("Hello world!"));
+
+ /* A fancier default argument */
+ std::vector<int> list{{13, 17}};
+ m.def("kw_func4", [](const std::vector<int> &entries) {
+ std::string ret = "{";
+ for (int i : entries)
+ ret += std::to_string(i) + " ";
+ ret.back() = '}';
+ return ret;
+ }, py::arg("myList") = list);
+
+ m.def("kw_func_udl", kw_func, "x"_a, "y"_a=300);
+ m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a=0);
+
+ // test_args_and_kwargs
+ m.def("args_function", [](py::args args) -> py::tuple {
+ return std::move(args);
+ });
+ m.def("args_kwargs_function", [](py::args args, py::kwargs kwargs) {
+ return py::make_tuple(args, kwargs);
+ });
+
+ // test_mixed_args_and_kwargs
+ m.def("mixed_plus_args", [](int i, double j, py::args args) {
+ return py::make_tuple(i, j, args);
+ });
+ m.def("mixed_plus_kwargs", [](int i, double j, py::kwargs kwargs) {
+ return py::make_tuple(i, j, kwargs);
+ });
+ auto mixed_plus_both = [](int i, double j, py::args args, py::kwargs kwargs) {
+ return py::make_tuple(i, j, args, kwargs);
+ };
+ m.def("mixed_plus_args_kwargs", mixed_plus_both);
+
+ m.def("mixed_plus_args_kwargs_defaults", mixed_plus_both,
+ py::arg("i") = 1, py::arg("j") = 3.14159);
+
+ // test_args_refcount
+ // PyPy needs a garbage collection to get the reference count values to match CPython's behaviour
+ #ifdef PYPY_VERSION
+ #define GC_IF_NEEDED ConstructorStats::gc()
+ #else
+ #define GC_IF_NEEDED
+ #endif
+ m.def("arg_refcount_h", [](py::handle h) { GC_IF_NEEDED; return h.ref_count(); });
+ m.def("arg_refcount_h", [](py::handle h, py::handle, py::handle) { GC_IF_NEEDED; return h.ref_count(); });
+ m.def("arg_refcount_o", [](py::object o) { GC_IF_NEEDED; return o.ref_count(); });
+ m.def("args_refcount", [](py::args a) {
+ GC_IF_NEEDED;
+ py::tuple t(a.size());
+ for (size_t i = 0; i < a.size(); i++)
+ // Use raw Python API here to avoid an extra, intermediate incref on the tuple item:
+ t[i] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast<ssize_t>(i)));
+ return t;
+ });
+ m.def("mixed_args_refcount", [](py::object o, py::args a) {
+ GC_IF_NEEDED;
+ py::tuple t(a.size() + 1);
+ t[0] = o.ref_count();
+ for (size_t i = 0; i < a.size(); i++)
+ // Use raw Python API here to avoid an extra, intermediate incref on the tuple item:
+ t[i + 1] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast<ssize_t>(i)));
+ return t;
+ });
+
+ // pybind11 won't allow these to be bound: args and kwargs, if present, must be at the end.
+ // Uncomment these to test that the static_assert is indeed working:
+// m.def("bad_args1", [](py::args, int) {});
+// m.def("bad_args2", [](py::kwargs, int) {});
+// m.def("bad_args3", [](py::kwargs, py::args) {});
+// m.def("bad_args4", [](py::args, int, py::kwargs) {});
+// m.def("bad_args5", [](py::args, py::kwargs, int) {});
+// m.def("bad_args6", [](py::args, py::args) {});
+// m.def("bad_args7", [](py::kwargs, py::kwargs) {});
+
+ // test_function_signatures (along with most of the above)
+ struct KWClass { void foo(int, float) {} };
+ py::class_<KWClass>(m, "KWClass")
+ .def("foo0", &KWClass::foo)
+ .def("foo1", &KWClass::foo, "x"_a, "y"_a);
+}
diff --git a/3rdparty/pybind11/tests/test_kwargs_and_defaults.py b/3rdparty/pybind11/tests/test_kwargs_and_defaults.py
new file mode 100644
index 00000000..27a05a02
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_kwargs_and_defaults.py
@@ -0,0 +1,147 @@
+import pytest
+from pybind11_tests import kwargs_and_defaults as m
+
+
+def test_function_signatures(doc):
+ assert doc(m.kw_func0) == "kw_func0(arg0: int, arg1: int) -> str"
+ assert doc(m.kw_func1) == "kw_func1(x: int, y: int) -> str"
+ assert doc(m.kw_func2) == "kw_func2(x: int = 100, y: int = 200) -> str"
+ assert doc(m.kw_func3) == "kw_func3(data: str = 'Hello world!') -> None"
+ assert doc(m.kw_func4) == "kw_func4(myList: List[int] = [13, 17]) -> str"
+ assert doc(m.kw_func_udl) == "kw_func_udl(x: int, y: int = 300) -> str"
+ assert doc(m.kw_func_udl_z) == "kw_func_udl_z(x: int, y: int = 0) -> str"
+ assert doc(m.args_function) == "args_function(*args) -> tuple"
+ assert doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple"
+ assert doc(m.KWClass.foo0) == \
+ "foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None"
+ assert doc(m.KWClass.foo1) == \
+ "foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None"
+
+
+def test_named_arguments(msg):
+ assert m.kw_func0(5, 10) == "x=5, y=10"
+
+ assert m.kw_func1(5, 10) == "x=5, y=10"
+ assert m.kw_func1(5, y=10) == "x=5, y=10"
+ assert m.kw_func1(y=10, x=5) == "x=5, y=10"
+
+ assert m.kw_func2() == "x=100, y=200"
+ assert m.kw_func2(5) == "x=5, y=200"
+ assert m.kw_func2(x=5) == "x=5, y=200"
+ assert m.kw_func2(y=10) == "x=100, y=10"
+ assert m.kw_func2(5, 10) == "x=5, y=10"
+ assert m.kw_func2(x=5, y=10) == "x=5, y=10"
+
+ with pytest.raises(TypeError) as excinfo:
+ # noinspection PyArgumentList
+ m.kw_func2(x=5, y=10, z=12)
+ assert excinfo.match(
+ r'(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))' + '{3}$')
+
+ assert m.kw_func4() == "{13 17}"
+ assert m.kw_func4(myList=[1, 2, 3]) == "{1 2 3}"
+
+ assert m.kw_func_udl(x=5, y=10) == "x=5, y=10"
+ assert m.kw_func_udl_z(x=5) == "x=5, y=0"
+
+
+def test_arg_and_kwargs():
+ args = 'arg1_value', 'arg2_value', 3
+ assert m.args_function(*args) == args
+
+ args = 'a1', 'a2'
+ kwargs = dict(arg3='a3', arg4=4)
+ assert m.args_kwargs_function(*args, **kwargs) == (args, kwargs)
+
+
+def test_mixed_args_and_kwargs(msg):
+ mpa = m.mixed_plus_args
+ mpk = m.mixed_plus_kwargs
+ mpak = m.mixed_plus_args_kwargs
+ mpakd = m.mixed_plus_args_kwargs_defaults
+
+ assert mpa(1, 2.5, 4, 99.5, None) == (1, 2.5, (4, 99.5, None))
+ assert mpa(1, 2.5) == (1, 2.5, ())
+ with pytest.raises(TypeError) as excinfo:
+ assert mpa(1)
+ assert msg(excinfo.value) == """
+ mixed_plus_args(): incompatible function arguments. The following argument types are supported:
+ 1. (arg0: int, arg1: float, *args) -> tuple
+
+ Invoked with: 1
+ """ # noqa: E501 line too long
+ with pytest.raises(TypeError) as excinfo:
+ assert mpa()
+ assert msg(excinfo.value) == """
+ mixed_plus_args(): incompatible function arguments. The following argument types are supported:
+ 1. (arg0: int, arg1: float, *args) -> tuple
+
+ Invoked with:
+ """ # noqa: E501 line too long
+
+ assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (-2, 3.5, {'e': 2.71828, 'pi': 3.14159})
+ assert mpak(7, 7.7, 7.77, 7.777, 7.7777, minusseven=-7) == (
+ 7, 7.7, (7.77, 7.777, 7.7777), {'minusseven': -7})
+ assert mpakd() == (1, 3.14159, (), {})
+ assert mpakd(3) == (3, 3.14159, (), {})
+ assert mpakd(j=2.71828) == (1, 2.71828, (), {})
+ assert mpakd(k=42) == (1, 3.14159, (), {'k': 42})
+ assert mpakd(1, 1, 2, 3, 5, 8, then=13, followedby=21) == (
+ 1, 1, (2, 3, 5, 8), {'then': 13, 'followedby': 21})
+ # Arguments specified both positionally and via kwargs should fail:
+ with pytest.raises(TypeError) as excinfo:
+ assert mpakd(1, i=1)
+ assert msg(excinfo.value) == """
+ mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:
+ 1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
+
+ Invoked with: 1; kwargs: i=1
+ """ # noqa: E501 line too long
+ with pytest.raises(TypeError) as excinfo:
+ assert mpakd(1, 2, j=1)
+ assert msg(excinfo.value) == """
+ mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:
+ 1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
+
+ Invoked with: 1, 2; kwargs: j=1
+ """ # noqa: E501 line too long
+
+
+def test_args_refcount():
+ """Issue/PR #1216 - py::args elements get double-inc_ref()ed when combined with regular
+ arguments"""
+ refcount = m.arg_refcount_h
+
+ myval = 54321
+ expected = refcount(myval)
+ assert m.arg_refcount_h(myval) == expected
+ assert m.arg_refcount_o(myval) == expected + 1
+ assert m.arg_refcount_h(myval) == expected
+ assert refcount(myval) == expected
+
+ assert m.mixed_plus_args(1, 2.0, "a", myval) == (1, 2.0, ("a", myval))
+ assert refcount(myval) == expected
+
+ assert m.mixed_plus_kwargs(3, 4.0, a=1, b=myval) == (3, 4.0, {"a": 1, "b": myval})
+ assert refcount(myval) == expected
+
+ assert m.args_function(-1, myval) == (-1, myval)
+ assert refcount(myval) == expected
+
+ assert m.mixed_plus_args_kwargs(5, 6.0, myval, a=myval) == (5, 6.0, (myval,), {"a": myval})
+ assert refcount(myval) == expected
+
+ assert m.args_kwargs_function(7, 8, myval, a=1, b=myval) == \
+ ((7, 8, myval), {"a": 1, "b": myval})
+ assert refcount(myval) == expected
+
+ exp3 = refcount(myval, myval, myval)
+ assert m.args_refcount(myval, myval, myval) == (exp3, exp3, exp3)
+ assert refcount(myval) == expected
+
+ # This function takes the first arg as a `py::object` and the rest as a `py::args`. Unlike the
+ # previous case, when we have both positional and `py::args` we need to construct a new tuple
+ # for the `py::args`; in the previous case, we could simply inc_ref and pass on Python's input
+ # tuple without having to inc_ref the individual elements, but here we can't, hence the extra
+ # refs.
+ assert m.mixed_args_refcount(myval, myval, myval) == (exp3 + 3, exp3 + 3, exp3 + 3)
diff --git a/3rdparty/pybind11/tests/test_local_bindings.cpp b/3rdparty/pybind11/tests/test_local_bindings.cpp
new file mode 100644
index 00000000..97c02dbe
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_local_bindings.cpp
@@ -0,0 +1,101 @@
+/*
+ tests/test_local_bindings.cpp -- tests the py::module_local class feature which makes a class
+ binding local to the module in which it is defined.
+
+ Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "local_bindings.h"
+#include <pybind11/stl.h>
+#include <pybind11/stl_bind.h>
+#include <numeric>
+
+TEST_SUBMODULE(local_bindings, m) {
+ // test_load_external
+ m.def("load_external1", [](ExternalType1 &e) { return e.i; });
+ m.def("load_external2", [](ExternalType2 &e) { return e.i; });
+
+ // test_local_bindings
+ // Register a class with py::module_local:
+ bind_local<LocalType, -1>(m, "LocalType", py::module_local())
+ .def("get3", [](LocalType &t) { return t.i + 3; })
+ ;
+
+ m.def("local_value", [](LocalType &l) { return l.i; });
+
+ // test_nonlocal_failure
+ // The main pybind11 test module is loaded first, so this registration will succeed (the second
+ // one, in pybind11_cross_module_tests.cpp, is designed to fail):
+ bind_local<NonLocalType, 0>(m, "NonLocalType")
+ .def(py::init<int>())
+ .def("get", [](LocalType &i) { return i.i; })
+ ;
+
+ // test_duplicate_local
+ // py::module_local declarations should be visible across compilation units that get linked together;
+ // this tries to register a duplicate local. It depends on a definition in test_class.cpp and
+ // should raise a runtime error from the duplicate definition attempt. If test_class isn't
+ // available it *also* throws a runtime error (with "test_class not enabled" as value).
+ m.def("register_local_external", [m]() {
+ auto main = py::module::import("pybind11_tests");
+ if (py::hasattr(main, "class_")) {
+ bind_local<LocalExternal, 7>(m, "LocalExternal", py::module_local());
+ }
+ else throw std::runtime_error("test_class not enabled");
+ });
+
+ // test_stl_bind_local
+ // stl_bind.h binders defaults to py::module_local if the types are local or converting:
+ py::bind_vector<LocalVec>(m, "LocalVec");
+ py::bind_map<LocalMap>(m, "LocalMap");
+ // and global if the type (or one of the types, for the map) is global:
+ py::bind_vector<NonLocalVec>(m, "NonLocalVec");
+ py::bind_map<NonLocalMap>(m, "NonLocalMap");
+
+ // test_stl_bind_global
+ // They can, however, be overridden to global using `py::module_local(false)`:
+ bind_local<NonLocal2, 10>(m, "NonLocal2");
+ py::bind_vector<LocalVec2>(m, "LocalVec2", py::module_local());
+ py::bind_map<NonLocalMap2>(m, "NonLocalMap2", py::module_local(false));
+
+ // test_mixed_local_global
+ // We try this both with the global type registered first and vice versa (the order shouldn't
+ // matter).
+ m.def("register_mixed_global", [m]() {
+ bind_local<MixedGlobalLocal, 100>(m, "MixedGlobalLocal", py::module_local(false));
+ });
+ m.def("register_mixed_local", [m]() {
+ bind_local<MixedLocalGlobal, 1000>(m, "MixedLocalGlobal", py::module_local());
+ });
+ m.def("get_mixed_gl", [](int i) { return MixedGlobalLocal(i); });
+ m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });
+
+ // test_internal_locals_differ
+ m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); });
+
+ // test_stl_caster_vs_stl_bind
+ m.def("load_vector_via_caster", [](std::vector<int> v) {
+ return std::accumulate(v.begin(), v.end(), 0);
+ });
+
+ // test_cross_module_calls
+ m.def("return_self", [](LocalVec *v) { return v; });
+ m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); });
+
+ class Cat : public pets::Pet { public: Cat(std::string name) : Pet(name) {}; };
+ py::class_<pets::Pet>(m, "Pet", py::module_local())
+ .def("get_name", &pets::Pet::name);
+ // Binding for local extending class:
+ py::class_<Cat, pets::Pet>(m, "Cat")
+ .def(py::init<std::string>());
+ m.def("pet_name", [](pets::Pet &p) { return p.name(); });
+
+ py::class_<MixGL>(m, "MixGL").def(py::init<int>());
+ m.def("get_gl_value", [](MixGL &o) { return o.i + 10; });
+
+ py::class_<MixGL2>(m, "MixGL2").def(py::init<int>());
+}
diff --git a/3rdparty/pybind11/tests/test_local_bindings.py b/3rdparty/pybind11/tests/test_local_bindings.py
new file mode 100644
index 00000000..b380376e
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_local_bindings.py
@@ -0,0 +1,226 @@
+import pytest
+
+from pybind11_tests import local_bindings as m
+
+
+def test_load_external():
+ """Load a `py::module_local` type that's only registered in an external module"""
+ import pybind11_cross_module_tests as cm
+
+ assert m.load_external1(cm.ExternalType1(11)) == 11
+ assert m.load_external2(cm.ExternalType2(22)) == 22
+
+ with pytest.raises(TypeError) as excinfo:
+ assert m.load_external2(cm.ExternalType1(21)) == 21
+ assert "incompatible function arguments" in str(excinfo.value)
+
+ with pytest.raises(TypeError) as excinfo:
+ assert m.load_external1(cm.ExternalType2(12)) == 12
+ assert "incompatible function arguments" in str(excinfo.value)
+
+
+def test_local_bindings():
+ """Tests that duplicate `py::module_local` class bindings work across modules"""
+
+ # Make sure we can load the second module with the conflicting (but local) definition:
+ import pybind11_cross_module_tests as cm
+
+ i1 = m.LocalType(5)
+ assert i1.get() == 4
+ assert i1.get3() == 8
+
+ i2 = cm.LocalType(10)
+ assert i2.get() == 11
+ assert i2.get2() == 12
+
+ assert not hasattr(i1, 'get2')
+ assert not hasattr(i2, 'get3')
+
+ # Loading within the local module
+ assert m.local_value(i1) == 5
+ assert cm.local_value(i2) == 10
+
+ # Cross-module loading works as well (on failure, the type loader looks for
+ # external module-local converters):
+ assert m.local_value(i2) == 10
+ assert cm.local_value(i1) == 5
+
+
+def test_nonlocal_failure():
+ """Tests that attempting to register a non-local type in multiple modules fails"""
+ import pybind11_cross_module_tests as cm
+
+ with pytest.raises(RuntimeError) as excinfo:
+ cm.register_nonlocal()
+ assert str(excinfo.value) == 'generic_type: type "NonLocalType" is already registered!'
+
+
+def test_duplicate_local():
+ """Tests expected failure when registering a class twice with py::local in the same module"""
+ with pytest.raises(RuntimeError) as excinfo:
+ m.register_local_external()
+ import pybind11_tests
+ assert str(excinfo.value) == (
+ 'generic_type: type "LocalExternal" is already registered!'
+ if hasattr(pybind11_tests, 'class_') else 'test_class not enabled')
+
+
+def test_stl_bind_local():
+ import pybind11_cross_module_tests as cm
+
+ v1, v2 = m.LocalVec(), cm.LocalVec()
+ v1.append(m.LocalType(1))
+ v1.append(m.LocalType(2))
+ v2.append(cm.LocalType(1))
+ v2.append(cm.LocalType(2))
+
+ # Cross module value loading:
+ v1.append(cm.LocalType(3))
+ v2.append(m.LocalType(3))
+
+ assert [i.get() for i in v1] == [0, 1, 2]
+ assert [i.get() for i in v2] == [2, 3, 4]
+
+ v3, v4 = m.NonLocalVec(), cm.NonLocalVec2()
+ v3.append(m.NonLocalType(1))
+ v3.append(m.NonLocalType(2))
+ v4.append(m.NonLocal2(3))
+ v4.append(m.NonLocal2(4))
+
+ assert [i.get() for i in v3] == [1, 2]
+ assert [i.get() for i in v4] == [13, 14]
+
+ d1, d2 = m.LocalMap(), cm.LocalMap()
+ d1["a"] = v1[0]
+ d1["b"] = v1[1]
+ d2["c"] = v2[0]
+ d2["d"] = v2[1]
+ assert {i: d1[i].get() for i in d1} == {'a': 0, 'b': 1}
+ assert {i: d2[i].get() for i in d2} == {'c': 2, 'd': 3}
+
+
+def test_stl_bind_global():
+ import pybind11_cross_module_tests as cm
+
+ with pytest.raises(RuntimeError) as excinfo:
+ cm.register_nonlocal_map()
+ assert str(excinfo.value) == 'generic_type: type "NonLocalMap" is already registered!'
+
+ with pytest.raises(RuntimeError) as excinfo:
+ cm.register_nonlocal_vec()
+ assert str(excinfo.value) == 'generic_type: type "NonLocalVec" is already registered!'
+
+ with pytest.raises(RuntimeError) as excinfo:
+ cm.register_nonlocal_map2()
+ assert str(excinfo.value) == 'generic_type: type "NonLocalMap2" is already registered!'
+
+
+def test_mixed_local_global():
+ """Local types take precedence over globally registered types: a module with a `module_local`
+ type can be registered even if the type is already registered globally. With the module,
+ casting will go to the local type; outside the module casting goes to the global type."""
+ import pybind11_cross_module_tests as cm
+ m.register_mixed_global()
+ m.register_mixed_local()
+
+ a = []
+ a.append(m.MixedGlobalLocal(1))
+ a.append(m.MixedLocalGlobal(2))
+ a.append(m.get_mixed_gl(3))
+ a.append(m.get_mixed_lg(4))
+
+ assert [x.get() for x in a] == [101, 1002, 103, 1004]
+
+ cm.register_mixed_global_local()
+ cm.register_mixed_local_global()
+ a.append(m.MixedGlobalLocal(5))
+ a.append(m.MixedLocalGlobal(6))
+ a.append(cm.MixedGlobalLocal(7))
+ a.append(cm.MixedLocalGlobal(8))
+ a.append(m.get_mixed_gl(9))
+ a.append(m.get_mixed_lg(10))
+ a.append(cm.get_mixed_gl(11))
+ a.append(cm.get_mixed_lg(12))
+
+ assert [x.get() for x in a] == \
+ [101, 1002, 103, 1004, 105, 1006, 207, 2008, 109, 1010, 211, 2012]
+
+
+def test_internal_locals_differ():
+ """Makes sure the internal local type map differs across the two modules"""
+ import pybind11_cross_module_tests as cm
+ assert m.local_cpp_types_addr() != cm.local_cpp_types_addr()
+
+
+def test_stl_caster_vs_stl_bind(msg):
+ """One module uses a generic vector caster from `<pybind11/stl.h>` while the other
+ exports `std::vector<int>` via `py:bind_vector` and `py::module_local`"""
+ import pybind11_cross_module_tests as cm
+
+ v1 = cm.VectorInt([1, 2, 3])
+ assert m.load_vector_via_caster(v1) == 6
+ assert cm.load_vector_via_binding(v1) == 6
+
+ v2 = [1, 2, 3]
+ assert m.load_vector_via_caster(v2) == 6
+ with pytest.raises(TypeError) as excinfo:
+ cm.load_vector_via_binding(v2) == 6
+ assert msg(excinfo.value) == """
+ load_vector_via_binding(): incompatible function arguments. The following argument types are supported:
+ 1. (arg0: pybind11_cross_module_tests.VectorInt) -> int
+
+ Invoked with: [1, 2, 3]
+ """ # noqa: E501 line too long
+
+
+def test_cross_module_calls():
+ import pybind11_cross_module_tests as cm
+
+ v1 = m.LocalVec()
+ v1.append(m.LocalType(1))
+ v2 = cm.LocalVec()
+ v2.append(cm.LocalType(2))
+
+ # Returning the self pointer should get picked up as returning an existing
+ # instance (even when that instance is of a foreign, non-local type).
+ assert m.return_self(v1) is v1
+ assert cm.return_self(v2) is v2
+ assert m.return_self(v2) is v2
+ assert cm.return_self(v1) is v1
+
+ assert m.LocalVec is not cm.LocalVec
+ # Returning a copy, on the other hand, always goes to the local type,
+ # regardless of where the source type came from.
+ assert type(m.return_copy(v1)) is m.LocalVec
+ assert type(m.return_copy(v2)) is m.LocalVec
+ assert type(cm.return_copy(v1)) is cm.LocalVec
+ assert type(cm.return_copy(v2)) is cm.LocalVec
+
+ # Test the example given in the documentation (which also tests inheritance casting):
+ mycat = m.Cat("Fluffy")
+ mydog = cm.Dog("Rover")
+ assert mycat.get_name() == "Fluffy"
+ assert mydog.name() == "Rover"
+ assert m.Cat.__base__.__name__ == "Pet"
+ assert cm.Dog.__base__.__name__ == "Pet"
+ assert m.Cat.__base__ is not cm.Dog.__base__
+ assert m.pet_name(mycat) == "Fluffy"
+ assert m.pet_name(mydog) == "Rover"
+ assert cm.pet_name(mycat) == "Fluffy"
+ assert cm.pet_name(mydog) == "Rover"
+
+ assert m.MixGL is not cm.MixGL
+ a = m.MixGL(1)
+ b = cm.MixGL(2)
+ assert m.get_gl_value(a) == 11
+ assert m.get_gl_value(b) == 12
+ assert cm.get_gl_value(a) == 101
+ assert cm.get_gl_value(b) == 102
+
+ c, d = m.MixGL2(3), cm.MixGL2(4)
+ with pytest.raises(TypeError) as excinfo:
+ m.get_gl_value(c)
+ assert "incompatible function arguments" in str(excinfo.value)
+ with pytest.raises(TypeError) as excinfo:
+ m.get_gl_value(d)
+ assert "incompatible function arguments" in str(excinfo.value)
diff --git a/3rdparty/pybind11/tests/test_methods_and_attributes.cpp b/3rdparty/pybind11/tests/test_methods_and_attributes.cpp
new file mode 100644
index 00000000..c7b82f13
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_methods_and_attributes.cpp
@@ -0,0 +1,460 @@
+/*
+ tests/test_methods_and_attributes.cpp -- constructors, deconstructors, attribute access,
+ __str__, argument and return value conventions
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+
+#if !defined(PYBIND11_OVERLOAD_CAST)
+template <typename... Args>
+using overload_cast_ = pybind11::detail::overload_cast_impl<Args...>;
+#endif
+
+class ExampleMandA {
+public:
+ ExampleMandA() { print_default_created(this); }
+ ExampleMandA(int value) : value(value) { print_created(this, value); }
+ ExampleMandA(const ExampleMandA &e) : value(e.value) { print_copy_created(this); }
+ ExampleMandA(ExampleMandA &&e) : value(e.value) { print_move_created(this); }
+ ~ExampleMandA() { print_destroyed(this); }
+
+ std::string toString() {
+ return "ExampleMandA[value=" + std::to_string(value) + "]";
+ }
+
+ void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; }
+ void operator=(ExampleMandA &&e) { print_move_assigned(this); value = e.value; }
+
+ void add1(ExampleMandA other) { value += other.value; } // passing by value
+ void add2(ExampleMandA &other) { value += other.value; } // passing by reference
+ void add3(const ExampleMandA &other) { value += other.value; } // passing by const reference
+ void add4(ExampleMandA *other) { value += other->value; } // passing by pointer
+ void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer
+
+ void add6(int other) { value += other; } // passing by value
+ void add7(int &other) { value += other; } // passing by reference
+ void add8(const int &other) { value += other; } // passing by const reference
+ void add9(int *other) { value += *other; } // passing by pointer
+ void add10(const int *other) { value += *other; } // passing by const pointer
+
+ ExampleMandA self1() { return *this; } // return by value
+ ExampleMandA &self2() { return *this; } // return by reference
+ const ExampleMandA &self3() { return *this; } // return by const reference
+ ExampleMandA *self4() { return this; } // return by pointer
+ const ExampleMandA *self5() { return this; } // return by const pointer
+
+ int internal1() { return value; } // return by value
+ int &internal2() { return value; } // return by reference
+ const int &internal3() { return value; } // return by const reference
+ int *internal4() { return &value; } // return by pointer
+ const int *internal5() { return &value; } // return by const pointer
+
+ py::str overloaded() { return "()"; }
+ py::str overloaded(int) { return "(int)"; }
+ py::str overloaded(int, float) { return "(int, float)"; }
+ py::str overloaded(float, int) { return "(float, int)"; }
+ py::str overloaded(int, int) { return "(int, int)"; }
+ py::str overloaded(float, float) { return "(float, float)"; }
+ py::str overloaded(int) const { return "(int) const"; }
+ py::str overloaded(int, float) const { return "(int, float) const"; }
+ py::str overloaded(float, int) const { return "(float, int) const"; }
+ py::str overloaded(int, int) const { return "(int, int) const"; }
+ py::str overloaded(float, float) const { return "(float, float) const"; }
+
+ static py::str overloaded(float) { return "static float"; }
+
+ int value = 0;
+};
+
+struct TestProperties {
+ int value = 1;
+ static int static_value;
+
+ int get() const { return value; }
+ void set(int v) { value = v; }
+
+ static int static_get() { return static_value; }
+ static void static_set(int v) { static_value = v; }
+};
+int TestProperties::static_value = 1;
+
+struct TestPropertiesOverride : TestProperties {
+ int value = 99;
+ static int static_value;
+};
+int TestPropertiesOverride::static_value = 99;
+
+struct TestPropRVP {
+ UserType v1{1};
+ UserType v2{1};
+ static UserType sv1;
+ static UserType sv2;
+
+ const UserType &get1() const { return v1; }
+ const UserType &get2() const { return v2; }
+ UserType get_rvalue() const { return v2; }
+ void set1(int v) { v1.set(v); }
+ void set2(int v) { v2.set(v); }
+};
+UserType TestPropRVP::sv1(1);
+UserType TestPropRVP::sv2(1);
+
+// py::arg/py::arg_v testing: these arguments just record their argument when invoked
+class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; };
+class ArgInspector2 { public: std::string arg = "(default arg inspector 2)"; };
+class ArgAlwaysConverts { };
+namespace pybind11 { namespace detail {
+template <> struct type_caster<ArgInspector1> {
+public:
+ PYBIND11_TYPE_CASTER(ArgInspector1, _("ArgInspector1"));
+
+ bool load(handle src, bool convert) {
+ value.arg = "loading ArgInspector1 argument " +
+ std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. "
+ "Argument value = " + (std::string) str(src);
+ return true;
+ }
+
+ static handle cast(const ArgInspector1 &src, return_value_policy, handle) {
+ return str(src.arg).release();
+ }
+};
+template <> struct type_caster<ArgInspector2> {
+public:
+ PYBIND11_TYPE_CASTER(ArgInspector2, _("ArgInspector2"));
+
+ bool load(handle src, bool convert) {
+ value.arg = "loading ArgInspector2 argument " +
+ std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. "
+ "Argument value = " + (std::string) str(src);
+ return true;
+ }
+
+ static handle cast(const ArgInspector2 &src, return_value_policy, handle) {
+ return str(src.arg).release();
+ }
+};
+template <> struct type_caster<ArgAlwaysConverts> {
+public:
+ PYBIND11_TYPE_CASTER(ArgAlwaysConverts, _("ArgAlwaysConverts"));
+
+ bool load(handle, bool convert) {
+ return convert;
+ }
+
+ static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) {
+ return py::none().release();
+ }
+};
+}}
+
+// test_custom_caster_destruction
+class DestructionTester {
+public:
+ DestructionTester() { print_default_created(this); }
+ ~DestructionTester() { print_destroyed(this); }
+ DestructionTester(const DestructionTester &) { print_copy_created(this); }
+ DestructionTester(DestructionTester &&) { print_move_created(this); }
+ DestructionTester &operator=(const DestructionTester &) { print_copy_assigned(this); return *this; }
+ DestructionTester &operator=(DestructionTester &&) { print_move_assigned(this); return *this; }
+};
+namespace pybind11 { namespace detail {
+template <> struct type_caster<DestructionTester> {
+ PYBIND11_TYPE_CASTER(DestructionTester, _("DestructionTester"));
+ bool load(handle, bool) { return true; }
+
+ static handle cast(const DestructionTester &, return_value_policy, handle) {
+ return py::bool_(true).release();
+ }
+};
+}}
+
+// Test None-allowed py::arg argument policy
+class NoneTester { public: int answer = 42; };
+int none1(const NoneTester &obj) { return obj.answer; }
+int none2(NoneTester *obj) { return obj ? obj->answer : -1; }
+int none3(std::shared_ptr<NoneTester> &obj) { return obj ? obj->answer : -1; }
+int none4(std::shared_ptr<NoneTester> *obj) { return obj && *obj ? (*obj)->answer : -1; }
+int none5(std::shared_ptr<NoneTester> obj) { return obj ? obj->answer : -1; }
+
+struct StrIssue {
+ int val = -1;
+
+ StrIssue() = default;
+ StrIssue(int i) : val{i} {}
+};
+
+// Issues #854, #910: incompatible function args when member function/pointer is in unregistered base class
+class UnregisteredBase {
+public:
+ void do_nothing() const {}
+ void increase_value() { rw_value++; ro_value += 0.25; }
+ void set_int(int v) { rw_value = v; }
+ int get_int() const { return rw_value; }
+ double get_double() const { return ro_value; }
+ int rw_value = 42;
+ double ro_value = 1.25;
+};
+class RegisteredDerived : public UnregisteredBase {
+public:
+ using UnregisteredBase::UnregisteredBase;
+ double sum() const { return rw_value + ro_value; }
+};
+
+TEST_SUBMODULE(methods_and_attributes, m) {
+ // test_methods_and_attributes
+ py::class_<ExampleMandA> emna(m, "ExampleMandA");
+ emna.def(py::init<>())
+ .def(py::init<int>())
+ .def(py::init<const ExampleMandA&>())
+ .def("add1", &ExampleMandA::add1)
+ .def("add2", &ExampleMandA::add2)
+ .def("add3", &ExampleMandA::add3)
+ .def("add4", &ExampleMandA::add4)
+ .def("add5", &ExampleMandA::add5)
+ .def("add6", &ExampleMandA::add6)
+ .def("add7", &ExampleMandA::add7)
+ .def("add8", &ExampleMandA::add8)
+ .def("add9", &ExampleMandA::add9)
+ .def("add10", &ExampleMandA::add10)
+ .def("self1", &ExampleMandA::self1)
+ .def("self2", &ExampleMandA::self2)
+ .def("self3", &ExampleMandA::self3)
+ .def("self4", &ExampleMandA::self4)
+ .def("self5", &ExampleMandA::self5)
+ .def("internal1", &ExampleMandA::internal1)
+ .def("internal2", &ExampleMandA::internal2)
+ .def("internal3", &ExampleMandA::internal3)
+ .def("internal4", &ExampleMandA::internal4)
+ .def("internal5", &ExampleMandA::internal5)
+#if defined(PYBIND11_OVERLOAD_CAST)
+ .def("overloaded", py::overload_cast<>(&ExampleMandA::overloaded))
+ .def("overloaded", py::overload_cast<int>(&ExampleMandA::overloaded))
+ .def("overloaded", py::overload_cast<int, float>(&ExampleMandA::overloaded))
+ .def("overloaded", py::overload_cast<float, int>(&ExampleMandA::overloaded))
+ .def("overloaded", py::overload_cast<int, int>(&ExampleMandA::overloaded))
+ .def("overloaded", py::overload_cast<float, float>(&ExampleMandA::overloaded))
+ .def("overloaded_float", py::overload_cast<float, float>(&ExampleMandA::overloaded))
+ .def("overloaded_const", py::overload_cast<int >(&ExampleMandA::overloaded, py::const_))
+ .def("overloaded_const", py::overload_cast<int, float>(&ExampleMandA::overloaded, py::const_))
+ .def("overloaded_const", py::overload_cast<float, int>(&ExampleMandA::overloaded, py::const_))
+ .def("overloaded_const", py::overload_cast<int, int>(&ExampleMandA::overloaded, py::const_))
+ .def("overloaded_const", py::overload_cast<float, float>(&ExampleMandA::overloaded, py::const_))
+#else
+ // Use both the traditional static_cast method and the C++11 compatible overload_cast_
+ .def("overloaded", overload_cast_<>()(&ExampleMandA::overloaded))
+ .def("overloaded", overload_cast_<int>()(&ExampleMandA::overloaded))
+ .def("overloaded", overload_cast_<int, float>()(&ExampleMandA::overloaded))
+ .def("overloaded", static_cast<py::str (ExampleMandA::*)(float, int)>(&ExampleMandA::overloaded))
+ .def("overloaded", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
+ .def("overloaded", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded))
+ .def("overloaded_float", overload_cast_<float, float>()(&ExampleMandA::overloaded))
+ .def("overloaded_const", overload_cast_<int >()(&ExampleMandA::overloaded, py::const_))
+ .def("overloaded_const", overload_cast_<int, float>()(&ExampleMandA::overloaded, py::const_))
+ .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, int) const>(&ExampleMandA::overloaded))
+ .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, int) const>(&ExampleMandA::overloaded))
+ .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, float) const>(&ExampleMandA::overloaded))
+#endif
+ // test_no_mixed_overloads
+ // Raise error if trying to mix static/non-static overloads on the same name:
+ .def_static("add_mixed_overloads1", []() {
+ auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
+ emna.def ("overload_mixed1", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
+ .def_static("overload_mixed1", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded));
+ })
+ .def_static("add_mixed_overloads2", []() {
+ auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
+ emna.def_static("overload_mixed2", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded))
+ .def ("overload_mixed2", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded));
+ })
+ .def("__str__", &ExampleMandA::toString)
+ .def_readwrite("value", &ExampleMandA::value);
+
+ // test_copy_method
+ // Issue #443: can't call copied methods in Python 3
+ emna.attr("add2b") = emna.attr("add2");
+
+ // test_properties, test_static_properties, test_static_cls
+ py::class_<TestProperties>(m, "TestProperties")
+ .def(py::init<>())
+ .def_readonly("def_readonly", &TestProperties::value)
+ .def_readwrite("def_readwrite", &TestProperties::value)
+ .def_property("def_writeonly", nullptr,
+ [](TestProperties& s,int v) { s.value = v; } )
+ .def_property("def_property_writeonly", nullptr, &TestProperties::set)
+ .def_property_readonly("def_property_readonly", &TestProperties::get)
+ .def_property("def_property", &TestProperties::get, &TestProperties::set)
+ .def_property("def_property_impossible", nullptr, nullptr)
+ .def_readonly_static("def_readonly_static", &TestProperties::static_value)
+ .def_readwrite_static("def_readwrite_static", &TestProperties::static_value)
+ .def_property_static("def_writeonly_static", nullptr,
+ [](py::object, int v) { TestProperties::static_value = v; })
+ .def_property_readonly_static("def_property_readonly_static",
+ [](py::object) { return TestProperties::static_get(); })
+ .def_property_static("def_property_writeonly_static", nullptr,
+ [](py::object, int v) { return TestProperties::static_set(v); })
+ .def_property_static("def_property_static",
+ [](py::object) { return TestProperties::static_get(); },
+ [](py::object, int v) { TestProperties::static_set(v); })
+ .def_property_static("static_cls",
+ [](py::object cls) { return cls; },
+ [](py::object cls, py::function f) { f(cls); });
+
+ py::class_<TestPropertiesOverride, TestProperties>(m, "TestPropertiesOverride")
+ .def(py::init<>())
+ .def_readonly("def_readonly", &TestPropertiesOverride::value)
+ .def_readonly_static("def_readonly_static", &TestPropertiesOverride::static_value);
+
+ auto static_get1 = [](py::object) -> const UserType & { return TestPropRVP::sv1; };
+ auto static_get2 = [](py::object) -> const UserType & { return TestPropRVP::sv2; };
+ auto static_set1 = [](py::object, int v) { TestPropRVP::sv1.set(v); };
+ auto static_set2 = [](py::object, int v) { TestPropRVP::sv2.set(v); };
+ auto rvp_copy = py::return_value_policy::copy;
+
+ // test_property_return_value_policies
+ py::class_<TestPropRVP>(m, "TestPropRVP")
+ .def(py::init<>())
+ .def_property_readonly("ro_ref", &TestPropRVP::get1)
+ .def_property_readonly("ro_copy", &TestPropRVP::get2, rvp_copy)
+ .def_property_readonly("ro_func", py::cpp_function(&TestPropRVP::get2, rvp_copy))
+ .def_property("rw_ref", &TestPropRVP::get1, &TestPropRVP::set1)
+ .def_property("rw_copy", &TestPropRVP::get2, &TestPropRVP::set2, rvp_copy)
+ .def_property("rw_func", py::cpp_function(&TestPropRVP::get2, rvp_copy), &TestPropRVP::set2)
+ .def_property_readonly_static("static_ro_ref", static_get1)
+ .def_property_readonly_static("static_ro_copy", static_get2, rvp_copy)
+ .def_property_readonly_static("static_ro_func", py::cpp_function(static_get2, rvp_copy))
+ .def_property_static("static_rw_ref", static_get1, static_set1)
+ .def_property_static("static_rw_copy", static_get2, static_set2, rvp_copy)
+ .def_property_static("static_rw_func", py::cpp_function(static_get2, rvp_copy), static_set2)
+ // test_property_rvalue_policy
+ .def_property_readonly("rvalue", &TestPropRVP::get_rvalue)
+ .def_property_readonly_static("static_rvalue", [](py::object) { return UserType(1); });
+
+ // test_metaclass_override
+ struct MetaclassOverride { };
+ py::class_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type))
+ .def_property_readonly_static("readonly", [](py::object) { return 1; });
+
+#if !defined(PYPY_VERSION)
+ // test_dynamic_attributes
+ class DynamicClass {
+ public:
+ DynamicClass() { print_default_created(this); }
+ ~DynamicClass() { print_destroyed(this); }
+ };
+ py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr())
+ .def(py::init());
+
+ class CppDerivedDynamicClass : public DynamicClass { };
+ py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass")
+ .def(py::init());
+#endif
+
+ // test_noconvert_args
+ //
+ // Test converting. The ArgAlwaysConverts is just there to make the first no-conversion pass
+ // fail so that our call always ends up happening via the second dispatch (the one that allows
+ // some conversion).
+ class ArgInspector {
+ public:
+ ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; }
+ std::string g(ArgInspector1 a, const ArgInspector1 &b, int c, ArgInspector2 *d, ArgAlwaysConverts) {
+ return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg;
+ }
+ static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; }
+ };
+ py::class_<ArgInspector>(m, "ArgInspector")
+ .def(py::init<>())
+ .def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts())
+ .def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert()=13, "d"_a=ArgInspector2(), py::arg() = ArgAlwaysConverts())
+ .def_static("h", &ArgInspector::h, py::arg().noconvert(), py::arg() = ArgAlwaysConverts())
+ ;
+ m.def("arg_inspect_func", [](ArgInspector2 a, ArgInspector1 b, ArgAlwaysConverts) { return a.arg + "\n" + b.arg; },
+ py::arg().noconvert(false), py::arg_v(nullptr, ArgInspector1()).noconvert(true), py::arg() = ArgAlwaysConverts());
+
+ m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f"));
+ m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert());
+ m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i"));
+ m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert());
+
+ // test_bad_arg_default
+ // Issue/PR #648: bad arg default debugging output
+#if !defined(NDEBUG)
+ m.attr("debug_enabled") = true;
+#else
+ m.attr("debug_enabled") = false;
+#endif
+ m.def("bad_arg_def_named", []{
+ auto m = py::module::import("pybind11_tests");
+ m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg("a") = UnregisteredType());
+ });
+ m.def("bad_arg_def_unnamed", []{
+ auto m = py::module::import("pybind11_tests");
+ m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType());
+ });
+
+ // test_accepts_none
+ py::class_<NoneTester, std::shared_ptr<NoneTester>>(m, "NoneTester")
+ .def(py::init<>());
+ m.def("no_none1", &none1, py::arg().none(false));
+ m.def("no_none2", &none2, py::arg().none(false));
+ m.def("no_none3", &none3, py::arg().none(false));
+ m.def("no_none4", &none4, py::arg().none(false));
+ m.def("no_none5", &none5, py::arg().none(false));
+ m.def("ok_none1", &none1);
+ m.def("ok_none2", &none2, py::arg().none(true));
+ m.def("ok_none3", &none3);
+ m.def("ok_none4", &none4, py::arg().none(true));
+ m.def("ok_none5", &none5);
+
+ // test_str_issue
+ // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
+ py::class_<StrIssue>(m, "StrIssue")
+ .def(py::init<int>())
+ .def(py::init<>())
+ .def("__str__", [](const StrIssue &si) {
+ return "StrIssue[" + std::to_string(si.val) + "]"; }
+ );
+
+ // test_unregistered_base_implementations
+ //
+ // Issues #854/910: incompatible function args when member function/pointer is in unregistered
+ // base class The methods and member pointers below actually resolve to members/pointers in
+ // UnregisteredBase; before this test/fix they would be registered via lambda with a first
+ // argument of an unregistered type, and thus uncallable.
+ py::class_<RegisteredDerived>(m, "RegisteredDerived")
+ .def(py::init<>())
+ .def("do_nothing", &RegisteredDerived::do_nothing)
+ .def("increase_value", &RegisteredDerived::increase_value)
+ .def_readwrite("rw_value", &RegisteredDerived::rw_value)
+ .def_readonly("ro_value", &RegisteredDerived::ro_value)
+ // These should trigger a static_assert if uncommented
+ //.def_readwrite("fails", &UserType::value) // should trigger a static_assert if uncommented
+ //.def_readonly("fails", &UserType::value) // should trigger a static_assert if uncommented
+ .def_property("rw_value_prop", &RegisteredDerived::get_int, &RegisteredDerived::set_int)
+ .def_property_readonly("ro_value_prop", &RegisteredDerived::get_double)
+ // This one is in the registered class:
+ .def("sum", &RegisteredDerived::sum)
+ ;
+
+ using Adapted = decltype(py::method_adaptor<RegisteredDerived>(&RegisteredDerived::do_nothing));
+ static_assert(std::is_same<Adapted, void (RegisteredDerived::*)() const>::value, "");
+
+ // test_custom_caster_destruction
+ // Test that `take_ownership` works on types with a custom type caster when given a pointer
+
+ // default policy: don't take ownership:
+ m.def("custom_caster_no_destroy", []() { static auto *dt = new DestructionTester(); return dt; });
+
+ m.def("custom_caster_destroy", []() { return new DestructionTester(); },
+ py::return_value_policy::take_ownership); // Takes ownership: destroy when finished
+ m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); },
+ py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction)
+ m.def("destruction_tester_cstats", &ConstructorStats::get<DestructionTester>, py::return_value_policy::reference);
+}
diff --git a/3rdparty/pybind11/tests/test_methods_and_attributes.py b/3rdparty/pybind11/tests/test_methods_and_attributes.py
new file mode 100644
index 00000000..f1c862be
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_methods_and_attributes.py
@@ -0,0 +1,512 @@
+import pytest
+from pybind11_tests import methods_and_attributes as m
+from pybind11_tests import ConstructorStats
+
+
+def test_methods_and_attributes():
+ instance1 = m.ExampleMandA()
+ instance2 = m.ExampleMandA(32)
+
+ instance1.add1(instance2)
+ instance1.add2(instance2)
+ instance1.add3(instance2)
+ instance1.add4(instance2)
+ instance1.add5(instance2)
+ instance1.add6(32)
+ instance1.add7(32)
+ instance1.add8(32)
+ instance1.add9(32)
+ instance1.add10(32)
+
+ assert str(instance1) == "ExampleMandA[value=320]"
+ assert str(instance2) == "ExampleMandA[value=32]"
+ assert str(instance1.self1()) == "ExampleMandA[value=320]"
+ assert str(instance1.self2()) == "ExampleMandA[value=320]"
+ assert str(instance1.self3()) == "ExampleMandA[value=320]"
+ assert str(instance1.self4()) == "ExampleMandA[value=320]"
+ assert str(instance1.self5()) == "ExampleMandA[value=320]"
+
+ assert instance1.internal1() == 320
+ assert instance1.internal2() == 320
+ assert instance1.internal3() == 320
+ assert instance1.internal4() == 320
+ assert instance1.internal5() == 320
+
+ assert instance1.overloaded() == "()"
+ assert instance1.overloaded(0) == "(int)"
+ assert instance1.overloaded(1, 1.0) == "(int, float)"
+ assert instance1.overloaded(2.0, 2) == "(float, int)"
+ assert instance1.overloaded(3, 3) == "(int, int)"
+ assert instance1.overloaded(4., 4.) == "(float, float)"
+ assert instance1.overloaded_const(-3) == "(int) const"
+ assert instance1.overloaded_const(5, 5.0) == "(int, float) const"
+ assert instance1.overloaded_const(6.0, 6) == "(float, int) const"
+ assert instance1.overloaded_const(7, 7) == "(int, int) const"
+ assert instance1.overloaded_const(8., 8.) == "(float, float) const"
+ assert instance1.overloaded_float(1, 1) == "(float, float)"
+ assert instance1.overloaded_float(1, 1.) == "(float, float)"
+ assert instance1.overloaded_float(1., 1) == "(float, float)"
+ assert instance1.overloaded_float(1., 1.) == "(float, float)"
+
+ assert instance1.value == 320
+ instance1.value = 100
+ assert str(instance1) == "ExampleMandA[value=100]"
+
+ cstats = ConstructorStats.get(m.ExampleMandA)
+ assert cstats.alive() == 2
+ del instance1, instance2
+ assert cstats.alive() == 0
+ assert cstats.values() == ["32"]
+ assert cstats.default_constructions == 1
+ assert cstats.copy_constructions == 3
+ assert cstats.move_constructions >= 1
+ assert cstats.copy_assignments == 0
+ assert cstats.move_assignments == 0
+
+
+def test_copy_method():
+ """Issue #443: calling copied methods fails in Python 3"""
+
+ m.ExampleMandA.add2c = m.ExampleMandA.add2
+ m.ExampleMandA.add2d = m.ExampleMandA.add2b
+ a = m.ExampleMandA(123)
+ assert a.value == 123
+ a.add2(m.ExampleMandA(-100))
+ assert a.value == 23
+ a.add2b(m.ExampleMandA(20))
+ assert a.value == 43
+ a.add2c(m.ExampleMandA(6))
+ assert a.value == 49
+ a.add2d(m.ExampleMandA(-7))
+ assert a.value == 42
+
+
+def test_properties():
+ instance = m.TestProperties()
+
+ assert instance.def_readonly == 1
+ with pytest.raises(AttributeError):
+ instance.def_readonly = 2
+
+ instance.def_readwrite = 2
+ assert instance.def_readwrite == 2
+
+ assert instance.def_property_readonly == 2
+ with pytest.raises(AttributeError):
+ instance.def_property_readonly = 3
+
+ instance.def_property = 3
+ assert instance.def_property == 3
+
+ with pytest.raises(AttributeError) as excinfo:
+ dummy = instance.def_property_writeonly # noqa: F841 unused var
+ assert "unreadable attribute" in str(excinfo.value)
+
+ instance.def_property_writeonly = 4
+ assert instance.def_property_readonly == 4
+
+ with pytest.raises(AttributeError) as excinfo:
+ dummy = instance.def_property_impossible # noqa: F841 unused var
+ assert "unreadable attribute" in str(excinfo.value)
+
+ with pytest.raises(AttributeError) as excinfo:
+ instance.def_property_impossible = 5
+ assert "can't set attribute" in str(excinfo.value)
+
+
+def test_static_properties():
+ assert m.TestProperties.def_readonly_static == 1
+ with pytest.raises(AttributeError) as excinfo:
+ m.TestProperties.def_readonly_static = 2
+ assert "can't set attribute" in str(excinfo.value)
+
+ m.TestProperties.def_readwrite_static = 2
+ assert m.TestProperties.def_readwrite_static == 2
+
+ with pytest.raises(AttributeError) as excinfo:
+ dummy = m.TestProperties.def_writeonly_static # noqa: F841 unused var
+ assert "unreadable attribute" in str(excinfo.value)
+
+ m.TestProperties.def_writeonly_static = 3
+ assert m.TestProperties.def_readonly_static == 3
+
+ assert m.TestProperties.def_property_readonly_static == 3
+ with pytest.raises(AttributeError) as excinfo:
+ m.TestProperties.def_property_readonly_static = 99
+ assert "can't set attribute" in str(excinfo.value)
+
+ m.TestProperties.def_property_static = 4
+ assert m.TestProperties.def_property_static == 4
+
+ with pytest.raises(AttributeError) as excinfo:
+ dummy = m.TestProperties.def_property_writeonly_static
+ assert "unreadable attribute" in str(excinfo.value)
+
+ m.TestProperties.def_property_writeonly_static = 5
+ assert m.TestProperties.def_property_static == 5
+
+ # Static property read and write via instance
+ instance = m.TestProperties()
+
+ m.TestProperties.def_readwrite_static = 0
+ assert m.TestProperties.def_readwrite_static == 0
+ assert instance.def_readwrite_static == 0
+
+ instance.def_readwrite_static = 2
+ assert m.TestProperties.def_readwrite_static == 2
+ assert instance.def_readwrite_static == 2
+
+ with pytest.raises(AttributeError) as excinfo:
+ dummy = instance.def_property_writeonly_static # noqa: F841 unused var
+ assert "unreadable attribute" in str(excinfo.value)
+
+ instance.def_property_writeonly_static = 4
+ assert instance.def_property_static == 4
+
+ # It should be possible to override properties in derived classes
+ assert m.TestPropertiesOverride().def_readonly == 99
+ assert m.TestPropertiesOverride.def_readonly_static == 99
+
+
+def test_static_cls():
+ """Static property getter and setters expect the type object as the their only argument"""
+
+ instance = m.TestProperties()
+ assert m.TestProperties.static_cls is m.TestProperties
+ assert instance.static_cls is m.TestProperties
+
+ def check_self(self):
+ assert self is m.TestProperties
+
+ m.TestProperties.static_cls = check_self
+ instance.static_cls = check_self
+
+
+def test_metaclass_override():
+ """Overriding pybind11's default metaclass changes the behavior of `static_property`"""
+
+ assert type(m.ExampleMandA).__name__ == "pybind11_type"
+ assert type(m.MetaclassOverride).__name__ == "type"
+
+ assert m.MetaclassOverride.readonly == 1
+ assert type(m.MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property"
+
+ # Regular `type` replaces the property instead of calling `__set__()`
+ m.MetaclassOverride.readonly = 2
+ assert m.MetaclassOverride.readonly == 2
+ assert isinstance(m.MetaclassOverride.__dict__["readonly"], int)
+
+
+def test_no_mixed_overloads():
+ from pybind11_tests import debug_enabled
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.ExampleMandA.add_mixed_overloads1()
+ assert (str(excinfo.value) ==
+ "overloading a method with both static and instance methods is not supported; " +
+ ("compile in debug mode for more details" if not debug_enabled else
+ "error while attempting to bind static method ExampleMandA.overload_mixed1"
+ "(arg0: float) -> str")
+ )
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.ExampleMandA.add_mixed_overloads2()
+ assert (str(excinfo.value) ==
+ "overloading a method with both static and instance methods is not supported; " +
+ ("compile in debug mode for more details" if not debug_enabled else
+ "error while attempting to bind instance method ExampleMandA.overload_mixed2"
+ "(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)"
+ " -> str")
+ )
+
+
+@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
+def test_property_return_value_policies(access):
+ if not access.startswith("static"):
+ obj = m.TestPropRVP()
+ else:
+ obj = m.TestPropRVP
+
+ ref = getattr(obj, access + "_ref")
+ assert ref.value == 1
+ ref.value = 2
+ assert getattr(obj, access + "_ref").value == 2
+ ref.value = 1 # restore original value for static properties
+
+ copy = getattr(obj, access + "_copy")
+ assert copy.value == 1
+ copy.value = 2
+ assert getattr(obj, access + "_copy").value == 1
+
+ copy = getattr(obj, access + "_func")
+ assert copy.value == 1
+ copy.value = 2
+ assert getattr(obj, access + "_func").value == 1
+
+
+def test_property_rvalue_policy():
+ """When returning an rvalue, the return value policy is automatically changed from
+ `reference(_internal)` to `move`. The following would not work otherwise."""
+
+ instance = m.TestPropRVP()
+ o = instance.rvalue
+ assert o.value == 1
+
+ os = m.TestPropRVP.static_rvalue
+ assert os.value == 1
+
+
+# https://bitbucket.org/pypy/pypy/issues/2447
+@pytest.unsupported_on_pypy
+def test_dynamic_attributes():
+ instance = m.DynamicClass()
+ assert not hasattr(instance, "foo")
+ assert "foo" not in dir(instance)
+
+ # Dynamically add attribute
+ instance.foo = 42
+ assert hasattr(instance, "foo")
+ assert instance.foo == 42
+ assert "foo" in dir(instance)
+
+ # __dict__ should be accessible and replaceable
+ assert "foo" in instance.__dict__
+ instance.__dict__ = {"bar": True}
+ assert not hasattr(instance, "foo")
+ assert hasattr(instance, "bar")
+
+ with pytest.raises(TypeError) as excinfo:
+ instance.__dict__ = []
+ assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'"
+
+ cstats = ConstructorStats.get(m.DynamicClass)
+ assert cstats.alive() == 1
+ del instance
+ assert cstats.alive() == 0
+
+ # Derived classes should work as well
+ class PythonDerivedDynamicClass(m.DynamicClass):
+ pass
+
+ for cls in m.CppDerivedDynamicClass, PythonDerivedDynamicClass:
+ derived = cls()
+ derived.foobar = 100
+ assert derived.foobar == 100
+
+ assert cstats.alive() == 1
+ del derived
+ assert cstats.alive() == 0
+
+
+# https://bitbucket.org/pypy/pypy/issues/2447
+@pytest.unsupported_on_pypy
+def test_cyclic_gc():
+ # One object references itself
+ instance = m.DynamicClass()
+ instance.circular_reference = instance
+
+ cstats = ConstructorStats.get(m.DynamicClass)
+ assert cstats.alive() == 1
+ del instance
+ assert cstats.alive() == 0
+
+ # Two object reference each other
+ i1 = m.DynamicClass()
+ i2 = m.DynamicClass()
+ i1.cycle = i2
+ i2.cycle = i1
+
+ assert cstats.alive() == 2
+ del i1, i2
+ assert cstats.alive() == 0
+
+
+def test_noconvert_args(msg):
+ a = m.ArgInspector()
+ assert msg(a.f("hi")) == """
+ loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
+ """
+ assert msg(a.g("this is a", "this is b")) == """
+ loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
+ loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
+ 13
+ loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
+ """ # noqa: E501 line too long
+ assert msg(a.g("this is a", "this is b", 42)) == """
+ loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
+ loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
+ 42
+ loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
+ """ # noqa: E501 line too long
+ assert msg(a.g("this is a", "this is b", 42, "this is d")) == """
+ loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a
+ loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
+ 42
+ loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d
+ """
+ assert (a.h("arg 1") ==
+ "loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1")
+ assert msg(m.arg_inspect_func("A1", "A2")) == """
+ loading ArgInspector2 argument WITH conversion allowed. Argument value = A1
+ loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2
+ """
+
+ assert m.floats_preferred(4) == 2.0
+ assert m.floats_only(4.0) == 2.0
+ with pytest.raises(TypeError) as excinfo:
+ m.floats_only(4)
+ assert msg(excinfo.value) == """
+ floats_only(): incompatible function arguments. The following argument types are supported:
+ 1. (f: float) -> float
+
+ Invoked with: 4
+ """
+
+ assert m.ints_preferred(4) == 2
+ assert m.ints_preferred(True) == 0
+ with pytest.raises(TypeError) as excinfo:
+ m.ints_preferred(4.0)
+ assert msg(excinfo.value) == """
+ ints_preferred(): incompatible function arguments. The following argument types are supported:
+ 1. (i: int) -> int
+
+ Invoked with: 4.0
+ """ # noqa: E501 line too long
+
+ assert m.ints_only(4) == 2
+ with pytest.raises(TypeError) as excinfo:
+ m.ints_only(4.0)
+ assert msg(excinfo.value) == """
+ ints_only(): incompatible function arguments. The following argument types are supported:
+ 1. (i: int) -> int
+
+ Invoked with: 4.0
+ """
+
+
+def test_bad_arg_default(msg):
+ from pybind11_tests import debug_enabled
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.bad_arg_def_named()
+ assert msg(excinfo.value) == (
+ "arg(): could not convert default argument 'a: UnregisteredType' in function "
+ "'should_fail' into a Python object (type not registered yet?)"
+ if debug_enabled else
+ "arg(): could not convert default argument into a Python object (type not registered "
+ "yet?). Compile in debug mode for more information."
+ )
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.bad_arg_def_unnamed()
+ assert msg(excinfo.value) == (
+ "arg(): could not convert default argument 'UnregisteredType' in function "
+ "'should_fail' into a Python object (type not registered yet?)"
+ if debug_enabled else
+ "arg(): could not convert default argument into a Python object (type not registered "
+ "yet?). Compile in debug mode for more information."
+ )
+
+
+def test_accepts_none(msg):
+ a = m.NoneTester()
+ assert m.no_none1(a) == 42
+ assert m.no_none2(a) == 42
+ assert m.no_none3(a) == 42
+ assert m.no_none4(a) == 42
+ assert m.no_none5(a) == 42
+ assert m.ok_none1(a) == 42
+ assert m.ok_none2(a) == 42
+ assert m.ok_none3(a) == 42
+ assert m.ok_none4(a) == 42
+ assert m.ok_none5(a) == 42
+
+ with pytest.raises(TypeError) as excinfo:
+ m.no_none1(None)
+ assert "incompatible function arguments" in str(excinfo.value)
+ with pytest.raises(TypeError) as excinfo:
+ m.no_none2(None)
+ assert "incompatible function arguments" in str(excinfo.value)
+ with pytest.raises(TypeError) as excinfo:
+ m.no_none3(None)
+ assert "incompatible function arguments" in str(excinfo.value)
+ with pytest.raises(TypeError) as excinfo:
+ m.no_none4(None)
+ assert "incompatible function arguments" in str(excinfo.value)
+ with pytest.raises(TypeError) as excinfo:
+ m.no_none5(None)
+ assert "incompatible function arguments" in str(excinfo.value)
+
+ # The first one still raises because you can't pass None as a lvalue reference arg:
+ with pytest.raises(TypeError) as excinfo:
+ assert m.ok_none1(None) == -1
+ assert msg(excinfo.value) == """
+ ok_none1(): incompatible function arguments. The following argument types are supported:
+ 1. (arg0: m.methods_and_attributes.NoneTester) -> int
+
+ Invoked with: None
+ """
+
+ # The rest take the argument as pointer or holder, and accept None:
+ assert m.ok_none2(None) == -1
+ assert m.ok_none3(None) == -1
+ assert m.ok_none4(None) == -1
+ assert m.ok_none5(None) == -1
+
+
+def test_str_issue(msg):
+ """#283: __str__ called on uninitialized instance when constructor arguments invalid"""
+
+ assert str(m.StrIssue(3)) == "StrIssue[3]"
+
+ with pytest.raises(TypeError) as excinfo:
+ str(m.StrIssue("no", "such", "constructor"))
+ assert msg(excinfo.value) == """
+ __init__(): incompatible constructor arguments. The following argument types are supported:
+ 1. m.methods_and_attributes.StrIssue(arg0: int)
+ 2. m.methods_and_attributes.StrIssue()
+
+ Invoked with: 'no', 'such', 'constructor'
+ """
+
+
+def test_unregistered_base_implementations():
+ a = m.RegisteredDerived()
+ a.do_nothing()
+ assert a.rw_value == 42
+ assert a.ro_value == 1.25
+ a.rw_value += 5
+ assert a.sum() == 48.25
+ a.increase_value()
+ assert a.rw_value == 48
+ assert a.ro_value == 1.5
+ assert a.sum() == 49.5
+ assert a.rw_value_prop == 48
+ a.rw_value_prop += 1
+ assert a.rw_value_prop == 49
+ a.increase_value()
+ assert a.ro_value_prop == 1.75
+
+
+def test_custom_caster_destruction():
+ """Tests that returning a pointer to a type that gets converted with a custom type caster gets
+ destroyed when the function has py::return_value_policy::take_ownership policy applied."""
+
+ cstats = m.destruction_tester_cstats()
+ # This one *doesn't* have take_ownership: the pointer should be used but not destroyed:
+ z = m.custom_caster_no_destroy()
+ assert cstats.alive() == 1 and cstats.default_constructions == 1
+ assert z
+
+ # take_ownership applied: this constructs a new object, casts it, then destroys it:
+ z = m.custom_caster_destroy()
+ assert z
+ assert cstats.default_constructions == 2
+
+ # Same, but with a const pointer return (which should *not* inhibit destruction):
+ z = m.custom_caster_destroy_const()
+ assert z
+ assert cstats.default_constructions == 3
+
+ # Make sure we still only have the original object (from ..._no_destroy()) alive:
+ assert cstats.alive() == 1
diff --git a/3rdparty/pybind11/tests/test_modules.cpp b/3rdparty/pybind11/tests/test_modules.cpp
new file mode 100644
index 00000000..c1475fa6
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_modules.cpp
@@ -0,0 +1,98 @@
+/*
+ tests/test_modules.cpp -- nested modules, importing modules, and
+ internal references
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+
+TEST_SUBMODULE(modules, m) {
+ // test_nested_modules
+ py::module m_sub = m.def_submodule("subsubmodule");
+ m_sub.def("submodule_func", []() { return "submodule_func()"; });
+
+ // test_reference_internal
+ class A {
+ public:
+ A(int v) : v(v) { print_created(this, v); }
+ ~A() { print_destroyed(this); }
+ A(const A&) { print_copy_created(this); }
+ A& operator=(const A &copy) { print_copy_assigned(this); v = copy.v; return *this; }
+ std::string toString() { return "A[" + std::to_string(v) + "]"; }
+ private:
+ int v;
+ };
+ py::class_<A>(m_sub, "A")
+ .def(py::init<int>())
+ .def("__repr__", &A::toString);
+
+ class B {
+ public:
+ B() { print_default_created(this); }
+ ~B() { print_destroyed(this); }
+ B(const B&) { print_copy_created(this); }
+ B& operator=(const B &copy) { print_copy_assigned(this); a1 = copy.a1; a2 = copy.a2; return *this; }
+ A &get_a1() { return a1; }
+ A &get_a2() { return a2; }
+
+ A a1{1};
+ A a2{2};
+ };
+ py::class_<B>(m_sub, "B")
+ .def(py::init<>())
+ .def("get_a1", &B::get_a1, "Return the internal A 1", py::return_value_policy::reference_internal)
+ .def("get_a2", &B::get_a2, "Return the internal A 2", py::return_value_policy::reference_internal)
+ .def_readwrite("a1", &B::a1) // def_readonly uses an internal reference return policy by default
+ .def_readwrite("a2", &B::a2);
+
+ m.attr("OD") = py::module::import("collections").attr("OrderedDict");
+
+ // test_duplicate_registration
+ // Registering two things with the same name
+ m.def("duplicate_registration", []() {
+ class Dupe1 { };
+ class Dupe2 { };
+ class Dupe3 { };
+ class DupeException { };
+
+ auto dm = py::module("dummy");
+ auto failures = py::list();
+
+ py::class_<Dupe1>(dm, "Dupe1");
+ py::class_<Dupe2>(dm, "Dupe2");
+ dm.def("dupe1_factory", []() { return Dupe1(); });
+ py::exception<DupeException>(dm, "DupeException");
+
+ try {
+ py::class_<Dupe1>(dm, "Dupe1");
+ failures.append("Dupe1 class");
+ } catch (std::runtime_error &) {}
+ try {
+ dm.def("Dupe1", []() { return Dupe1(); });
+ failures.append("Dupe1 function");
+ } catch (std::runtime_error &) {}
+ try {
+ py::class_<Dupe3>(dm, "dupe1_factory");
+ failures.append("dupe1_factory");
+ } catch (std::runtime_error &) {}
+ try {
+ py::exception<Dupe3>(dm, "Dupe2");
+ failures.append("Dupe2");
+ } catch (std::runtime_error &) {}
+ try {
+ dm.def("DupeException", []() { return 30; });
+ failures.append("DupeException1");
+ } catch (std::runtime_error &) {}
+ try {
+ py::class_<DupeException>(dm, "DupeException");
+ failures.append("DupeException2");
+ } catch (std::runtime_error &) {}
+
+ return failures;
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_modules.py b/3rdparty/pybind11/tests/test_modules.py
new file mode 100644
index 00000000..2552838c
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_modules.py
@@ -0,0 +1,72 @@
+from pybind11_tests import modules as m
+from pybind11_tests.modules import subsubmodule as ms
+from pybind11_tests import ConstructorStats
+
+
+def test_nested_modules():
+ import pybind11_tests
+ assert pybind11_tests.__name__ == "pybind11_tests"
+ assert pybind11_tests.modules.__name__ == "pybind11_tests.modules"
+ assert pybind11_tests.modules.subsubmodule.__name__ == "pybind11_tests.modules.subsubmodule"
+ assert m.__name__ == "pybind11_tests.modules"
+ assert ms.__name__ == "pybind11_tests.modules.subsubmodule"
+
+ assert ms.submodule_func() == "submodule_func()"
+
+
+def test_reference_internal():
+ b = ms.B()
+ assert str(b.get_a1()) == "A[1]"
+ assert str(b.a1) == "A[1]"
+ assert str(b.get_a2()) == "A[2]"
+ assert str(b.a2) == "A[2]"
+
+ b.a1 = ms.A(42)
+ b.a2 = ms.A(43)
+ assert str(b.get_a1()) == "A[42]"
+ assert str(b.a1) == "A[42]"
+ assert str(b.get_a2()) == "A[43]"
+ assert str(b.a2) == "A[43]"
+
+ astats, bstats = ConstructorStats.get(ms.A), ConstructorStats.get(ms.B)
+ assert astats.alive() == 2
+ assert bstats.alive() == 1
+ del b
+ assert astats.alive() == 0
+ assert bstats.alive() == 0
+ assert astats.values() == ['1', '2', '42', '43']
+ assert bstats.values() == []
+ assert astats.default_constructions == 0
+ assert bstats.default_constructions == 1
+ assert astats.copy_constructions == 0
+ assert bstats.copy_constructions == 0
+ # assert astats.move_constructions >= 0 # Don't invoke any
+ # assert bstats.move_constructions >= 0 # Don't invoke any
+ assert astats.copy_assignments == 2
+ assert bstats.copy_assignments == 0
+ assert astats.move_assignments == 0
+ assert bstats.move_assignments == 0
+
+
+def test_importing():
+ from pybind11_tests.modules import OD
+ from collections import OrderedDict
+
+ assert OD is OrderedDict
+ assert str(OD([(1, 'a'), (2, 'b')])) == "OrderedDict([(1, 'a'), (2, 'b')])"
+
+
+def test_pydoc():
+ """Pydoc needs to be able to provide help() for everything inside a pybind11 module"""
+ import pybind11_tests
+ import pydoc
+
+ assert pybind11_tests.__name__ == "pybind11_tests"
+ assert pybind11_tests.__doc__ == "pybind11 test module"
+ assert pydoc.text.docmodule(pybind11_tests)
+
+
+def test_duplicate_registration():
+ """Registering two things with the same name"""
+
+ assert m.duplicate_registration() == []
diff --git a/3rdparty/pybind11/tests/test_multiple_inheritance.cpp b/3rdparty/pybind11/tests/test_multiple_inheritance.cpp
new file mode 100644
index 00000000..ba1674fb
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_multiple_inheritance.cpp
@@ -0,0 +1,220 @@
+/*
+ tests/test_multiple_inheritance.cpp -- multiple inheritance,
+ implicit MI casts
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+
+// Many bases for testing that multiple inheritance from many classes (i.e. requiring extra
+// space for holder constructed flags) works.
+template <int N> struct BaseN {
+ BaseN(int i) : i(i) { }
+ int i;
+};
+
+// test_mi_static_properties
+struct Vanilla {
+ std::string vanilla() { return "Vanilla"; };
+};
+struct WithStatic1 {
+ static std::string static_func1() { return "WithStatic1"; };
+ static int static_value1;
+};
+struct WithStatic2 {
+ static std::string static_func2() { return "WithStatic2"; };
+ static int static_value2;
+};
+struct VanillaStaticMix1 : Vanilla, WithStatic1, WithStatic2 {
+ static std::string static_func() { return "VanillaStaticMix1"; }
+ static int static_value;
+};
+struct VanillaStaticMix2 : WithStatic1, Vanilla, WithStatic2 {
+ static std::string static_func() { return "VanillaStaticMix2"; }
+ static int static_value;
+};
+int WithStatic1::static_value1 = 1;
+int WithStatic2::static_value2 = 2;
+int VanillaStaticMix1::static_value = 12;
+int VanillaStaticMix2::static_value = 12;
+
+TEST_SUBMODULE(multiple_inheritance, m) {
+
+ // test_multiple_inheritance_mix1
+ // test_multiple_inheritance_mix2
+ struct Base1 {
+ Base1(int i) : i(i) { }
+ int foo() { return i; }
+ int i;
+ };
+ py::class_<Base1> b1(m, "Base1");
+ b1.def(py::init<int>())
+ .def("foo", &Base1::foo);
+
+ struct Base2 {
+ Base2(int i) : i(i) { }
+ int bar() { return i; }
+ int i;
+ };
+ py::class_<Base2> b2(m, "Base2");
+ b2.def(py::init<int>())
+ .def("bar", &Base2::bar);
+
+
+ // test_multiple_inheritance_cpp
+ struct Base12 : Base1, Base2 {
+ Base12(int i, int j) : Base1(i), Base2(j) { }
+ };
+ struct MIType : Base12 {
+ MIType(int i, int j) : Base12(i, j) { }
+ };
+ py::class_<Base12, Base1, Base2>(m, "Base12");
+ py::class_<MIType, Base12>(m, "MIType")
+ .def(py::init<int, int>());
+
+
+ // test_multiple_inheritance_python_many_bases
+ #define PYBIND11_BASEN(N) py::class_<BaseN<N>>(m, "BaseN" #N).def(py::init<int>()).def("f" #N, [](BaseN<N> &b) { return b.i + N; })
+ PYBIND11_BASEN( 1); PYBIND11_BASEN( 2); PYBIND11_BASEN( 3); PYBIND11_BASEN( 4);
+ PYBIND11_BASEN( 5); PYBIND11_BASEN( 6); PYBIND11_BASEN( 7); PYBIND11_BASEN( 8);
+ PYBIND11_BASEN( 9); PYBIND11_BASEN(10); PYBIND11_BASEN(11); PYBIND11_BASEN(12);
+ PYBIND11_BASEN(13); PYBIND11_BASEN(14); PYBIND11_BASEN(15); PYBIND11_BASEN(16);
+ PYBIND11_BASEN(17);
+
+ // Uncommenting this should result in a compile time failure (MI can only be specified via
+ // template parameters because pybind has to know the types involved; see discussion in #742 for
+ // details).
+// struct Base12v2 : Base1, Base2 {
+// Base12v2(int i, int j) : Base1(i), Base2(j) { }
+// };
+// py::class_<Base12v2>(m, "Base12v2", b1, b2)
+// .def(py::init<int, int>());
+
+
+ // test_multiple_inheritance_virtbase
+ // Test the case where not all base classes are specified, and where pybind11 requires the
+ // py::multiple_inheritance flag to perform proper casting between types.
+ struct Base1a {
+ Base1a(int i) : i(i) { }
+ int foo() { return i; }
+ int i;
+ };
+ py::class_<Base1a, std::shared_ptr<Base1a>>(m, "Base1a")
+ .def(py::init<int>())
+ .def("foo", &Base1a::foo);
+
+ struct Base2a {
+ Base2a(int i) : i(i) { }
+ int bar() { return i; }
+ int i;
+ };
+ py::class_<Base2a, std::shared_ptr<Base2a>>(m, "Base2a")
+ .def(py::init<int>())
+ .def("bar", &Base2a::bar);
+
+ struct Base12a : Base1a, Base2a {
+ Base12a(int i, int j) : Base1a(i), Base2a(j) { }
+ };
+ py::class_<Base12a, /* Base1 missing */ Base2a,
+ std::shared_ptr<Base12a>>(m, "Base12a", py::multiple_inheritance())
+ .def(py::init<int, int>());
+
+ m.def("bar_base2a", [](Base2a *b) { return b->bar(); });
+ m.def("bar_base2a_sharedptr", [](std::shared_ptr<Base2a> b) { return b->bar(); });
+
+ // test_mi_unaligned_base
+ // test_mi_base_return
+ // Issue #801: invalid casting to derived type with MI bases
+ struct I801B1 { int a = 1; I801B1() = default; I801B1(const I801B1 &) = default; virtual ~I801B1() = default; };
+ struct I801B2 { int b = 2; I801B2() = default; I801B2(const I801B2 &) = default; virtual ~I801B2() = default; };
+ struct I801C : I801B1, I801B2 {};
+ struct I801D : I801C {}; // Indirect MI
+ // Unregistered classes:
+ struct I801B3 { int c = 3; virtual ~I801B3() = default; };
+ struct I801E : I801B3, I801D {};
+
+ py::class_<I801B1, std::shared_ptr<I801B1>>(m, "I801B1").def(py::init<>()).def_readonly("a", &I801B1::a);
+ py::class_<I801B2, std::shared_ptr<I801B2>>(m, "I801B2").def(py::init<>()).def_readonly("b", &I801B2::b);
+ py::class_<I801C, I801B1, I801B2, std::shared_ptr<I801C>>(m, "I801C").def(py::init<>());
+ py::class_<I801D, I801C, std::shared_ptr<I801D>>(m, "I801D").def(py::init<>());
+
+ // Two separate issues here: first, we want to recognize a pointer to a base type as being a
+ // known instance even when the pointer value is unequal (i.e. due to a non-first
+ // multiple-inheritance base class):
+ m.def("i801b1_c", [](I801C *c) { return static_cast<I801B1 *>(c); });
+ m.def("i801b2_c", [](I801C *c) { return static_cast<I801B2 *>(c); });
+ m.def("i801b1_d", [](I801D *d) { return static_cast<I801B1 *>(d); });
+ m.def("i801b2_d", [](I801D *d) { return static_cast<I801B2 *>(d); });
+
+ // Second, when returned a base class pointer to a derived instance, we cannot assume that the
+ // pointer is `reinterpret_cast`able to the derived pointer because, like above, the base class
+ // pointer could be offset.
+ m.def("i801c_b1", []() -> I801B1 * { return new I801C(); });
+ m.def("i801c_b2", []() -> I801B2 * { return new I801C(); });
+ m.def("i801d_b1", []() -> I801B1 * { return new I801D(); });
+ m.def("i801d_b2", []() -> I801B2 * { return new I801D(); });
+
+ // Return a base class pointer to a pybind-registered type when the actual derived type
+ // isn't pybind-registered (and uses multiple-inheritance to offset the pybind base)
+ m.def("i801e_c", []() -> I801C * { return new I801E(); });
+ m.def("i801e_b2", []() -> I801B2 * { return new I801E(); });
+
+
+ // test_mi_static_properties
+ py::class_<Vanilla>(m, "Vanilla")
+ .def(py::init<>())
+ .def("vanilla", &Vanilla::vanilla);
+
+ py::class_<WithStatic1>(m, "WithStatic1")
+ .def(py::init<>())
+ .def_static("static_func1", &WithStatic1::static_func1)
+ .def_readwrite_static("static_value1", &WithStatic1::static_value1);
+
+ py::class_<WithStatic2>(m, "WithStatic2")
+ .def(py::init<>())
+ .def_static("static_func2", &WithStatic2::static_func2)
+ .def_readwrite_static("static_value2", &WithStatic2::static_value2);
+
+ py::class_<VanillaStaticMix1, Vanilla, WithStatic1, WithStatic2>(
+ m, "VanillaStaticMix1")
+ .def(py::init<>())
+ .def_static("static_func", &VanillaStaticMix1::static_func)
+ .def_readwrite_static("static_value", &VanillaStaticMix1::static_value);
+
+ py::class_<VanillaStaticMix2, WithStatic1, Vanilla, WithStatic2>(
+ m, "VanillaStaticMix2")
+ .def(py::init<>())
+ .def_static("static_func", &VanillaStaticMix2::static_func)
+ .def_readwrite_static("static_value", &VanillaStaticMix2::static_value);
+
+
+#if !defined(PYPY_VERSION)
+ struct WithDict { };
+ struct VanillaDictMix1 : Vanilla, WithDict { };
+ struct VanillaDictMix2 : WithDict, Vanilla { };
+ py::class_<WithDict>(m, "WithDict", py::dynamic_attr()).def(py::init<>());
+ py::class_<VanillaDictMix1, Vanilla, WithDict>(m, "VanillaDictMix1").def(py::init<>());
+ py::class_<VanillaDictMix2, WithDict, Vanilla>(m, "VanillaDictMix2").def(py::init<>());
+#endif
+
+ // test_diamond_inheritance
+ // Issue #959: segfault when constructing diamond inheritance instance
+ // All of these have int members so that there will be various unequal pointers involved.
+ struct B { int b; B() = default; B(const B&) = default; virtual ~B() = default; };
+ struct C0 : public virtual B { int c0; };
+ struct C1 : public virtual B { int c1; };
+ struct D : public C0, public C1 { int d; };
+ py::class_<B>(m, "B")
+ .def("b", [](B *self) { return self; });
+ py::class_<C0, B>(m, "C0")
+ .def("c0", [](C0 *self) { return self; });
+ py::class_<C1, B>(m, "C1")
+ .def("c1", [](C1 *self) { return self; });
+ py::class_<D, C0, C1>(m, "D")
+ .def(py::init<>());
+}
diff --git a/3rdparty/pybind11/tests/test_multiple_inheritance.py b/3rdparty/pybind11/tests/test_multiple_inheritance.py
new file mode 100644
index 00000000..475dd3b3
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_multiple_inheritance.py
@@ -0,0 +1,349 @@
+import pytest
+from pybind11_tests import ConstructorStats
+from pybind11_tests import multiple_inheritance as m
+
+
+def test_multiple_inheritance_cpp():
+ mt = m.MIType(3, 4)
+
+ assert mt.foo() == 3
+ assert mt.bar() == 4
+
+
+def test_multiple_inheritance_mix1():
+ class Base1:
+ def __init__(self, i):
+ self.i = i
+
+ def foo(self):
+ return self.i
+
+ class MITypePy(Base1, m.Base2):
+ def __init__(self, i, j):
+ Base1.__init__(self, i)
+ m.Base2.__init__(self, j)
+
+ mt = MITypePy(3, 4)
+
+ assert mt.foo() == 3
+ assert mt.bar() == 4
+
+
+def test_multiple_inheritance_mix2():
+
+ class Base2:
+ def __init__(self, i):
+ self.i = i
+
+ def bar(self):
+ return self.i
+
+ class MITypePy(m.Base1, Base2):
+ def __init__(self, i, j):
+ m.Base1.__init__(self, i)
+ Base2.__init__(self, j)
+
+ mt = MITypePy(3, 4)
+
+ assert mt.foo() == 3
+ assert mt.bar() == 4
+
+
+def test_multiple_inheritance_python():
+
+ class MI1(m.Base1, m.Base2):
+ def __init__(self, i, j):
+ m.Base1.__init__(self, i)
+ m.Base2.__init__(self, j)
+
+ class B1(object):
+ def v(self):
+ return 1
+
+ class MI2(B1, m.Base1, m.Base2):
+ def __init__(self, i, j):
+ B1.__init__(self)
+ m.Base1.__init__(self, i)
+ m.Base2.__init__(self, j)
+
+ class MI3(MI2):
+ def __init__(self, i, j):
+ MI2.__init__(self, i, j)
+
+ class MI4(MI3, m.Base2):
+ def __init__(self, i, j):
+ MI3.__init__(self, i, j)
+ # This should be ignored (Base2 is already initialized via MI2):
+ m.Base2.__init__(self, i + 100)
+
+ class MI5(m.Base2, B1, m.Base1):
+ def __init__(self, i, j):
+ B1.__init__(self)
+ m.Base1.__init__(self, i)
+ m.Base2.__init__(self, j)
+
+ class MI6(m.Base2, B1):
+ def __init__(self, i):
+ m.Base2.__init__(self, i)
+ B1.__init__(self)
+
+ class B2(B1):
+ def v(self):
+ return 2
+
+ class B3(object):
+ def v(self):
+ return 3
+
+ class B4(B3, B2):
+ def v(self):
+ return 4
+
+ class MI7(B4, MI6):
+ def __init__(self, i):
+ B4.__init__(self)
+ MI6.__init__(self, i)
+
+ class MI8(MI6, B3):
+ def __init__(self, i):
+ MI6.__init__(self, i)
+ B3.__init__(self)
+
+ class MI8b(B3, MI6):
+ def __init__(self, i):
+ B3.__init__(self)
+ MI6.__init__(self, i)
+
+ mi1 = MI1(1, 2)
+ assert mi1.foo() == 1
+ assert mi1.bar() == 2
+
+ mi2 = MI2(3, 4)
+ assert mi2.v() == 1
+ assert mi2.foo() == 3
+ assert mi2.bar() == 4
+
+ mi3 = MI3(5, 6)
+ assert mi3.v() == 1
+ assert mi3.foo() == 5
+ assert mi3.bar() == 6
+
+ mi4 = MI4(7, 8)
+ assert mi4.v() == 1
+ assert mi4.foo() == 7
+ assert mi4.bar() == 8
+
+ mi5 = MI5(10, 11)
+ assert mi5.v() == 1
+ assert mi5.foo() == 10
+ assert mi5.bar() == 11
+
+ mi6 = MI6(12)
+ assert mi6.v() == 1
+ assert mi6.bar() == 12
+
+ mi7 = MI7(13)
+ assert mi7.v() == 4
+ assert mi7.bar() == 13
+
+ mi8 = MI8(14)
+ assert mi8.v() == 1
+ assert mi8.bar() == 14
+
+ mi8b = MI8b(15)
+ assert mi8b.v() == 3
+ assert mi8b.bar() == 15
+
+
+def test_multiple_inheritance_python_many_bases():
+
+ class MIMany14(m.BaseN1, m.BaseN2, m.BaseN3, m.BaseN4):
+ def __init__(self):
+ m.BaseN1.__init__(self, 1)
+ m.BaseN2.__init__(self, 2)
+ m.BaseN3.__init__(self, 3)
+ m.BaseN4.__init__(self, 4)
+
+ class MIMany58(m.BaseN5, m.BaseN6, m.BaseN7, m.BaseN8):
+ def __init__(self):
+ m.BaseN5.__init__(self, 5)
+ m.BaseN6.__init__(self, 6)
+ m.BaseN7.__init__(self, 7)
+ m.BaseN8.__init__(self, 8)
+
+ class MIMany916(m.BaseN9, m.BaseN10, m.BaseN11, m.BaseN12, m.BaseN13, m.BaseN14, m.BaseN15,
+ m.BaseN16):
+ def __init__(self):
+ m.BaseN9.__init__(self, 9)
+ m.BaseN10.__init__(self, 10)
+ m.BaseN11.__init__(self, 11)
+ m.BaseN12.__init__(self, 12)
+ m.BaseN13.__init__(self, 13)
+ m.BaseN14.__init__(self, 14)
+ m.BaseN15.__init__(self, 15)
+ m.BaseN16.__init__(self, 16)
+
+ class MIMany19(MIMany14, MIMany58, m.BaseN9):
+ def __init__(self):
+ MIMany14.__init__(self)
+ MIMany58.__init__(self)
+ m.BaseN9.__init__(self, 9)
+
+ class MIMany117(MIMany14, MIMany58, MIMany916, m.BaseN17):
+ def __init__(self):
+ MIMany14.__init__(self)
+ MIMany58.__init__(self)
+ MIMany916.__init__(self)
+ m.BaseN17.__init__(self, 17)
+
+ # Inherits from 4 registered C++ classes: can fit in one pointer on any modern arch:
+ a = MIMany14()
+ for i in range(1, 4):
+ assert getattr(a, "f" + str(i))() == 2 * i
+
+ # Inherits from 8: requires 1/2 pointers worth of holder flags on 32/64-bit arch:
+ b = MIMany916()
+ for i in range(9, 16):
+ assert getattr(b, "f" + str(i))() == 2 * i
+
+ # Inherits from 9: requires >= 2 pointers worth of holder flags
+ c = MIMany19()
+ for i in range(1, 9):
+ assert getattr(c, "f" + str(i))() == 2 * i
+
+ # Inherits from 17: requires >= 3 pointers worth of holder flags
+ d = MIMany117()
+ for i in range(1, 17):
+ assert getattr(d, "f" + str(i))() == 2 * i
+
+
+def test_multiple_inheritance_virtbase():
+
+ class MITypePy(m.Base12a):
+ def __init__(self, i, j):
+ m.Base12a.__init__(self, i, j)
+
+ mt = MITypePy(3, 4)
+ assert mt.bar() == 4
+ assert m.bar_base2a(mt) == 4
+ assert m.bar_base2a_sharedptr(mt) == 4
+
+
+def test_mi_static_properties():
+ """Mixing bases with and without static properties should be possible
+ and the result should be independent of base definition order"""
+
+ for d in (m.VanillaStaticMix1(), m.VanillaStaticMix2()):
+ assert d.vanilla() == "Vanilla"
+ assert d.static_func1() == "WithStatic1"
+ assert d.static_func2() == "WithStatic2"
+ assert d.static_func() == d.__class__.__name__
+
+ m.WithStatic1.static_value1 = 1
+ m.WithStatic2.static_value2 = 2
+ assert d.static_value1 == 1
+ assert d.static_value2 == 2
+ assert d.static_value == 12
+
+ d.static_value1 = 0
+ assert d.static_value1 == 0
+ d.static_value2 = 0
+ assert d.static_value2 == 0
+ d.static_value = 0
+ assert d.static_value == 0
+
+
+@pytest.unsupported_on_pypy
+def test_mi_dynamic_attributes():
+ """Mixing bases with and without dynamic attribute support"""
+
+ for d in (m.VanillaDictMix1(), m.VanillaDictMix2()):
+ d.dynamic = 1
+ assert d.dynamic == 1
+
+
+def test_mi_unaligned_base():
+ """Returning an offset (non-first MI) base class pointer should recognize the instance"""
+
+ n_inst = ConstructorStats.detail_reg_inst()
+
+ c = m.I801C()
+ d = m.I801D()
+ # + 4 below because we have the two instances, and each instance has offset base I801B2
+ assert ConstructorStats.detail_reg_inst() == n_inst + 4
+ b1c = m.i801b1_c(c)
+ assert b1c is c
+ b2c = m.i801b2_c(c)
+ assert b2c is c
+ b1d = m.i801b1_d(d)
+ assert b1d is d
+ b2d = m.i801b2_d(d)
+ assert b2d is d
+
+ assert ConstructorStats.detail_reg_inst() == n_inst + 4 # no extra instances
+ del c, b1c, b2c
+ assert ConstructorStats.detail_reg_inst() == n_inst + 2
+ del d, b1d, b2d
+ assert ConstructorStats.detail_reg_inst() == n_inst
+
+
+def test_mi_base_return():
+ """Tests returning an offset (non-first MI) base class pointer to a derived instance"""
+
+ n_inst = ConstructorStats.detail_reg_inst()
+
+ c1 = m.i801c_b1()
+ assert type(c1) is m.I801C
+ assert c1.a == 1
+ assert c1.b == 2
+
+ d1 = m.i801d_b1()
+ assert type(d1) is m.I801D
+ assert d1.a == 1
+ assert d1.b == 2
+
+ assert ConstructorStats.detail_reg_inst() == n_inst + 4
+
+ c2 = m.i801c_b2()
+ assert type(c2) is m.I801C
+ assert c2.a == 1
+ assert c2.b == 2
+
+ d2 = m.i801d_b2()
+ assert type(d2) is m.I801D
+ assert d2.a == 1
+ assert d2.b == 2
+
+ assert ConstructorStats.detail_reg_inst() == n_inst + 8
+
+ del c2
+ assert ConstructorStats.detail_reg_inst() == n_inst + 6
+ del c1, d1, d2
+ assert ConstructorStats.detail_reg_inst() == n_inst
+
+ # Returning an unregistered derived type with a registered base; we won't
+ # pick up the derived type, obviously, but should still work (as an object
+ # of whatever type was returned).
+ e1 = m.i801e_c()
+ assert type(e1) is m.I801C
+ assert e1.a == 1
+ assert e1.b == 2
+
+ e2 = m.i801e_b2()
+ assert type(e2) is m.I801B2
+ assert e2.b == 2
+
+
+def test_diamond_inheritance():
+ """Tests that diamond inheritance works as expected (issue #959)"""
+
+ # Issue #959: this shouldn't segfault:
+ d = m.D()
+
+ # Make sure all the various distinct pointers are all recognized as registered instances:
+ assert d is d.c0()
+ assert d is d.c1()
+ assert d is d.b()
+ assert d is d.c0().b()
+ assert d is d.c1().b()
+ assert d is d.c0().c1().b().c0().b()
diff --git a/3rdparty/pybind11/tests/test_numpy_array.cpp b/3rdparty/pybind11/tests/test_numpy_array.cpp
new file mode 100644
index 00000000..156a3bfa
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_numpy_array.cpp
@@ -0,0 +1,390 @@
+/*
+ tests/test_numpy_array.cpp -- test core array functionality
+
+ Copyright (c) 2016 Ivan Smirnov <i.s.smirnov@gmail.com>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+#include <pybind11/numpy.h>
+#include <pybind11/stl.h>
+
+#include <cstdint>
+
+// Size / dtype checks.
+struct DtypeCheck {
+ py::dtype numpy{};
+ py::dtype pybind11{};
+};
+
+template <typename T>
+DtypeCheck get_dtype_check(const char* name) {
+ py::module np = py::module::import("numpy");
+ DtypeCheck check{};
+ check.numpy = np.attr("dtype")(np.attr(name));
+ check.pybind11 = py::dtype::of<T>();
+ return check;
+}
+
+std::vector<DtypeCheck> get_concrete_dtype_checks() {
+ return {
+ // Normalization
+ get_dtype_check<std::int8_t>("int8"),
+ get_dtype_check<std::uint8_t>("uint8"),
+ get_dtype_check<std::int16_t>("int16"),
+ get_dtype_check<std::uint16_t>("uint16"),
+ get_dtype_check<std::int32_t>("int32"),
+ get_dtype_check<std::uint32_t>("uint32"),
+ get_dtype_check<std::int64_t>("int64"),
+ get_dtype_check<std::uint64_t>("uint64")
+ };
+}
+
+struct DtypeSizeCheck {
+ std::string name{};
+ int size_cpp{};
+ int size_numpy{};
+ // For debugging.
+ py::dtype dtype{};
+};
+
+template <typename T>
+DtypeSizeCheck get_dtype_size_check() {
+ DtypeSizeCheck check{};
+ check.name = py::type_id<T>();
+ check.size_cpp = sizeof(T);
+ check.dtype = py::dtype::of<T>();
+ check.size_numpy = check.dtype.attr("itemsize").template cast<int>();
+ return check;
+}
+
+std::vector<DtypeSizeCheck> get_platform_dtype_size_checks() {
+ return {
+ get_dtype_size_check<short>(),
+ get_dtype_size_check<unsigned short>(),
+ get_dtype_size_check<int>(),
+ get_dtype_size_check<unsigned int>(),
+ get_dtype_size_check<long>(),
+ get_dtype_size_check<unsigned long>(),
+ get_dtype_size_check<long long>(),
+ get_dtype_size_check<unsigned long long>(),
+ };
+}
+
+// Arrays.
+using arr = py::array;
+using arr_t = py::array_t<uint16_t, 0>;
+static_assert(std::is_same<arr_t::value_type, uint16_t>::value, "");
+
+template<typename... Ix> arr data(const arr& a, Ix... index) {
+ return arr(a.nbytes() - a.offset_at(index...), (const uint8_t *) a.data(index...));
+}
+
+template<typename... Ix> arr data_t(const arr_t& a, Ix... index) {
+ return arr(a.size() - a.index_at(index...), a.data(index...));
+}
+
+template<typename... Ix> arr& mutate_data(arr& a, Ix... index) {
+ auto ptr = (uint8_t *) a.mutable_data(index...);
+ for (ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++)
+ ptr[i] = (uint8_t) (ptr[i] * 2);
+ return a;
+}
+
+template<typename... Ix> arr_t& mutate_data_t(arr_t& a, Ix... index) {
+ auto ptr = a.mutable_data(index...);
+ for (ssize_t i = 0; i < a.size() - a.index_at(index...); i++)
+ ptr[i]++;
+ return a;
+}
+
+template<typename... Ix> ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); }
+template<typename... Ix> ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); }
+template<typename... Ix> ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); }
+template<typename... Ix> ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); }
+template<typename... Ix> ssize_t at_t(const arr_t& a, Ix... idx) { return a.at(idx...); }
+template<typename... Ix> arr_t& mutate_at_t(arr_t& a, Ix... idx) { a.mutable_at(idx...)++; return a; }
+
+#define def_index_fn(name, type) \
+ sm.def(#name, [](type a) { return name(a); }); \
+ sm.def(#name, [](type a, int i) { return name(a, i); }); \
+ sm.def(#name, [](type a, int i, int j) { return name(a, i, j); }); \
+ sm.def(#name, [](type a, int i, int j, int k) { return name(a, i, j, k); });
+
+template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) {
+ if (r.ndim() != 2) throw std::domain_error("error: ndim != 2");
+ py::list l;
+ l.append(*r.data(0, 0));
+ l.append(*r2.mutable_data(0, 0));
+ l.append(r.data(0, 1) == r2.mutable_data(0, 1));
+ l.append(r.ndim());
+ l.append(r.itemsize());
+ l.append(r.shape(0));
+ l.append(r.shape(1));
+ l.append(r.size());
+ l.append(r.nbytes());
+ return l.release();
+}
+
+// note: declaration at local scope would create a dangling reference!
+static int data_i = 42;
+
+TEST_SUBMODULE(numpy_array, sm) {
+ try { py::module::import("numpy"); }
+ catch (...) { return; }
+
+ // test_dtypes
+ py::class_<DtypeCheck>(sm, "DtypeCheck")
+ .def_readonly("numpy", &DtypeCheck::numpy)
+ .def_readonly("pybind11", &DtypeCheck::pybind11)
+ .def("__repr__", [](const DtypeCheck& self) {
+ return py::str("<DtypeCheck numpy={} pybind11={}>").format(
+ self.numpy, self.pybind11);
+ });
+ sm.def("get_concrete_dtype_checks", &get_concrete_dtype_checks);
+
+ py::class_<DtypeSizeCheck>(sm, "DtypeSizeCheck")
+ .def_readonly("name", &DtypeSizeCheck::name)
+ .def_readonly("size_cpp", &DtypeSizeCheck::size_cpp)
+ .def_readonly("size_numpy", &DtypeSizeCheck::size_numpy)
+ .def("__repr__", [](const DtypeSizeCheck& self) {
+ return py::str("<DtypeSizeCheck name='{}' size_cpp={} size_numpy={} dtype={}>").format(
+ self.name, self.size_cpp, self.size_numpy, self.dtype);
+ });
+ sm.def("get_platform_dtype_size_checks", &get_platform_dtype_size_checks);
+
+ // test_array_attributes
+ sm.def("ndim", [](const arr& a) { return a.ndim(); });
+ sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); });
+ sm.def("shape", [](const arr& a, ssize_t dim) { return a.shape(dim); });
+ sm.def("strides", [](const arr& a) { return arr(a.ndim(), a.strides()); });
+ sm.def("strides", [](const arr& a, ssize_t dim) { return a.strides(dim); });
+ sm.def("writeable", [](const arr& a) { return a.writeable(); });
+ sm.def("size", [](const arr& a) { return a.size(); });
+ sm.def("itemsize", [](const arr& a) { return a.itemsize(); });
+ sm.def("nbytes", [](const arr& a) { return a.nbytes(); });
+ sm.def("owndata", [](const arr& a) { return a.owndata(); });
+
+ // test_index_offset
+ def_index_fn(index_at, const arr&);
+ def_index_fn(index_at_t, const arr_t&);
+ def_index_fn(offset_at, const arr&);
+ def_index_fn(offset_at_t, const arr_t&);
+ // test_data
+ def_index_fn(data, const arr&);
+ def_index_fn(data_t, const arr_t&);
+ // test_mutate_data, test_mutate_readonly
+ def_index_fn(mutate_data, arr&);
+ def_index_fn(mutate_data_t, arr_t&);
+ def_index_fn(at_t, const arr_t&);
+ def_index_fn(mutate_at_t, arr_t&);
+
+ // test_make_c_f_array
+ sm.def("make_f_array", [] { return py::array_t<float>({ 2, 2 }, { 4, 8 }); });
+ sm.def("make_c_array", [] { return py::array_t<float>({ 2, 2 }, { 8, 4 }); });
+
+ // test_empty_shaped_array
+ sm.def("make_empty_shaped_array", [] { return py::array(py::dtype("f"), {}, {}); });
+ // test numpy scalars (empty shape, ndim==0)
+ sm.def("scalar_int", []() { return py::array(py::dtype("i"), {}, {}, &data_i); });
+
+ // test_wrap
+ sm.def("wrap", [](py::array a) {
+ return py::array(
+ a.dtype(),
+ {a.shape(), a.shape() + a.ndim()},
+ {a.strides(), a.strides() + a.ndim()},
+ a.data(),
+ a
+ );
+ });
+
+ // test_numpy_view
+ struct ArrayClass {
+ int data[2] = { 1, 2 };
+ ArrayClass() { py::print("ArrayClass()"); }
+ ~ArrayClass() { py::print("~ArrayClass()"); }
+ };
+ py::class_<ArrayClass>(sm, "ArrayClass")
+ .def(py::init<>())
+ .def("numpy_view", [](py::object &obj) {
+ py::print("ArrayClass::numpy_view()");
+ ArrayClass &a = obj.cast<ArrayClass&>();
+ return py::array_t<int>({2}, {4}, a.data, obj);
+ }
+ );
+
+ // test_cast_numpy_int64_to_uint64
+ sm.def("function_taking_uint64", [](uint64_t) { });
+
+ // test_isinstance
+ sm.def("isinstance_untyped", [](py::object yes, py::object no) {
+ return py::isinstance<py::array>(yes) && !py::isinstance<py::array>(no);
+ });
+ sm.def("isinstance_typed", [](py::object o) {
+ return py::isinstance<py::array_t<double>>(o) && !py::isinstance<py::array_t<int>>(o);
+ });
+
+ // test_constructors
+ sm.def("default_constructors", []() {
+ return py::dict(
+ "array"_a=py::array(),
+ "array_t<int32>"_a=py::array_t<std::int32_t>(),
+ "array_t<double>"_a=py::array_t<double>()
+ );
+ });
+ sm.def("converting_constructors", [](py::object o) {
+ return py::dict(
+ "array"_a=py::array(o),
+ "array_t<int32>"_a=py::array_t<std::int32_t>(o),
+ "array_t<double>"_a=py::array_t<double>(o)
+ );
+ });
+
+ // test_overload_resolution
+ sm.def("overloaded", [](py::array_t<double>) { return "double"; });
+ sm.def("overloaded", [](py::array_t<float>) { return "float"; });
+ sm.def("overloaded", [](py::array_t<int>) { return "int"; });
+ sm.def("overloaded", [](py::array_t<unsigned short>) { return "unsigned short"; });
+ sm.def("overloaded", [](py::array_t<long long>) { return "long long"; });
+ sm.def("overloaded", [](py::array_t<std::complex<double>>) { return "double complex"; });
+ sm.def("overloaded", [](py::array_t<std::complex<float>>) { return "float complex"; });
+
+ sm.def("overloaded2", [](py::array_t<std::complex<double>>) { return "double complex"; });
+ sm.def("overloaded2", [](py::array_t<double>) { return "double"; });
+ sm.def("overloaded2", [](py::array_t<std::complex<float>>) { return "float complex"; });
+ sm.def("overloaded2", [](py::array_t<float>) { return "float"; });
+
+ // Only accept the exact types:
+ sm.def("overloaded3", [](py::array_t<int>) { return "int"; }, py::arg().noconvert());
+ sm.def("overloaded3", [](py::array_t<double>) { return "double"; }, py::arg().noconvert());
+
+ // Make sure we don't do unsafe coercion (e.g. float to int) when not using forcecast, but
+ // rather that float gets converted via the safe (conversion to double) overload:
+ sm.def("overloaded4", [](py::array_t<long long, 0>) { return "long long"; });
+ sm.def("overloaded4", [](py::array_t<double, 0>) { return "double"; });
+
+ // But we do allow conversion to int if forcecast is enabled (but only if no overload matches
+ // without conversion)
+ sm.def("overloaded5", [](py::array_t<unsigned int>) { return "unsigned int"; });
+ sm.def("overloaded5", [](py::array_t<double>) { return "double"; });
+
+ // test_greedy_string_overload
+ // Issue 685: ndarray shouldn't go to std::string overload
+ sm.def("issue685", [](std::string) { return "string"; });
+ sm.def("issue685", [](py::array) { return "array"; });
+ sm.def("issue685", [](py::object) { return "other"; });
+
+ // test_array_unchecked_fixed_dims
+ sm.def("proxy_add2", [](py::array_t<double> a, double v) {
+ auto r = a.mutable_unchecked<2>();
+ for (ssize_t i = 0; i < r.shape(0); i++)
+ for (ssize_t j = 0; j < r.shape(1); j++)
+ r(i, j) += v;
+ }, py::arg().noconvert(), py::arg());
+
+ sm.def("proxy_init3", [](double start) {
+ py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
+ auto r = a.mutable_unchecked<3>();
+ for (ssize_t i = 0; i < r.shape(0); i++)
+ for (ssize_t j = 0; j < r.shape(1); j++)
+ for (ssize_t k = 0; k < r.shape(2); k++)
+ r(i, j, k) = start++;
+ return a;
+ });
+ sm.def("proxy_init3F", [](double start) {
+ py::array_t<double, py::array::f_style> a({ 3, 3, 3 });
+ auto r = a.mutable_unchecked<3>();
+ for (ssize_t k = 0; k < r.shape(2); k++)
+ for (ssize_t j = 0; j < r.shape(1); j++)
+ for (ssize_t i = 0; i < r.shape(0); i++)
+ r(i, j, k) = start++;
+ return a;
+ });
+ sm.def("proxy_squared_L2_norm", [](py::array_t<double> a) {
+ auto r = a.unchecked<1>();
+ double sumsq = 0;
+ for (ssize_t i = 0; i < r.shape(0); i++)
+ sumsq += r[i] * r(i); // Either notation works for a 1D array
+ return sumsq;
+ });
+
+ sm.def("proxy_auxiliaries2", [](py::array_t<double> a) {
+ auto r = a.unchecked<2>();
+ auto r2 = a.mutable_unchecked<2>();
+ return auxiliaries(r, r2);
+ });
+
+ // test_array_unchecked_dyn_dims
+ // Same as the above, but without a compile-time dimensions specification:
+ sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) {
+ auto r = a.mutable_unchecked();
+ if (r.ndim() != 2) throw std::domain_error("error: ndim != 2");
+ for (ssize_t i = 0; i < r.shape(0); i++)
+ for (ssize_t j = 0; j < r.shape(1); j++)
+ r(i, j) += v;
+ }, py::arg().noconvert(), py::arg());
+ sm.def("proxy_init3_dyn", [](double start) {
+ py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
+ auto r = a.mutable_unchecked();
+ if (r.ndim() != 3) throw std::domain_error("error: ndim != 3");
+ for (ssize_t i = 0; i < r.shape(0); i++)
+ for (ssize_t j = 0; j < r.shape(1); j++)
+ for (ssize_t k = 0; k < r.shape(2); k++)
+ r(i, j, k) = start++;
+ return a;
+ });
+ sm.def("proxy_auxiliaries2_dyn", [](py::array_t<double> a) {
+ return auxiliaries(a.unchecked(), a.mutable_unchecked());
+ });
+
+ sm.def("array_auxiliaries2", [](py::array_t<double> a) {
+ return auxiliaries(a, a);
+ });
+
+ // test_array_failures
+ // Issue #785: Uninformative "Unknown internal error" exception when constructing array from empty object:
+ sm.def("array_fail_test", []() { return py::array(py::object()); });
+ sm.def("array_t_fail_test", []() { return py::array_t<double>(py::object()); });
+ // Make sure the error from numpy is being passed through:
+ sm.def("array_fail_test_negative_size", []() { int c = 0; return py::array(-1, &c); });
+
+ // test_initializer_list
+ // Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous
+ sm.def("array_initializer_list1", []() { return py::array_t<float>(1); }); // { 1 } also works, but clang warns about it
+ sm.def("array_initializer_list2", []() { return py::array_t<float>({ 1, 2 }); });
+ sm.def("array_initializer_list3", []() { return py::array_t<float>({ 1, 2, 3 }); });
+ sm.def("array_initializer_list4", []() { return py::array_t<float>({ 1, 2, 3, 4 }); });
+
+ // test_array_resize
+ // reshape array to 2D without changing size
+ sm.def("array_reshape2", [](py::array_t<double> a) {
+ const ssize_t dim_sz = (ssize_t)std::sqrt(a.size());
+ if (dim_sz * dim_sz != a.size())
+ throw std::domain_error("array_reshape2: input array total size is not a squared integer");
+ a.resize({dim_sz, dim_sz});
+ });
+
+ // resize to 3D array with each dimension = N
+ sm.def("array_resize3", [](py::array_t<double> a, size_t N, bool refcheck) {
+ a.resize({N, N, N}, refcheck);
+ });
+
+ // test_array_create_and_resize
+ // return 2D array with Nrows = Ncols = N
+ sm.def("create_and_resize", [](size_t N) {
+ py::array_t<double> a;
+ a.resize({N, N});
+ std::fill(a.mutable_data(), a.mutable_data() + a.size(), 42.);
+ return a;
+ });
+
+#if PY_MAJOR_VERSION >= 3
+ sm.def("index_using_ellipsis", [](py::array a) {
+ return a[py::make_tuple(0, py::ellipsis(), 0)];
+ });
+#endif
+}
diff --git a/3rdparty/pybind11/tests/test_numpy_array.py b/3rdparty/pybind11/tests/test_numpy_array.py
new file mode 100644
index 00000000..d0a6324d
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_numpy_array.py
@@ -0,0 +1,447 @@
+import pytest
+from pybind11_tests import numpy_array as m
+
+pytestmark = pytest.requires_numpy
+
+with pytest.suppress(ImportError):
+ import numpy as np
+
+
+def test_dtypes():
+ # See issue #1328.
+ # - Platform-dependent sizes.
+ for size_check in m.get_platform_dtype_size_checks():
+ print(size_check)
+ assert size_check.size_cpp == size_check.size_numpy, size_check
+ # - Concrete sizes.
+ for check in m.get_concrete_dtype_checks():
+ print(check)
+ assert check.numpy == check.pybind11, check
+ if check.numpy.num != check.pybind11.num:
+ print("NOTE: typenum mismatch for {}: {} != {}".format(
+ check, check.numpy.num, check.pybind11.num))
+
+
+@pytest.fixture(scope='function')
+def arr():
+ return np.array([[1, 2, 3], [4, 5, 6]], '=u2')
+
+
+def test_array_attributes():
+ a = np.array(0, 'f8')
+ assert m.ndim(a) == 0
+ assert all(m.shape(a) == [])
+ assert all(m.strides(a) == [])
+ with pytest.raises(IndexError) as excinfo:
+ m.shape(a, 0)
+ assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)'
+ with pytest.raises(IndexError) as excinfo:
+ m.strides(a, 0)
+ assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)'
+ assert m.writeable(a)
+ assert m.size(a) == 1
+ assert m.itemsize(a) == 8
+ assert m.nbytes(a) == 8
+ assert m.owndata(a)
+
+ a = np.array([[1, 2, 3], [4, 5, 6]], 'u2').view()
+ a.flags.writeable = False
+ assert m.ndim(a) == 2
+ assert all(m.shape(a) == [2, 3])
+ assert m.shape(a, 0) == 2
+ assert m.shape(a, 1) == 3
+ assert all(m.strides(a) == [6, 2])
+ assert m.strides(a, 0) == 6
+ assert m.strides(a, 1) == 2
+ with pytest.raises(IndexError) as excinfo:
+ m.shape(a, 2)
+ assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)'
+ with pytest.raises(IndexError) as excinfo:
+ m.strides(a, 2)
+ assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)'
+ assert not m.writeable(a)
+ assert m.size(a) == 6
+ assert m.itemsize(a) == 2
+ assert m.nbytes(a) == 12
+ assert not m.owndata(a)
+
+
+@pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)])
+def test_index_offset(arr, args, ret):
+ assert m.index_at(arr, *args) == ret
+ assert m.index_at_t(arr, *args) == ret
+ assert m.offset_at(arr, *args) == ret * arr.dtype.itemsize
+ assert m.offset_at_t(arr, *args) == ret * arr.dtype.itemsize
+
+
+def test_dim_check_fail(arr):
+ for func in (m.index_at, m.index_at_t, m.offset_at, m.offset_at_t, m.data, m.data_t,
+ m.mutate_data, m.mutate_data_t):
+ with pytest.raises(IndexError) as excinfo:
+ func(arr, 1, 2, 3)
+ assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)'
+
+
+@pytest.mark.parametrize('args, ret',
+ [([], [1, 2, 3, 4, 5, 6]),
+ ([1], [4, 5, 6]),
+ ([0, 1], [2, 3, 4, 5, 6]),
+ ([1, 2], [6])])
+def test_data(arr, args, ret):
+ from sys import byteorder
+ assert all(m.data_t(arr, *args) == ret)
+ assert all(m.data(arr, *args)[(0 if byteorder == 'little' else 1)::2] == ret)
+ assert all(m.data(arr, *args)[(1 if byteorder == 'little' else 0)::2] == 0)
+
+
+@pytest.mark.parametrize('dim', [0, 1, 3])
+def test_at_fail(arr, dim):
+ for func in m.at_t, m.mutate_at_t:
+ with pytest.raises(IndexError) as excinfo:
+ func(arr, *([0] * dim))
+ assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim)
+
+
+def test_at(arr):
+ assert m.at_t(arr, 0, 2) == 3
+ assert m.at_t(arr, 1, 0) == 4
+
+ assert all(m.mutate_at_t(arr, 0, 2).ravel() == [1, 2, 4, 4, 5, 6])
+ assert all(m.mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6])
+
+
+def test_mutate_readonly(arr):
+ arr.flags.writeable = False
+ for func, args in (m.mutate_data, ()), (m.mutate_data_t, ()), (m.mutate_at_t, (0, 0)):
+ with pytest.raises(ValueError) as excinfo:
+ func(arr, *args)
+ assert str(excinfo.value) == 'array is not writeable'
+
+
+def test_mutate_data(arr):
+ assert all(m.mutate_data(arr).ravel() == [2, 4, 6, 8, 10, 12])
+ assert all(m.mutate_data(arr).ravel() == [4, 8, 12, 16, 20, 24])
+ assert all(m.mutate_data(arr, 1).ravel() == [4, 8, 12, 32, 40, 48])
+ assert all(m.mutate_data(arr, 0, 1).ravel() == [4, 16, 24, 64, 80, 96])
+ assert all(m.mutate_data(arr, 1, 2).ravel() == [4, 16, 24, 64, 80, 192])
+
+ assert all(m.mutate_data_t(arr).ravel() == [5, 17, 25, 65, 81, 193])
+ assert all(m.mutate_data_t(arr).ravel() == [6, 18, 26, 66, 82, 194])
+ assert all(m.mutate_data_t(arr, 1).ravel() == [6, 18, 26, 67, 83, 195])
+ assert all(m.mutate_data_t(arr, 0, 1).ravel() == [6, 19, 27, 68, 84, 196])
+ assert all(m.mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197])
+
+
+def test_bounds_check(arr):
+ for func in (m.index_at, m.index_at_t, m.data, m.data_t,
+ m.mutate_data, m.mutate_data_t, m.at_t, m.mutate_at_t):
+ with pytest.raises(IndexError) as excinfo:
+ func(arr, 2, 0)
+ assert str(excinfo.value) == 'index 2 is out of bounds for axis 0 with size 2'
+ with pytest.raises(IndexError) as excinfo:
+ func(arr, 0, 4)
+ assert str(excinfo.value) == 'index 4 is out of bounds for axis 1 with size 3'
+
+
+def test_make_c_f_array():
+ assert m.make_c_array().flags.c_contiguous
+ assert not m.make_c_array().flags.f_contiguous
+ assert m.make_f_array().flags.f_contiguous
+ assert not m.make_f_array().flags.c_contiguous
+
+
+def test_make_empty_shaped_array():
+ m.make_empty_shaped_array()
+
+ # empty shape means numpy scalar, PEP 3118
+ assert m.scalar_int().ndim == 0
+ assert m.scalar_int().shape == ()
+ assert m.scalar_int() == 42
+
+
+def test_wrap():
+ def assert_references(a, b, base=None):
+ from distutils.version import LooseVersion
+ if base is None:
+ base = a
+ assert a is not b
+ assert a.__array_interface__['data'][0] == b.__array_interface__['data'][0]
+ assert a.shape == b.shape
+ assert a.strides == b.strides
+ assert a.flags.c_contiguous == b.flags.c_contiguous
+ assert a.flags.f_contiguous == b.flags.f_contiguous
+ assert a.flags.writeable == b.flags.writeable
+ assert a.flags.aligned == b.flags.aligned
+ if LooseVersion(np.__version__) >= LooseVersion("1.14.0"):
+ assert a.flags.writebackifcopy == b.flags.writebackifcopy
+ else:
+ assert a.flags.updateifcopy == b.flags.updateifcopy
+ assert np.all(a == b)
+ assert not b.flags.owndata
+ assert b.base is base
+ if a.flags.writeable and a.ndim == 2:
+ a[0, 0] = 1234
+ assert b[0, 0] == 1234
+
+ a1 = np.array([1, 2], dtype=np.int16)
+ assert a1.flags.owndata and a1.base is None
+ a2 = m.wrap(a1)
+ assert_references(a1, a2)
+
+ a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='F')
+ assert a1.flags.owndata and a1.base is None
+ a2 = m.wrap(a1)
+ assert_references(a1, a2)
+
+ a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='C')
+ a1.flags.writeable = False
+ a2 = m.wrap(a1)
+ assert_references(a1, a2)
+
+ a1 = np.random.random((4, 4, 4))
+ a2 = m.wrap(a1)
+ assert_references(a1, a2)
+
+ a1t = a1.transpose()
+ a2 = m.wrap(a1t)
+ assert_references(a1t, a2, a1)
+
+ a1d = a1.diagonal()
+ a2 = m.wrap(a1d)
+ assert_references(a1d, a2, a1)
+
+ a1m = a1[::-1, ::-1, ::-1]
+ a2 = m.wrap(a1m)
+ assert_references(a1m, a2, a1)
+
+
+def test_numpy_view(capture):
+ with capture:
+ ac = m.ArrayClass()
+ ac_view_1 = ac.numpy_view()
+ ac_view_2 = ac.numpy_view()
+ assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32))
+ del ac
+ pytest.gc_collect()
+ assert capture == """
+ ArrayClass()
+ ArrayClass::numpy_view()
+ ArrayClass::numpy_view()
+ """
+ ac_view_1[0] = 4
+ ac_view_1[1] = 3
+ assert ac_view_2[0] == 4
+ assert ac_view_2[1] == 3
+ with capture:
+ del ac_view_1
+ del ac_view_2
+ pytest.gc_collect()
+ pytest.gc_collect()
+ assert capture == """
+ ~ArrayClass()
+ """
+
+
+@pytest.unsupported_on_pypy
+def test_cast_numpy_int64_to_uint64():
+ m.function_taking_uint64(123)
+ m.function_taking_uint64(np.uint64(123))
+
+
+def test_isinstance():
+ assert m.isinstance_untyped(np.array([1, 2, 3]), "not an array")
+ assert m.isinstance_typed(np.array([1.0, 2.0, 3.0]))
+
+
+def test_constructors():
+ defaults = m.default_constructors()
+ for a in defaults.values():
+ assert a.size == 0
+ assert defaults["array"].dtype == np.array([]).dtype
+ assert defaults["array_t<int32>"].dtype == np.int32
+ assert defaults["array_t<double>"].dtype == np.float64
+
+ results = m.converting_constructors([1, 2, 3])
+ for a in results.values():
+ np.testing.assert_array_equal(a, [1, 2, 3])
+ assert results["array"].dtype == np.int_
+ assert results["array_t<int32>"].dtype == np.int32
+ assert results["array_t<double>"].dtype == np.float64
+
+
+def test_overload_resolution(msg):
+ # Exact overload matches:
+ assert m.overloaded(np.array([1], dtype='float64')) == 'double'
+ assert m.overloaded(np.array([1], dtype='float32')) == 'float'
+ assert m.overloaded(np.array([1], dtype='ushort')) == 'unsigned short'
+ assert m.overloaded(np.array([1], dtype='intc')) == 'int'
+ assert m.overloaded(np.array([1], dtype='longlong')) == 'long long'
+ assert m.overloaded(np.array([1], dtype='complex')) == 'double complex'
+ assert m.overloaded(np.array([1], dtype='csingle')) == 'float complex'
+
+ # No exact match, should call first convertible version:
+ assert m.overloaded(np.array([1], dtype='uint8')) == 'double'
+
+ with pytest.raises(TypeError) as excinfo:
+ m.overloaded("not an array")
+ assert msg(excinfo.value) == """
+ overloaded(): incompatible function arguments. The following argument types are supported:
+ 1. (arg0: numpy.ndarray[float64]) -> str
+ 2. (arg0: numpy.ndarray[float32]) -> str
+ 3. (arg0: numpy.ndarray[int32]) -> str
+ 4. (arg0: numpy.ndarray[uint16]) -> str
+ 5. (arg0: numpy.ndarray[int64]) -> str
+ 6. (arg0: numpy.ndarray[complex128]) -> str
+ 7. (arg0: numpy.ndarray[complex64]) -> str
+
+ Invoked with: 'not an array'
+ """
+
+ assert m.overloaded2(np.array([1], dtype='float64')) == 'double'
+ assert m.overloaded2(np.array([1], dtype='float32')) == 'float'
+ assert m.overloaded2(np.array([1], dtype='complex64')) == 'float complex'
+ assert m.overloaded2(np.array([1], dtype='complex128')) == 'double complex'
+ assert m.overloaded2(np.array([1], dtype='float32')) == 'float'
+
+ assert m.overloaded3(np.array([1], dtype='float64')) == 'double'
+ assert m.overloaded3(np.array([1], dtype='intc')) == 'int'
+ expected_exc = """
+ overloaded3(): incompatible function arguments. The following argument types are supported:
+ 1. (arg0: numpy.ndarray[int32]) -> str
+ 2. (arg0: numpy.ndarray[float64]) -> str
+
+ Invoked with: """
+
+ with pytest.raises(TypeError) as excinfo:
+ m.overloaded3(np.array([1], dtype='uintc'))
+ assert msg(excinfo.value) == expected_exc + repr(np.array([1], dtype='uint32'))
+ with pytest.raises(TypeError) as excinfo:
+ m.overloaded3(np.array([1], dtype='float32'))
+ assert msg(excinfo.value) == expected_exc + repr(np.array([1.], dtype='float32'))
+ with pytest.raises(TypeError) as excinfo:
+ m.overloaded3(np.array([1], dtype='complex'))
+ assert msg(excinfo.value) == expected_exc + repr(np.array([1. + 0.j]))
+
+ # Exact matches:
+ assert m.overloaded4(np.array([1], dtype='double')) == 'double'
+ assert m.overloaded4(np.array([1], dtype='longlong')) == 'long long'
+ # Non-exact matches requiring conversion. Since float to integer isn't a
+ # save conversion, it should go to the double overload, but short can go to
+ # either (and so should end up on the first-registered, the long long).
+ assert m.overloaded4(np.array([1], dtype='float32')) == 'double'
+ assert m.overloaded4(np.array([1], dtype='short')) == 'long long'
+
+ assert m.overloaded5(np.array([1], dtype='double')) == 'double'
+ assert m.overloaded5(np.array([1], dtype='uintc')) == 'unsigned int'
+ assert m.overloaded5(np.array([1], dtype='float32')) == 'unsigned int'
+
+
+def test_greedy_string_overload():
+ """Tests fix for #685 - ndarray shouldn't go to std::string overload"""
+
+ assert m.issue685("abc") == "string"
+ assert m.issue685(np.array([97, 98, 99], dtype='b')) == "array"
+ assert m.issue685(123) == "other"
+
+
+def test_array_unchecked_fixed_dims(msg):
+ z1 = np.array([[1, 2], [3, 4]], dtype='float64')
+ m.proxy_add2(z1, 10)
+ assert np.all(z1 == [[11, 12], [13, 14]])
+
+ with pytest.raises(ValueError) as excinfo:
+ m.proxy_add2(np.array([1., 2, 3]), 5.0)
+ assert msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2"
+
+ expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int')
+ assert np.all(m.proxy_init3(3.0) == expect_c)
+ expect_f = np.transpose(expect_c)
+ assert np.all(m.proxy_init3F(3.0) == expect_f)
+
+ assert m.proxy_squared_L2_norm(np.array(range(6))) == 55
+ assert m.proxy_squared_L2_norm(np.array(range(6), dtype="float64")) == 55
+
+ assert m.proxy_auxiliaries2(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
+ assert m.proxy_auxiliaries2(z1) == m.array_auxiliaries2(z1)
+
+
+def test_array_unchecked_dyn_dims(msg):
+ z1 = np.array([[1, 2], [3, 4]], dtype='float64')
+ m.proxy_add2_dyn(z1, 10)
+ assert np.all(z1 == [[11, 12], [13, 14]])
+
+ expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int')
+ assert np.all(m.proxy_init3_dyn(3.0) == expect_c)
+
+ assert m.proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
+ assert m.proxy_auxiliaries2_dyn(z1) == m.array_auxiliaries2(z1)
+
+
+def test_array_failure():
+ with pytest.raises(ValueError) as excinfo:
+ m.array_fail_test()
+ assert str(excinfo.value) == 'cannot create a pybind11::array from a nullptr'
+
+ with pytest.raises(ValueError) as excinfo:
+ m.array_t_fail_test()
+ assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr'
+
+ with pytest.raises(ValueError) as excinfo:
+ m.array_fail_test_negative_size()
+ assert str(excinfo.value) == 'negative dimensions are not allowed'
+
+
+def test_initializer_list():
+ assert m.array_initializer_list1().shape == (1,)
+ assert m.array_initializer_list2().shape == (1, 2)
+ assert m.array_initializer_list3().shape == (1, 2, 3)
+ assert m.array_initializer_list4().shape == (1, 2, 3, 4)
+
+
+def test_array_resize(msg):
+ a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='float64')
+ m.array_reshape2(a)
+ assert(a.size == 9)
+ assert(np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
+
+ # total size change should succced with refcheck off
+ m.array_resize3(a, 4, False)
+ assert(a.size == 64)
+ # ... and fail with refcheck on
+ try:
+ m.array_resize3(a, 3, True)
+ except ValueError as e:
+ assert(str(e).startswith("cannot resize an array"))
+ # transposed array doesn't own data
+ b = a.transpose()
+ try:
+ m.array_resize3(b, 3, False)
+ except ValueError as e:
+ assert(str(e).startswith("cannot resize this array: it does not own its data"))
+ # ... but reshape should be fine
+ m.array_reshape2(b)
+ assert(b.shape == (8, 8))
+
+
+@pytest.unsupported_on_pypy
+def test_array_create_and_resize(msg):
+ a = m.create_and_resize(2)
+ assert(a.size == 4)
+ assert(np.all(a == 42.))
+
+
+@pytest.unsupported_on_py2
+def test_index_using_ellipsis():
+ a = m.index_using_ellipsis(np.zeros((5, 6, 7)))
+ assert a.shape == (6,)
+
+
+@pytest.unsupported_on_pypy
+def test_dtype_refcount_leak():
+ from sys import getrefcount
+ dtype = np.dtype(np.float_)
+ a = np.array([1], dtype=dtype)
+ before = getrefcount(dtype)
+ m.ndim(a)
+ after = getrefcount(dtype)
+ assert after == before
diff --git a/3rdparty/pybind11/tests/test_numpy_dtypes.cpp b/3rdparty/pybind11/tests/test_numpy_dtypes.cpp
new file mode 100644
index 00000000..467e0253
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_numpy_dtypes.cpp
@@ -0,0 +1,474 @@
+/*
+ tests/test_numpy_dtypes.cpp -- Structured and compound NumPy dtypes
+
+ Copyright (c) 2016 Ivan Smirnov
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include <pybind11/numpy.h>
+
+#ifdef __GNUC__
+#define PYBIND11_PACKED(cls) cls __attribute__((__packed__))
+#else
+#define PYBIND11_PACKED(cls) __pragma(pack(push, 1)) cls __pragma(pack(pop))
+#endif
+
+namespace py = pybind11;
+
+struct SimpleStruct {
+ bool bool_;
+ uint32_t uint_;
+ float float_;
+ long double ldbl_;
+};
+
+std::ostream& operator<<(std::ostream& os, const SimpleStruct& v) {
+ return os << "s:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_;
+}
+
+struct SimpleStructReordered {
+ bool bool_;
+ float float_;
+ uint32_t uint_;
+ long double ldbl_;
+};
+
+PYBIND11_PACKED(struct PackedStruct {
+ bool bool_;
+ uint32_t uint_;
+ float float_;
+ long double ldbl_;
+});
+
+std::ostream& operator<<(std::ostream& os, const PackedStruct& v) {
+ return os << "p:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_;
+}
+
+PYBIND11_PACKED(struct NestedStruct {
+ SimpleStruct a;
+ PackedStruct b;
+});
+
+std::ostream& operator<<(std::ostream& os, const NestedStruct& v) {
+ return os << "n:a=" << v.a << ";b=" << v.b;
+}
+
+struct PartialStruct {
+ bool bool_;
+ uint32_t uint_;
+ float float_;
+ uint64_t dummy2;
+ long double ldbl_;
+};
+
+struct PartialNestedStruct {
+ uint64_t dummy1;
+ PartialStruct a;
+ uint64_t dummy2;
+};
+
+struct UnboundStruct { };
+
+struct StringStruct {
+ char a[3];
+ std::array<char, 3> b;
+};
+
+struct ComplexStruct {
+ std::complex<float> cflt;
+ std::complex<double> cdbl;
+};
+
+std::ostream& operator<<(std::ostream& os, const ComplexStruct& v) {
+ return os << "c:" << v.cflt << "," << v.cdbl;
+}
+
+struct ArrayStruct {
+ char a[3][4];
+ int32_t b[2];
+ std::array<uint8_t, 3> c;
+ std::array<float, 2> d[4];
+};
+
+PYBIND11_PACKED(struct StructWithUglyNames {
+ int8_t __x__;
+ uint64_t __y__;
+});
+
+enum class E1 : int64_t { A = -1, B = 1 };
+enum E2 : uint8_t { X = 1, Y = 2 };
+
+PYBIND11_PACKED(struct EnumStruct {
+ E1 e1;
+ E2 e2;
+});
+
+std::ostream& operator<<(std::ostream& os, const StringStruct& v) {
+ os << "a='";
+ for (size_t i = 0; i < 3 && v.a[i]; i++) os << v.a[i];
+ os << "',b='";
+ for (size_t i = 0; i < 3 && v.b[i]; i++) os << v.b[i];
+ return os << "'";
+}
+
+std::ostream& operator<<(std::ostream& os, const ArrayStruct& v) {
+ os << "a={";
+ for (int i = 0; i < 3; i++) {
+ if (i > 0)
+ os << ',';
+ os << '{';
+ for (int j = 0; j < 3; j++)
+ os << v.a[i][j] << ',';
+ os << v.a[i][3] << '}';
+ }
+ os << "},b={" << v.b[0] << ',' << v.b[1];
+ os << "},c={" << int(v.c[0]) << ',' << int(v.c[1]) << ',' << int(v.c[2]);
+ os << "},d={";
+ for (int i = 0; i < 4; i++) {
+ if (i > 0)
+ os << ',';
+ os << '{' << v.d[i][0] << ',' << v.d[i][1] << '}';
+ }
+ return os << '}';
+}
+
+std::ostream& operator<<(std::ostream& os, const EnumStruct& v) {
+ return os << "e1=" << (v.e1 == E1::A ? "A" : "B") << ",e2=" << (v.e2 == E2::X ? "X" : "Y");
+}
+
+template <typename T>
+py::array mkarray_via_buffer(size_t n) {
+ return py::array(py::buffer_info(nullptr, sizeof(T),
+ py::format_descriptor<T>::format(),
+ 1, { n }, { sizeof(T) }));
+}
+
+#define SET_TEST_VALS(s, i) do { \
+ s.bool_ = (i) % 2 != 0; \
+ s.uint_ = (uint32_t) (i); \
+ s.float_ = (float) (i) * 1.5f; \
+ s.ldbl_ = (long double) (i) * -2.5L; } while (0)
+
+template <typename S>
+py::array_t<S, 0> create_recarray(size_t n) {
+ auto arr = mkarray_via_buffer<S>(n);
+ auto req = arr.request();
+ auto ptr = static_cast<S*>(req.ptr);
+ for (size_t i = 0; i < n; i++) {
+ SET_TEST_VALS(ptr[i], i);
+ }
+ return arr;
+}
+
+template <typename S>
+py::list print_recarray(py::array_t<S, 0> arr) {
+ const auto req = arr.request();
+ const auto ptr = static_cast<S*>(req.ptr);
+ auto l = py::list();
+ for (ssize_t i = 0; i < req.size; i++) {
+ std::stringstream ss;
+ ss << ptr[i];
+ l.append(py::str(ss.str()));
+ }
+ return l;
+}
+
+py::array_t<int32_t, 0> test_array_ctors(int i) {
+ using arr_t = py::array_t<int32_t, 0>;
+
+ std::vector<int32_t> data { 1, 2, 3, 4, 5, 6 };
+ std::vector<ssize_t> shape { 3, 2 };
+ std::vector<ssize_t> strides { 8, 4 };
+
+ auto ptr = data.data();
+ auto vptr = (void *) ptr;
+ auto dtype = py::dtype("int32");
+
+ py::buffer_info buf_ndim1(vptr, 4, "i", 6);
+ py::buffer_info buf_ndim1_null(nullptr, 4, "i", 6);
+ py::buffer_info buf_ndim2(vptr, 4, "i", 2, shape, strides);
+ py::buffer_info buf_ndim2_null(nullptr, 4, "i", 2, shape, strides);
+
+ auto fill = [](py::array arr) {
+ auto req = arr.request();
+ for (int i = 0; i < 6; i++) ((int32_t *) req.ptr)[i] = i + 1;
+ return arr;
+ };
+
+ switch (i) {
+ // shape: (3, 2)
+ case 10: return arr_t(shape, strides, ptr);
+ case 11: return py::array(shape, strides, ptr);
+ case 12: return py::array(dtype, shape, strides, vptr);
+ case 13: return arr_t(shape, ptr);
+ case 14: return py::array(shape, ptr);
+ case 15: return py::array(dtype, shape, vptr);
+ case 16: return arr_t(buf_ndim2);
+ case 17: return py::array(buf_ndim2);
+ // shape: (3, 2) - post-fill
+ case 20: return fill(arr_t(shape, strides));
+ case 21: return py::array(shape, strides, ptr); // can't have nullptr due to templated ctor
+ case 22: return fill(py::array(dtype, shape, strides));
+ case 23: return fill(arr_t(shape));
+ case 24: return py::array(shape, ptr); // can't have nullptr due to templated ctor
+ case 25: return fill(py::array(dtype, shape));
+ case 26: return fill(arr_t(buf_ndim2_null));
+ case 27: return fill(py::array(buf_ndim2_null));
+ // shape: (6, )
+ case 30: return arr_t(6, ptr);
+ case 31: return py::array(6, ptr);
+ case 32: return py::array(dtype, 6, vptr);
+ case 33: return arr_t(buf_ndim1);
+ case 34: return py::array(buf_ndim1);
+ // shape: (6, )
+ case 40: return fill(arr_t(6));
+ case 41: return py::array(6, ptr); // can't have nullptr due to templated ctor
+ case 42: return fill(py::array(dtype, 6));
+ case 43: return fill(arr_t(buf_ndim1_null));
+ case 44: return fill(py::array(buf_ndim1_null));
+ }
+ return arr_t();
+}
+
+py::list test_dtype_ctors() {
+ py::list list;
+ list.append(py::dtype("int32"));
+ list.append(py::dtype(std::string("float64")));
+ list.append(py::dtype::from_args(py::str("bool")));
+ py::list names, offsets, formats;
+ py::dict dict;
+ names.append(py::str("a")); names.append(py::str("b")); dict["names"] = names;
+ offsets.append(py::int_(1)); offsets.append(py::int_(10)); dict["offsets"] = offsets;
+ formats.append(py::dtype("int32")); formats.append(py::dtype("float64")); dict["formats"] = formats;
+ dict["itemsize"] = py::int_(20);
+ list.append(py::dtype::from_args(dict));
+ list.append(py::dtype(names, formats, offsets, 20));
+ list.append(py::dtype(py::buffer_info((void *) 0, sizeof(unsigned int), "I", 1)));
+ list.append(py::dtype(py::buffer_info((void *) 0, 0, "T{i:a:f:b:}", 1)));
+ return list;
+}
+
+struct A {};
+struct B {};
+
+TEST_SUBMODULE(numpy_dtypes, m) {
+ try { py::module::import("numpy"); }
+ catch (...) { return; }
+
+ // typeinfo may be registered before the dtype descriptor for scalar casts to work...
+ py::class_<SimpleStruct>(m, "SimpleStruct");
+
+ PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_);
+ PYBIND11_NUMPY_DTYPE(SimpleStructReordered, bool_, uint_, float_, ldbl_);
+ PYBIND11_NUMPY_DTYPE(PackedStruct, bool_, uint_, float_, ldbl_);
+ PYBIND11_NUMPY_DTYPE(NestedStruct, a, b);
+ PYBIND11_NUMPY_DTYPE(PartialStruct, bool_, uint_, float_, ldbl_);
+ PYBIND11_NUMPY_DTYPE(PartialNestedStruct, a);
+ PYBIND11_NUMPY_DTYPE(StringStruct, a, b);
+ PYBIND11_NUMPY_DTYPE(ArrayStruct, a, b, c, d);
+ PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2);
+ PYBIND11_NUMPY_DTYPE(ComplexStruct, cflt, cdbl);
+
+ // ... or after
+ py::class_<PackedStruct>(m, "PackedStruct");
+
+ PYBIND11_NUMPY_DTYPE_EX(StructWithUglyNames, __x__, "x", __y__, "y");
+
+ // If uncommented, this should produce a static_assert failure telling the user that the struct
+ // is not a POD type
+// struct NotPOD { std::string v; NotPOD() : v("hi") {}; };
+// PYBIND11_NUMPY_DTYPE(NotPOD, v);
+
+ // Check that dtypes can be registered programmatically, both from
+ // initializer lists of field descriptors and from other containers.
+ py::detail::npy_format_descriptor<A>::register_dtype(
+ {}
+ );
+ py::detail::npy_format_descriptor<B>::register_dtype(
+ std::vector<py::detail::field_descriptor>{}
+ );
+
+ // test_recarray, test_scalar_conversion
+ m.def("create_rec_simple", &create_recarray<SimpleStruct>);
+ m.def("create_rec_packed", &create_recarray<PackedStruct>);
+ m.def("create_rec_nested", [](size_t n) { // test_signature
+ py::array_t<NestedStruct, 0> arr = mkarray_via_buffer<NestedStruct>(n);
+ auto req = arr.request();
+ auto ptr = static_cast<NestedStruct*>(req.ptr);
+ for (size_t i = 0; i < n; i++) {
+ SET_TEST_VALS(ptr[i].a, i);
+ SET_TEST_VALS(ptr[i].b, i + 1);
+ }
+ return arr;
+ });
+ m.def("create_rec_partial", &create_recarray<PartialStruct>);
+ m.def("create_rec_partial_nested", [](size_t n) {
+ py::array_t<PartialNestedStruct, 0> arr = mkarray_via_buffer<PartialNestedStruct>(n);
+ auto req = arr.request();
+ auto ptr = static_cast<PartialNestedStruct*>(req.ptr);
+ for (size_t i = 0; i < n; i++) {
+ SET_TEST_VALS(ptr[i].a, i);
+ }
+ return arr;
+ });
+ m.def("print_rec_simple", &print_recarray<SimpleStruct>);
+ m.def("print_rec_packed", &print_recarray<PackedStruct>);
+ m.def("print_rec_nested", &print_recarray<NestedStruct>);
+
+ // test_format_descriptors
+ m.def("get_format_unbound", []() { return py::format_descriptor<UnboundStruct>::format(); });
+ m.def("print_format_descriptors", []() {
+ py::list l;
+ for (const auto &fmt : {
+ py::format_descriptor<SimpleStruct>::format(),
+ py::format_descriptor<PackedStruct>::format(),
+ py::format_descriptor<NestedStruct>::format(),
+ py::format_descriptor<PartialStruct>::format(),
+ py::format_descriptor<PartialNestedStruct>::format(),
+ py::format_descriptor<StringStruct>::format(),
+ py::format_descriptor<ArrayStruct>::format(),
+ py::format_descriptor<EnumStruct>::format(),
+ py::format_descriptor<ComplexStruct>::format()
+ }) {
+ l.append(py::cast(fmt));
+ }
+ return l;
+ });
+
+ // test_dtype
+ m.def("print_dtypes", []() {
+ py::list l;
+ for (const py::handle &d : {
+ py::dtype::of<SimpleStruct>(),
+ py::dtype::of<PackedStruct>(),
+ py::dtype::of<NestedStruct>(),
+ py::dtype::of<PartialStruct>(),
+ py::dtype::of<PartialNestedStruct>(),
+ py::dtype::of<StringStruct>(),
+ py::dtype::of<ArrayStruct>(),
+ py::dtype::of<EnumStruct>(),
+ py::dtype::of<StructWithUglyNames>(),
+ py::dtype::of<ComplexStruct>()
+ })
+ l.append(py::str(d));
+ return l;
+ });
+ m.def("test_dtype_ctors", &test_dtype_ctors);
+ m.def("test_dtype_methods", []() {
+ py::list list;
+ auto dt1 = py::dtype::of<int32_t>();
+ auto dt2 = py::dtype::of<SimpleStruct>();
+ list.append(dt1); list.append(dt2);
+ list.append(py::bool_(dt1.has_fields())); list.append(py::bool_(dt2.has_fields()));
+ list.append(py::int_(dt1.itemsize())); list.append(py::int_(dt2.itemsize()));
+ return list;
+ });
+ struct TrailingPaddingStruct {
+ int32_t a;
+ char b;
+ };
+ PYBIND11_NUMPY_DTYPE(TrailingPaddingStruct, a, b);
+ m.def("trailing_padding_dtype", []() { return py::dtype::of<TrailingPaddingStruct>(); });
+
+ // test_string_array
+ m.def("create_string_array", [](bool non_empty) {
+ py::array_t<StringStruct, 0> arr = mkarray_via_buffer<StringStruct>(non_empty ? 4 : 0);
+ if (non_empty) {
+ auto req = arr.request();
+ auto ptr = static_cast<StringStruct*>(req.ptr);
+ for (ssize_t i = 0; i < req.size * req.itemsize; i++)
+ static_cast<char*>(req.ptr)[i] = 0;
+ ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a';
+ ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a';
+ ptr[3].a[0] = 'a'; ptr[3].b[0] = 'a';
+
+ ptr[2].a[1] = 'b'; ptr[2].b[1] = 'b';
+ ptr[3].a[1] = 'b'; ptr[3].b[1] = 'b';
+
+ ptr[3].a[2] = 'c'; ptr[3].b[2] = 'c';
+ }
+ return arr;
+ });
+ m.def("print_string_array", &print_recarray<StringStruct>);
+
+ // test_array_array
+ m.def("create_array_array", [](size_t n) {
+ py::array_t<ArrayStruct, 0> arr = mkarray_via_buffer<ArrayStruct>(n);
+ auto ptr = (ArrayStruct *) arr.mutable_data();
+ for (size_t i = 0; i < n; i++) {
+ for (size_t j = 0; j < 3; j++)
+ for (size_t k = 0; k < 4; k++)
+ ptr[i].a[j][k] = char('A' + (i * 100 + j * 10 + k) % 26);
+ for (size_t j = 0; j < 2; j++)
+ ptr[i].b[j] = int32_t(i * 1000 + j);
+ for (size_t j = 0; j < 3; j++)
+ ptr[i].c[j] = uint8_t(i * 10 + j);
+ for (size_t j = 0; j < 4; j++)
+ for (size_t k = 0; k < 2; k++)
+ ptr[i].d[j][k] = float(i) * 100.0f + float(j) * 10.0f + float(k);
+ }
+ return arr;
+ });
+ m.def("print_array_array", &print_recarray<ArrayStruct>);
+
+ // test_enum_array
+ m.def("create_enum_array", [](size_t n) {
+ py::array_t<EnumStruct, 0> arr = mkarray_via_buffer<EnumStruct>(n);
+ auto ptr = (EnumStruct *) arr.mutable_data();
+ for (size_t i = 0; i < n; i++) {
+ ptr[i].e1 = static_cast<E1>(-1 + ((int) i % 2) * 2);
+ ptr[i].e2 = static_cast<E2>(1 + (i % 2));
+ }
+ return arr;
+ });
+ m.def("print_enum_array", &print_recarray<EnumStruct>);
+
+ // test_complex_array
+ m.def("create_complex_array", [](size_t n) {
+ py::array_t<ComplexStruct, 0> arr = mkarray_via_buffer<ComplexStruct>(n);
+ auto ptr = (ComplexStruct *) arr.mutable_data();
+ for (size_t i = 0; i < n; i++) {
+ ptr[i].cflt.real(float(i));
+ ptr[i].cflt.imag(float(i) + 0.25f);
+ ptr[i].cdbl.real(double(i) + 0.5);
+ ptr[i].cdbl.imag(double(i) + 0.75);
+ }
+ return arr;
+ });
+ m.def("print_complex_array", &print_recarray<ComplexStruct>);
+
+ // test_array_constructors
+ m.def("test_array_ctors", &test_array_ctors);
+
+ // test_compare_buffer_info
+ struct CompareStruct {
+ bool x;
+ uint32_t y;
+ float z;
+ };
+ PYBIND11_NUMPY_DTYPE(CompareStruct, x, y, z);
+ m.def("compare_buffer_info", []() {
+ py::list list;
+ list.append(py::bool_(py::detail::compare_buffer_info<float>::compare(py::buffer_info(nullptr, sizeof(float), "f", 1))));
+ list.append(py::bool_(py::detail::compare_buffer_info<unsigned>::compare(py::buffer_info(nullptr, sizeof(int), "I", 1))));
+ list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), "l", 1))));
+ list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), sizeof(long) == sizeof(int) ? "i" : "q", 1))));
+ list.append(py::bool_(py::detail::compare_buffer_info<CompareStruct>::compare(py::buffer_info(nullptr, sizeof(CompareStruct), "T{?:x:3xI:y:f:z:}", 1))));
+ return list;
+ });
+ m.def("buffer_to_dtype", [](py::buffer& buf) { return py::dtype(buf.request()); });
+
+ // test_scalar_conversion
+ m.def("f_simple", [](SimpleStruct s) { return s.uint_ * 10; });
+ m.def("f_packed", [](PackedStruct s) { return s.uint_ * 10; });
+ m.def("f_nested", [](NestedStruct s) { return s.a.uint_ * 10; });
+
+ // test_register_dtype
+ m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
+
+ // test_str_leak
+ m.def("dtype_wrapper", [](py::object d) { return py::dtype::from_args(std::move(d)); });
+}
diff --git a/3rdparty/pybind11/tests/test_numpy_dtypes.py b/3rdparty/pybind11/tests/test_numpy_dtypes.py
new file mode 100644
index 00000000..2e638851
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_numpy_dtypes.py
@@ -0,0 +1,310 @@
+import re
+import pytest
+from pybind11_tests import numpy_dtypes as m
+
+pytestmark = pytest.requires_numpy
+
+with pytest.suppress(ImportError):
+ import numpy as np
+
+
+@pytest.fixture(scope='module')
+def simple_dtype():
+ ld = np.dtype('longdouble')
+ return np.dtype({'names': ['bool_', 'uint_', 'float_', 'ldbl_'],
+ 'formats': ['?', 'u4', 'f4', 'f{}'.format(ld.itemsize)],
+ 'offsets': [0, 4, 8, (16 if ld.alignment > 4 else 12)]})
+
+
+@pytest.fixture(scope='module')
+def packed_dtype():
+ return np.dtype([('bool_', '?'), ('uint_', 'u4'), ('float_', 'f4'), ('ldbl_', 'g')])
+
+
+def dt_fmt():
+ from sys import byteorder
+ e = '<' if byteorder == 'little' else '>'
+ return ("{{'names':['bool_','uint_','float_','ldbl_'],"
+ " 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}'],"
+ " 'offsets':[0,4,8,{}], 'itemsize':{}}}")
+
+
+def simple_dtype_fmt():
+ ld = np.dtype('longdouble')
+ simple_ld_off = 12 + 4 * (ld.alignment > 4)
+ return dt_fmt().format(ld.itemsize, simple_ld_off, simple_ld_off + ld.itemsize)
+
+
+def packed_dtype_fmt():
+ from sys import byteorder
+ return "[('bool_', '?'), ('uint_', '{e}u4'), ('float_', '{e}f4'), ('ldbl_', '{e}f{}')]".format(
+ np.dtype('longdouble').itemsize, e='<' if byteorder == 'little' else '>')
+
+
+def partial_ld_offset():
+ return 12 + 4 * (np.dtype('uint64').alignment > 4) + 8 + 8 * (
+ np.dtype('longdouble').alignment > 8)
+
+
+def partial_dtype_fmt():
+ ld = np.dtype('longdouble')
+ partial_ld_off = partial_ld_offset()
+ return dt_fmt().format(ld.itemsize, partial_ld_off, partial_ld_off + ld.itemsize)
+
+
+def partial_nested_fmt():
+ ld = np.dtype('longdouble')
+ partial_nested_off = 8 + 8 * (ld.alignment > 8)
+ partial_ld_off = partial_ld_offset()
+ partial_nested_size = partial_nested_off * 2 + partial_ld_off + ld.itemsize
+ return "{{'names':['a'], 'formats':[{}], 'offsets':[{}], 'itemsize':{}}}".format(
+ partial_dtype_fmt(), partial_nested_off, partial_nested_size)
+
+
+def assert_equal(actual, expected_data, expected_dtype):
+ np.testing.assert_equal(actual, np.array(expected_data, dtype=expected_dtype))
+
+
+def test_format_descriptors():
+ with pytest.raises(RuntimeError) as excinfo:
+ m.get_format_unbound()
+ assert re.match('^NumPy type info missing for .*UnboundStruct.*$', str(excinfo.value))
+
+ ld = np.dtype('longdouble')
+ ldbl_fmt = ('4x' if ld.alignment > 4 else '') + ld.char
+ ss_fmt = "^T{?:bool_:3xI:uint_:f:float_:" + ldbl_fmt + ":ldbl_:}"
+ dbl = np.dtype('double')
+ partial_fmt = ("^T{?:bool_:3xI:uint_:f:float_:" +
+ str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) +
+ "xg:ldbl_:}")
+ nested_extra = str(max(8, ld.alignment))
+ assert m.print_format_descriptors() == [
+ ss_fmt,
+ "^T{?:bool_:I:uint_:f:float_:g:ldbl_:}",
+ "^T{" + ss_fmt + ":a:^T{?:bool_:I:uint_:f:float_:g:ldbl_:}:b:}",
+ partial_fmt,
+ "^T{" + nested_extra + "x" + partial_fmt + ":a:" + nested_extra + "x}",
+ "^T{3s:a:3s:b:}",
+ "^T{(3)4s:a:(2)i:b:(3)B:c:1x(4, 2)f:d:}",
+ '^T{q:e1:B:e2:}',
+ '^T{Zf:cflt:Zd:cdbl:}'
+ ]
+
+
+def test_dtype(simple_dtype):
+ from sys import byteorder
+ e = '<' if byteorder == 'little' else '>'
+
+ assert m.print_dtypes() == [
+ simple_dtype_fmt(),
+ packed_dtype_fmt(),
+ "[('a', {}), ('b', {})]".format(simple_dtype_fmt(), packed_dtype_fmt()),
+ partial_dtype_fmt(),
+ partial_nested_fmt(),
+ "[('a', 'S3'), ('b', 'S3')]",
+ ("{{'names':['a','b','c','d'], " +
+ "'formats':[('S4', (3,)),('" + e + "i4', (2,)),('u1', (3,)),('" + e + "f4', (4, 2))], " +
+ "'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e),
+ "[('e1', '" + e + "i8'), ('e2', 'u1')]",
+ "[('x', 'i1'), ('y', '" + e + "u8')]",
+ "[('cflt', '" + e + "c8'), ('cdbl', '" + e + "c16')]"
+ ]
+
+ d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'],
+ 'offsets': [1, 10], 'itemsize': 20})
+ d2 = np.dtype([('a', 'i4'), ('b', 'f4')])
+ assert m.test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'),
+ np.dtype('bool'), d1, d1, np.dtype('uint32'), d2]
+
+ assert m.test_dtype_methods() == [np.dtype('int32'), simple_dtype, False, True,
+ np.dtype('int32').itemsize, simple_dtype.itemsize]
+
+ assert m.trailing_padding_dtype() == m.buffer_to_dtype(np.zeros(1, m.trailing_padding_dtype()))
+
+
+def test_recarray(simple_dtype, packed_dtype):
+ elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)]
+
+ for func, dtype in [(m.create_rec_simple, simple_dtype), (m.create_rec_packed, packed_dtype)]:
+ arr = func(0)
+ assert arr.dtype == dtype
+ assert_equal(arr, [], simple_dtype)
+ assert_equal(arr, [], packed_dtype)
+
+ arr = func(3)
+ assert arr.dtype == dtype
+ assert_equal(arr, elements, simple_dtype)
+ assert_equal(arr, elements, packed_dtype)
+
+ if dtype == simple_dtype:
+ assert m.print_rec_simple(arr) == [
+ "s:0,0,0,-0",
+ "s:1,1,1.5,-2.5",
+ "s:0,2,3,-5"
+ ]
+ else:
+ assert m.print_rec_packed(arr) == [
+ "p:0,0,0,-0",
+ "p:1,1,1.5,-2.5",
+ "p:0,2,3,-5"
+ ]
+
+ nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)])
+
+ arr = m.create_rec_nested(0)
+ assert arr.dtype == nested_dtype
+ assert_equal(arr, [], nested_dtype)
+
+ arr = m.create_rec_nested(3)
+ assert arr.dtype == nested_dtype
+ assert_equal(arr, [((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)),
+ ((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)),
+ ((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5))], nested_dtype)
+ assert m.print_rec_nested(arr) == [
+ "n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5",
+ "n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5",
+ "n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5"
+ ]
+
+ arr = m.create_rec_partial(3)
+ assert str(arr.dtype) == partial_dtype_fmt()
+ partial_dtype = arr.dtype
+ assert '' not in arr.dtype.fields
+ assert partial_dtype.itemsize > simple_dtype.itemsize
+ assert_equal(arr, elements, simple_dtype)
+ assert_equal(arr, elements, packed_dtype)
+
+ arr = m.create_rec_partial_nested(3)
+ assert str(arr.dtype) == partial_nested_fmt()
+ assert '' not in arr.dtype.fields
+ assert '' not in arr.dtype.fields['a'][0].fields
+ assert arr.dtype.itemsize > partial_dtype.itemsize
+ np.testing.assert_equal(arr['a'], m.create_rec_partial(3))
+
+
+def test_array_constructors():
+ data = np.arange(1, 7, dtype='int32')
+ for i in range(8):
+ np.testing.assert_array_equal(m.test_array_ctors(10 + i), data.reshape((3, 2)))
+ np.testing.assert_array_equal(m.test_array_ctors(20 + i), data.reshape((3, 2)))
+ for i in range(5):
+ np.testing.assert_array_equal(m.test_array_ctors(30 + i), data)
+ np.testing.assert_array_equal(m.test_array_ctors(40 + i), data)
+
+
+def test_string_array():
+ arr = m.create_string_array(True)
+ assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]"
+ assert m.print_string_array(arr) == [
+ "a='',b=''",
+ "a='a',b='a'",
+ "a='ab',b='ab'",
+ "a='abc',b='abc'"
+ ]
+ dtype = arr.dtype
+ assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc']
+ assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc']
+ arr = m.create_string_array(False)
+ assert dtype == arr.dtype
+
+
+def test_array_array():
+ from sys import byteorder
+ e = '<' if byteorder == 'little' else '>'
+
+ arr = m.create_array_array(3)
+ assert str(arr.dtype) == (
+ "{{'names':['a','b','c','d'], " +
+ "'formats':[('S4', (3,)),('" + e + "i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], " +
+ "'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e)
+ assert m.print_array_array(arr) == [
+ "a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," +
+ "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}",
+ "a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," +
+ "c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}",
+ "a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001}," +
+ "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}",
+ ]
+ assert arr['a'].tolist() == [[b'ABCD', b'KLMN', b'UVWX'],
+ [b'WXYZ', b'GHIJ', b'QRST'],
+ [b'STUV', b'CDEF', b'MNOP']]
+ assert arr['b'].tolist() == [[0, 1], [1000, 1001], [2000, 2001]]
+ assert m.create_array_array(0).dtype == arr.dtype
+
+
+def test_enum_array():
+ from sys import byteorder
+ e = '<' if byteorder == 'little' else '>'
+
+ arr = m.create_enum_array(3)
+ dtype = arr.dtype
+ assert dtype == np.dtype([('e1', e + 'i8'), ('e2', 'u1')])
+ assert m.print_enum_array(arr) == [
+ "e1=A,e2=X",
+ "e1=B,e2=Y",
+ "e1=A,e2=X"
+ ]
+ assert arr['e1'].tolist() == [-1, 1, -1]
+ assert arr['e2'].tolist() == [1, 2, 1]
+ assert m.create_enum_array(0).dtype == dtype
+
+
+def test_complex_array():
+ from sys import byteorder
+ e = '<' if byteorder == 'little' else '>'
+
+ arr = m.create_complex_array(3)
+ dtype = arr.dtype
+ assert dtype == np.dtype([('cflt', e + 'c8'), ('cdbl', e + 'c16')])
+ assert m.print_complex_array(arr) == [
+ "c:(0,0.25),(0.5,0.75)",
+ "c:(1,1.25),(1.5,1.75)",
+ "c:(2,2.25),(2.5,2.75)"
+ ]
+ assert arr['cflt'].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j]
+ assert arr['cdbl'].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j]
+ assert m.create_complex_array(0).dtype == dtype
+
+
+def test_signature(doc):
+ assert doc(m.create_rec_nested) == \
+ "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
+
+
+def test_scalar_conversion():
+ n = 3
+ arrays = [m.create_rec_simple(n), m.create_rec_packed(n),
+ m.create_rec_nested(n), m.create_enum_array(n)]
+ funcs = [m.f_simple, m.f_packed, m.f_nested]
+
+ for i, func in enumerate(funcs):
+ for j, arr in enumerate(arrays):
+ if i == j and i < 2:
+ assert [func(arr[k]) for k in range(n)] == [k * 10 for k in range(n)]
+ else:
+ with pytest.raises(TypeError) as excinfo:
+ func(arr[0])
+ assert 'incompatible function arguments' in str(excinfo.value)
+
+
+def test_register_dtype():
+ with pytest.raises(RuntimeError) as excinfo:
+ m.register_dtype()
+ assert 'dtype is already registered' in str(excinfo.value)
+
+
+@pytest.unsupported_on_pypy
+def test_str_leak():
+ from sys import getrefcount
+ fmt = "f4"
+ pytest.gc_collect()
+ start = getrefcount(fmt)
+ d = m.dtype_wrapper(fmt)
+ assert d is np.dtype("f4")
+ del d
+ pytest.gc_collect()
+ assert getrefcount(fmt) == start
+
+
+def test_compare_buffer_info():
+ assert all(m.compare_buffer_info())
diff --git a/3rdparty/pybind11/tests/test_numpy_vectorize.cpp b/3rdparty/pybind11/tests/test_numpy_vectorize.cpp
new file mode 100644
index 00000000..a875a74b
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_numpy_vectorize.cpp
@@ -0,0 +1,89 @@
+/*
+ tests/test_numpy_vectorize.cpp -- auto-vectorize functions over NumPy array
+ arguments
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include <pybind11/numpy.h>
+
+double my_func(int x, float y, double z) {
+ py::print("my_func(x:int={}, y:float={:.0f}, z:float={:.0f})"_s.format(x, y, z));
+ return (float) x*y*z;
+}
+
+TEST_SUBMODULE(numpy_vectorize, m) {
+ try { py::module::import("numpy"); }
+ catch (...) { return; }
+
+ // test_vectorize, test_docs, test_array_collapse
+ // Vectorize all arguments of a function (though non-vector arguments are also allowed)
+ m.def("vectorized_func", py::vectorize(my_func));
+
+ // Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization)
+ m.def("vectorized_func2",
+ [](py::array_t<int> x, py::array_t<float> y, float z) {
+ return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(x, y);
+ }
+ );
+
+ // Vectorize a complex-valued function
+ m.def("vectorized_func3", py::vectorize(
+ [](std::complex<double> c) { return c * std::complex<double>(2.f); }
+ ));
+
+ // test_type_selection
+ // Numpy function which only accepts specific data types
+ m.def("selective_func", [](py::array_t<int, py::array::c_style>) { return "Int branch taken."; });
+ m.def("selective_func", [](py::array_t<float, py::array::c_style>) { return "Float branch taken."; });
+ m.def("selective_func", [](py::array_t<std::complex<float>, py::array::c_style>) { return "Complex float branch taken."; });
+
+
+ // test_passthrough_arguments
+ // Passthrough test: references and non-pod types should be automatically passed through (in the
+ // function definition below, only `b`, `d`, and `g` are vectorized):
+ struct NonPODClass {
+ NonPODClass(int v) : value{v} {}
+ int value;
+ };
+ py::class_<NonPODClass>(m, "NonPODClass").def(py::init<int>());
+ m.def("vec_passthrough", py::vectorize(
+ [](double *a, double b, py::array_t<double> c, const int &d, int &e, NonPODClass f, const double g) {
+ return *a + b + c.at(0) + d + e + f.value + g;
+ }
+ ));
+
+ // test_method_vectorization
+ struct VectorizeTestClass {
+ VectorizeTestClass(int v) : value{v} {};
+ float method(int x, float y) { return y + (float) (x + value); }
+ int value = 0;
+ };
+ py::class_<VectorizeTestClass> vtc(m, "VectorizeTestClass");
+ vtc .def(py::init<int>())
+ .def_readwrite("value", &VectorizeTestClass::value);
+
+ // Automatic vectorizing of methods
+ vtc.def("method", py::vectorize(&VectorizeTestClass::method));
+
+ // test_trivial_broadcasting
+ // Internal optimization test for whether the input is trivially broadcastable:
+ py::enum_<py::detail::broadcast_trivial>(m, "trivial")
+ .value("f_trivial", py::detail::broadcast_trivial::f_trivial)
+ .value("c_trivial", py::detail::broadcast_trivial::c_trivial)
+ .value("non_trivial", py::detail::broadcast_trivial::non_trivial);
+ m.def("vectorized_is_trivial", [](
+ py::array_t<int, py::array::forcecast> arg1,
+ py::array_t<float, py::array::forcecast> arg2,
+ py::array_t<double, py::array::forcecast> arg3
+ ) {
+ ssize_t ndim;
+ std::vector<ssize_t> shape;
+ std::array<py::buffer_info, 3> buffers {{ arg1.request(), arg2.request(), arg3.request() }};
+ return py::detail::broadcast(buffers, ndim, shape);
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_numpy_vectorize.py b/3rdparty/pybind11/tests/test_numpy_vectorize.py
new file mode 100644
index 00000000..0e9c8839
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_numpy_vectorize.py
@@ -0,0 +1,196 @@
+import pytest
+from pybind11_tests import numpy_vectorize as m
+
+pytestmark = pytest.requires_numpy
+
+with pytest.suppress(ImportError):
+ import numpy as np
+
+
+def test_vectorize(capture):
+ assert np.isclose(m.vectorized_func3(np.array(3 + 7j)), [6 + 14j])
+
+ for f in [m.vectorized_func, m.vectorized_func2]:
+ with capture:
+ assert np.isclose(f(1, 2, 3), 6)
+ assert capture == "my_func(x:int=1, y:float=2, z:float=3)"
+ with capture:
+ assert np.isclose(f(np.array(1), np.array(2), 3), 6)
+ assert capture == "my_func(x:int=1, y:float=2, z:float=3)"
+ with capture:
+ assert np.allclose(f(np.array([1, 3]), np.array([2, 4]), 3), [6, 36])
+ assert capture == """
+ my_func(x:int=1, y:float=2, z:float=3)
+ my_func(x:int=3, y:float=4, z:float=3)
+ """
+ with capture:
+ a = np.array([[1, 2], [3, 4]], order='F')
+ b = np.array([[10, 20], [30, 40]], order='F')
+ c = 3
+ result = f(a, b, c)
+ assert np.allclose(result, a * b * c)
+ assert result.flags.f_contiguous
+ # All inputs are F order and full or singletons, so we the result is in col-major order:
+ assert capture == """
+ my_func(x:int=1, y:float=10, z:float=3)
+ my_func(x:int=3, y:float=30, z:float=3)
+ my_func(x:int=2, y:float=20, z:float=3)
+ my_func(x:int=4, y:float=40, z:float=3)
+ """
+ with capture:
+ a, b, c = np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3
+ assert np.allclose(f(a, b, c), a * b * c)
+ assert capture == """
+ my_func(x:int=1, y:float=2, z:float=3)
+ my_func(x:int=3, y:float=4, z:float=3)
+ my_func(x:int=5, y:float=6, z:float=3)
+ my_func(x:int=7, y:float=8, z:float=3)
+ my_func(x:int=9, y:float=10, z:float=3)
+ my_func(x:int=11, y:float=12, z:float=3)
+ """
+ with capture:
+ a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2
+ assert np.allclose(f(a, b, c), a * b * c)
+ assert capture == """
+ my_func(x:int=1, y:float=2, z:float=2)
+ my_func(x:int=2, y:float=3, z:float=2)
+ my_func(x:int=3, y:float=4, z:float=2)
+ my_func(x:int=4, y:float=2, z:float=2)
+ my_func(x:int=5, y:float=3, z:float=2)
+ my_func(x:int=6, y:float=4, z:float=2)
+ """
+ with capture:
+ a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2
+ assert np.allclose(f(a, b, c), a * b * c)
+ assert capture == """
+ my_func(x:int=1, y:float=2, z:float=2)
+ my_func(x:int=2, y:float=2, z:float=2)
+ my_func(x:int=3, y:float=2, z:float=2)
+ my_func(x:int=4, y:float=3, z:float=2)
+ my_func(x:int=5, y:float=3, z:float=2)
+ my_func(x:int=6, y:float=3, z:float=2)
+ """
+ with capture:
+ a, b, c = np.array([[1, 2, 3], [4, 5, 6]], order='F'), np.array([[2], [3]]), 2
+ assert np.allclose(f(a, b, c), a * b * c)
+ assert capture == """
+ my_func(x:int=1, y:float=2, z:float=2)
+ my_func(x:int=2, y:float=2, z:float=2)
+ my_func(x:int=3, y:float=2, z:float=2)
+ my_func(x:int=4, y:float=3, z:float=2)
+ my_func(x:int=5, y:float=3, z:float=2)
+ my_func(x:int=6, y:float=3, z:float=2)
+ """
+ with capture:
+ a, b, c = np.array([[1, 2, 3], [4, 5, 6]])[::, ::2], np.array([[2], [3]]), 2
+ assert np.allclose(f(a, b, c), a * b * c)
+ assert capture == """
+ my_func(x:int=1, y:float=2, z:float=2)
+ my_func(x:int=3, y:float=2, z:float=2)
+ my_func(x:int=4, y:float=3, z:float=2)
+ my_func(x:int=6, y:float=3, z:float=2)
+ """
+ with capture:
+ a, b, c = np.array([[1, 2, 3], [4, 5, 6]], order='F')[::, ::2], np.array([[2], [3]]), 2
+ assert np.allclose(f(a, b, c), a * b * c)
+ assert capture == """
+ my_func(x:int=1, y:float=2, z:float=2)
+ my_func(x:int=3, y:float=2, z:float=2)
+ my_func(x:int=4, y:float=3, z:float=2)
+ my_func(x:int=6, y:float=3, z:float=2)
+ """
+
+
+def test_type_selection():
+ assert m.selective_func(np.array([1], dtype=np.int32)) == "Int branch taken."
+ assert m.selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken."
+ assert m.selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken."
+
+
+def test_docs(doc):
+ assert doc(m.vectorized_func) == """
+ vectorized_func(arg0: numpy.ndarray[int32], arg1: numpy.ndarray[float32], arg2: numpy.ndarray[float64]) -> object
+ """ # noqa: E501 line too long
+
+
+def test_trivial_broadcasting():
+ trivial, vectorized_is_trivial = m.trivial, m.vectorized_is_trivial
+
+ assert vectorized_is_trivial(1, 2, 3) == trivial.c_trivial
+ assert vectorized_is_trivial(np.array(1), np.array(2), 3) == trivial.c_trivial
+ assert vectorized_is_trivial(np.array([1, 3]), np.array([2, 4]), 3) == trivial.c_trivial
+ assert trivial.c_trivial == vectorized_is_trivial(
+ np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3)
+ assert vectorized_is_trivial(
+ np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2) == trivial.non_trivial
+ assert vectorized_is_trivial(
+ np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2) == trivial.non_trivial
+ z1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype='int32')
+ z2 = np.array(z1, dtype='float32')
+ z3 = np.array(z1, dtype='float64')
+ assert vectorized_is_trivial(z1, z2, z3) == trivial.c_trivial
+ assert vectorized_is_trivial(1, z2, z3) == trivial.c_trivial
+ assert vectorized_is_trivial(z1, 1, z3) == trivial.c_trivial
+ assert vectorized_is_trivial(z1, z2, 1) == trivial.c_trivial
+ assert vectorized_is_trivial(z1[::2, ::2], 1, 1) == trivial.non_trivial
+ assert vectorized_is_trivial(1, 1, z1[::2, ::2]) == trivial.c_trivial
+ assert vectorized_is_trivial(1, 1, z3[::2, ::2]) == trivial.non_trivial
+ assert vectorized_is_trivial(z1, 1, z3[1::4, 1::4]) == trivial.c_trivial
+
+ y1 = np.array(z1, order='F')
+ y2 = np.array(y1)
+ y3 = np.array(y1)
+ assert vectorized_is_trivial(y1, y2, y3) == trivial.f_trivial
+ assert vectorized_is_trivial(y1, 1, 1) == trivial.f_trivial
+ assert vectorized_is_trivial(1, y2, 1) == trivial.f_trivial
+ assert vectorized_is_trivial(1, 1, y3) == trivial.f_trivial
+ assert vectorized_is_trivial(y1, z2, 1) == trivial.non_trivial
+ assert vectorized_is_trivial(z1[1::4, 1::4], y2, 1) == trivial.f_trivial
+ assert vectorized_is_trivial(y1[1::4, 1::4], z2, 1) == trivial.c_trivial
+
+ assert m.vectorized_func(z1, z2, z3).flags.c_contiguous
+ assert m.vectorized_func(y1, y2, y3).flags.f_contiguous
+ assert m.vectorized_func(z1, 1, 1).flags.c_contiguous
+ assert m.vectorized_func(1, y2, 1).flags.f_contiguous
+ assert m.vectorized_func(z1[1::4, 1::4], y2, 1).flags.f_contiguous
+ assert m.vectorized_func(y1[1::4, 1::4], z2, 1).flags.c_contiguous
+
+
+def test_passthrough_arguments(doc):
+ assert doc(m.vec_passthrough) == (
+ "vec_passthrough(" + ", ".join([
+ "arg0: float",
+ "arg1: numpy.ndarray[float64]",
+ "arg2: numpy.ndarray[float64]",
+ "arg3: numpy.ndarray[int32]",
+ "arg4: int",
+ "arg5: m.numpy_vectorize.NonPODClass",
+ "arg6: numpy.ndarray[float64]"]) + ") -> object")
+
+ b = np.array([[10, 20, 30]], dtype='float64')
+ c = np.array([100, 200]) # NOT a vectorized argument
+ d = np.array([[1000], [2000], [3000]], dtype='int')
+ g = np.array([[1000000, 2000000, 3000000]], dtype='int') # requires casting
+ assert np.all(
+ m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g) ==
+ np.array([[1111111, 2111121, 3111131],
+ [1112111, 2112121, 3112131],
+ [1113111, 2113121, 3113131]]))
+
+
+def test_method_vectorization():
+ o = m.VectorizeTestClass(3)
+ x = np.array([1, 2], dtype='int')
+ y = np.array([[10], [20]], dtype='float32')
+ assert np.all(o.method(x, y) == [[14, 15], [24, 25]])
+
+
+def test_array_collapse():
+ assert not isinstance(m.vectorized_func(1, 2, 3), np.ndarray)
+ assert not isinstance(m.vectorized_func(np.array(1), 2, 3), np.ndarray)
+ z = m.vectorized_func([1], 2, 3)
+ assert isinstance(z, np.ndarray)
+ assert z.shape == (1, )
+ z = m.vectorized_func(1, [[[2]]], 3)
+ assert isinstance(z, np.ndarray)
+ assert z.shape == (1, 1, 1)
diff --git a/3rdparty/pybind11/tests/test_opaque_types.cpp b/3rdparty/pybind11/tests/test_opaque_types.cpp
new file mode 100644
index 00000000..0d20d9a0
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_opaque_types.cpp
@@ -0,0 +1,67 @@
+/*
+ tests/test_opaque_types.cpp -- opaque types, passing void pointers
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include <pybind11/stl.h>
+#include <vector>
+
+// IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures
+//
+// This also deliberately doesn't use the below StringList type alias to test
+// that MAKE_OPAQUE can handle a type containing a `,`. (The `std::allocator`
+// bit is just the default `std::vector` allocator).
+PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>);
+
+using StringList = std::vector<std::string, std::allocator<std::string>>;
+
+TEST_SUBMODULE(opaque_types, m) {
+ // test_string_list
+ py::class_<StringList>(m, "StringList")
+ .def(py::init<>())
+ .def("pop_back", &StringList::pop_back)
+ /* There are multiple versions of push_back(), etc. Select the right ones. */
+ .def("push_back", (void (StringList::*)(const std::string &)) &StringList::push_back)
+ .def("back", (std::string &(StringList::*)()) &StringList::back)
+ .def("__len__", [](const StringList &v) { return v.size(); })
+ .def("__iter__", [](StringList &v) {
+ return py::make_iterator(v.begin(), v.end());
+ }, py::keep_alive<0, 1>());
+
+ class ClassWithSTLVecProperty {
+ public:
+ StringList stringList;
+ };
+ py::class_<ClassWithSTLVecProperty>(m, "ClassWithSTLVecProperty")
+ .def(py::init<>())
+ .def_readwrite("stringList", &ClassWithSTLVecProperty::stringList);
+
+ m.def("print_opaque_list", [](const StringList &l) {
+ std::string ret = "Opaque list: [";
+ bool first = true;
+ for (auto entry : l) {
+ if (!first)
+ ret += ", ";
+ ret += entry;
+ first = false;
+ }
+ return ret + "]";
+ });
+
+ // test_pointers
+ m.def("return_void_ptr", []() { return (void *) 0x1234; });
+ m.def("get_void_ptr_value", [](void *ptr) { return reinterpret_cast<std::intptr_t>(ptr); });
+ m.def("return_null_str", []() { return (char *) nullptr; });
+ m.def("get_null_str_value", [](char *ptr) { return reinterpret_cast<std::intptr_t>(ptr); });
+
+ m.def("return_unique_ptr", []() -> std::unique_ptr<StringList> {
+ StringList *result = new StringList();
+ result->push_back("some value");
+ return std::unique_ptr<StringList>(result);
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_opaque_types.py b/3rdparty/pybind11/tests/test_opaque_types.py
new file mode 100644
index 00000000..6b3802fd
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_opaque_types.py
@@ -0,0 +1,46 @@
+import pytest
+from pybind11_tests import opaque_types as m
+from pybind11_tests import ConstructorStats, UserType
+
+
+def test_string_list():
+ lst = m.StringList()
+ lst.push_back("Element 1")
+ lst.push_back("Element 2")
+ assert m.print_opaque_list(lst) == "Opaque list: [Element 1, Element 2]"
+ assert lst.back() == "Element 2"
+
+ for i, k in enumerate(lst, start=1):
+ assert k == "Element {}".format(i)
+ lst.pop_back()
+ assert m.print_opaque_list(lst) == "Opaque list: [Element 1]"
+
+ cvp = m.ClassWithSTLVecProperty()
+ assert m.print_opaque_list(cvp.stringList) == "Opaque list: []"
+
+ cvp.stringList = lst
+ cvp.stringList.push_back("Element 3")
+ assert m.print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]"
+
+
+def test_pointers(msg):
+ living_before = ConstructorStats.get(UserType).alive()
+ assert m.get_void_ptr_value(m.return_void_ptr()) == 0x1234
+ assert m.get_void_ptr_value(UserType()) # Should also work for other C++ types
+ assert ConstructorStats.get(UserType).alive() == living_before
+
+ with pytest.raises(TypeError) as excinfo:
+ m.get_void_ptr_value([1, 2, 3]) # This should not work
+ assert msg(excinfo.value) == """
+ get_void_ptr_value(): incompatible function arguments. The following argument types are supported:
+ 1. (arg0: capsule) -> int
+
+ Invoked with: [1, 2, 3]
+ """ # noqa: E501 line too long
+
+ assert m.return_null_str() is None
+ assert m.get_null_str_value(m.return_null_str()) is not None
+
+ ptr = m.return_unique_ptr()
+ assert "StringList" in repr(ptr)
+ assert m.print_opaque_list(ptr) == "Opaque list: [some value]"
diff --git a/3rdparty/pybind11/tests/test_operator_overloading.cpp b/3rdparty/pybind11/tests/test_operator_overloading.cpp
new file mode 100644
index 00000000..7b111704
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_operator_overloading.cpp
@@ -0,0 +1,171 @@
+/*
+ tests/test_operator_overloading.cpp -- operator overloading
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/operators.h>
+#include <functional>
+
+class Vector2 {
+public:
+ Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); }
+ Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); }
+ Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; }
+ Vector2 &operator=(const Vector2 &v) { x = v.x; y = v.y; print_copy_assigned(this); return *this; }
+ Vector2 &operator=(Vector2 &&v) { x = v.x; y = v.y; v.x = v.y = 0; print_move_assigned(this); return *this; }
+ ~Vector2() { print_destroyed(this); }
+
+ std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; }
+
+ Vector2 operator-() const { return Vector2(-x, -y); }
+ Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); }
+ Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); }
+ Vector2 operator-(float value) const { return Vector2(x - value, y - value); }
+ Vector2 operator+(float value) const { return Vector2(x + value, y + value); }
+ Vector2 operator*(float value) const { return Vector2(x * value, y * value); }
+ Vector2 operator/(float value) const { return Vector2(x / value, y / value); }
+ Vector2 operator*(const Vector2 &v) const { return Vector2(x * v.x, y * v.y); }
+ Vector2 operator/(const Vector2 &v) const { return Vector2(x / v.x, y / v.y); }
+ Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; }
+ Vector2& operator-=(const Vector2 &v) { x -= v.x; y -= v.y; return *this; }
+ Vector2& operator*=(float v) { x *= v; y *= v; return *this; }
+ Vector2& operator/=(float v) { x /= v; y /= v; return *this; }
+ Vector2& operator*=(const Vector2 &v) { x *= v.x; y *= v.y; return *this; }
+ Vector2& operator/=(const Vector2 &v) { x /= v.x; y /= v.y; return *this; }
+
+ friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); }
+ friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); }
+ friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); }
+ friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); }
+private:
+ float x, y;
+};
+
+class C1 { };
+class C2 { };
+
+int operator+(const C1 &, const C1 &) { return 11; }
+int operator+(const C2 &, const C2 &) { return 22; }
+int operator+(const C2 &, const C1 &) { return 21; }
+int operator+(const C1 &, const C2 &) { return 12; }
+
+namespace std {
+ template<>
+ struct hash<Vector2> {
+ // Not a good hash function, but easy to test
+ size_t operator()(const Vector2 &) { return 4; }
+ };
+}
+
+// MSVC warns about unknown pragmas, and warnings are errors.
+#ifndef _MSC_VER
+ #pragma GCC diagnostic push
+ // clang 7.0.0 and Apple LLVM 10.0.1 introduce `-Wself-assign-overloaded` to
+ // `-Wall`, which is used here for overloading (e.g. `py::self += py::self `).
+ // Here, we suppress the warning using `#pragma diagnostic`.
+ // Taken from: https://github.com/RobotLocomotion/drake/commit/aaf84b46
+ // TODO(eric): This could be resolved using a function / functor (e.g. `py::self()`).
+ #if (__APPLE__) && (__clang__)
+ #if (__clang_major__ >= 10) && (__clang_minor__ >= 0) && (__clang_patchlevel__ >= 1)
+ #pragma GCC diagnostic ignored "-Wself-assign-overloaded"
+ #endif
+ #elif (__clang__)
+ #if (__clang_major__ >= 7)
+ #pragma GCC diagnostic ignored "-Wself-assign-overloaded"
+ #endif
+ #endif
+#endif
+
+TEST_SUBMODULE(operators, m) {
+
+ // test_operator_overloading
+ py::class_<Vector2>(m, "Vector2")
+ .def(py::init<float, float>())
+ .def(py::self + py::self)
+ .def(py::self + float())
+ .def(py::self - py::self)
+ .def(py::self - float())
+ .def(py::self * float())
+ .def(py::self / float())
+ .def(py::self * py::self)
+ .def(py::self / py::self)
+ .def(py::self += py::self)
+ .def(py::self -= py::self)
+ .def(py::self *= float())
+ .def(py::self /= float())
+ .def(py::self *= py::self)
+ .def(py::self /= py::self)
+ .def(float() + py::self)
+ .def(float() - py::self)
+ .def(float() * py::self)
+ .def(float() / py::self)
+ .def(-py::self)
+ .def("__str__", &Vector2::toString)
+ .def(hash(py::self))
+ ;
+
+ m.attr("Vector") = m.attr("Vector2");
+
+ // test_operators_notimplemented
+ // #393: need to return NotSupported to ensure correct arithmetic operator behavior
+ py::class_<C1>(m, "C1")
+ .def(py::init<>())
+ .def(py::self + py::self);
+
+ py::class_<C2>(m, "C2")
+ .def(py::init<>())
+ .def(py::self + py::self)
+ .def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; })
+ .def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; });
+
+ // test_nested
+ // #328: first member in a class can't be used in operators
+ struct NestABase { int value = -2; };
+ py::class_<NestABase>(m, "NestABase")
+ .def(py::init<>())
+ .def_readwrite("value", &NestABase::value);
+
+ struct NestA : NestABase {
+ int value = 3;
+ NestA& operator+=(int i) { value += i; return *this; }
+ };
+ py::class_<NestA>(m, "NestA")
+ .def(py::init<>())
+ .def(py::self += int())
+ .def("as_base", [](NestA &a) -> NestABase& {
+ return (NestABase&) a;
+ }, py::return_value_policy::reference_internal);
+ m.def("get_NestA", [](const NestA &a) { return a.value; });
+
+ struct NestB {
+ NestA a;
+ int value = 4;
+ NestB& operator-=(int i) { value -= i; return *this; }
+ };
+ py::class_<NestB>(m, "NestB")
+ .def(py::init<>())
+ .def(py::self -= int())
+ .def_readwrite("a", &NestB::a);
+ m.def("get_NestB", [](const NestB &b) { return b.value; });
+
+ struct NestC {
+ NestB b;
+ int value = 5;
+ NestC& operator*=(int i) { value *= i; return *this; }
+ };
+ py::class_<NestC>(m, "NestC")
+ .def(py::init<>())
+ .def(py::self *= int())
+ .def_readwrite("b", &NestC::b);
+ m.def("get_NestC", [](const NestC &c) { return c.value; });
+}
+
+#ifndef _MSC_VER
+ #pragma GCC diagnostic pop
+#endif
diff --git a/3rdparty/pybind11/tests/test_operator_overloading.py b/3rdparty/pybind11/tests/test_operator_overloading.py
new file mode 100644
index 00000000..bd36ac2a
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_operator_overloading.py
@@ -0,0 +1,108 @@
+import pytest
+from pybind11_tests import operators as m
+from pybind11_tests import ConstructorStats
+
+
+def test_operator_overloading():
+ v1 = m.Vector2(1, 2)
+ v2 = m.Vector(3, -1)
+ assert str(v1) == "[1.000000, 2.000000]"
+ assert str(v2) == "[3.000000, -1.000000]"
+
+ assert str(-v2) == "[-3.000000, 1.000000]"
+
+ assert str(v1 + v2) == "[4.000000, 1.000000]"
+ assert str(v1 - v2) == "[-2.000000, 3.000000]"
+ assert str(v1 - 8) == "[-7.000000, -6.000000]"
+ assert str(v1 + 8) == "[9.000000, 10.000000]"
+ assert str(v1 * 8) == "[8.000000, 16.000000]"
+ assert str(v1 / 8) == "[0.125000, 0.250000]"
+ assert str(8 - v1) == "[7.000000, 6.000000]"
+ assert str(8 + v1) == "[9.000000, 10.000000]"
+ assert str(8 * v1) == "[8.000000, 16.000000]"
+ assert str(8 / v1) == "[8.000000, 4.000000]"
+ assert str(v1 * v2) == "[3.000000, -2.000000]"
+ assert str(v2 / v1) == "[3.000000, -0.500000]"
+
+ v1 += 2 * v2
+ assert str(v1) == "[7.000000, 0.000000]"
+ v1 -= v2
+ assert str(v1) == "[4.000000, 1.000000]"
+ v1 *= 2
+ assert str(v1) == "[8.000000, 2.000000]"
+ v1 /= 16
+ assert str(v1) == "[0.500000, 0.125000]"
+ v1 *= v2
+ assert str(v1) == "[1.500000, -0.125000]"
+ v2 /= v1
+ assert str(v2) == "[2.000000, 8.000000]"
+
+ assert hash(v1) == 4
+
+ cstats = ConstructorStats.get(m.Vector2)
+ assert cstats.alive() == 2
+ del v1
+ assert cstats.alive() == 1
+ del v2
+ assert cstats.alive() == 0
+ assert cstats.values() == ['[1.000000, 2.000000]', '[3.000000, -1.000000]',
+ '[-3.000000, 1.000000]', '[4.000000, 1.000000]',
+ '[-2.000000, 3.000000]', '[-7.000000, -6.000000]',
+ '[9.000000, 10.000000]', '[8.000000, 16.000000]',
+ '[0.125000, 0.250000]', '[7.000000, 6.000000]',
+ '[9.000000, 10.000000]', '[8.000000, 16.000000]',
+ '[8.000000, 4.000000]', '[3.000000, -2.000000]',
+ '[3.000000, -0.500000]', '[6.000000, -2.000000]']
+ assert cstats.default_constructions == 0
+ assert cstats.copy_constructions == 0
+ assert cstats.move_constructions >= 10
+ assert cstats.copy_assignments == 0
+ assert cstats.move_assignments == 0
+
+
+def test_operators_notimplemented():
+ """#393: need to return NotSupported to ensure correct arithmetic operator behavior"""
+
+ c1, c2 = m.C1(), m.C2()
+ assert c1 + c1 == 11
+ assert c2 + c2 == 22
+ assert c2 + c1 == 21
+ assert c1 + c2 == 12
+
+
+def test_nested():
+ """#328: first member in a class can't be used in operators"""
+
+ a = m.NestA()
+ b = m.NestB()
+ c = m.NestC()
+
+ a += 10
+ assert m.get_NestA(a) == 13
+ b.a += 100
+ assert m.get_NestA(b.a) == 103
+ c.b.a += 1000
+ assert m.get_NestA(c.b.a) == 1003
+ b -= 1
+ assert m.get_NestB(b) == 3
+ c.b -= 3
+ assert m.get_NestB(c.b) == 1
+ c *= 7
+ assert m.get_NestC(c) == 35
+
+ abase = a.as_base()
+ assert abase.value == -2
+ a.as_base().value += 44
+ assert abase.value == 42
+ assert c.b.a.as_base().value == -2
+ c.b.a.as_base().value += 44
+ assert c.b.a.as_base().value == 42
+
+ del c
+ pytest.gc_collect()
+ del a # Shouldn't delete while abase is still alive
+ pytest.gc_collect()
+
+ assert abase.value == 42
+ del abase, b
+ pytest.gc_collect()
diff --git a/3rdparty/pybind11/tests/test_pickling.cpp b/3rdparty/pybind11/tests/test_pickling.cpp
new file mode 100644
index 00000000..9dc63bda
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_pickling.cpp
@@ -0,0 +1,130 @@
+/*
+ tests/test_pickling.cpp -- pickle support
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+TEST_SUBMODULE(pickling, m) {
+ // test_roundtrip
+ class Pickleable {
+ public:
+ Pickleable(const std::string &value) : m_value(value) { }
+ const std::string &value() const { return m_value; }
+
+ void setExtra1(int extra1) { m_extra1 = extra1; }
+ void setExtra2(int extra2) { m_extra2 = extra2; }
+ int extra1() const { return m_extra1; }
+ int extra2() const { return m_extra2; }
+ private:
+ std::string m_value;
+ int m_extra1 = 0;
+ int m_extra2 = 0;
+ };
+
+ class PickleableNew : public Pickleable {
+ public:
+ using Pickleable::Pickleable;
+ };
+
+ py::class_<Pickleable>(m, "Pickleable")
+ .def(py::init<std::string>())
+ .def("value", &Pickleable::value)
+ .def("extra1", &Pickleable::extra1)
+ .def("extra2", &Pickleable::extra2)
+ .def("setExtra1", &Pickleable::setExtra1)
+ .def("setExtra2", &Pickleable::setExtra2)
+ // For details on the methods below, refer to
+ // http://docs.python.org/3/library/pickle.html#pickling-class-instances
+ .def("__getstate__", [](const Pickleable &p) {
+ /* Return a tuple that fully encodes the state of the object */
+ return py::make_tuple(p.value(), p.extra1(), p.extra2());
+ })
+ .def("__setstate__", [](Pickleable &p, py::tuple t) {
+ if (t.size() != 3)
+ throw std::runtime_error("Invalid state!");
+ /* Invoke the constructor (need to use in-place version) */
+ new (&p) Pickleable(t[0].cast<std::string>());
+
+ /* Assign any additional state */
+ p.setExtra1(t[1].cast<int>());
+ p.setExtra2(t[2].cast<int>());
+ });
+
+ py::class_<PickleableNew, Pickleable>(m, "PickleableNew")
+ .def(py::init<std::string>())
+ .def(py::pickle(
+ [](const PickleableNew &p) {
+ return py::make_tuple(p.value(), p.extra1(), p.extra2());
+ },
+ [](py::tuple t) {
+ if (t.size() != 3)
+ throw std::runtime_error("Invalid state!");
+ auto p = PickleableNew(t[0].cast<std::string>());
+
+ p.setExtra1(t[1].cast<int>());
+ p.setExtra2(t[2].cast<int>());
+ return p;
+ }
+ ));
+
+#if !defined(PYPY_VERSION)
+ // test_roundtrip_with_dict
+ class PickleableWithDict {
+ public:
+ PickleableWithDict(const std::string &value) : value(value) { }
+
+ std::string value;
+ int extra;
+ };
+
+ class PickleableWithDictNew : public PickleableWithDict {
+ public:
+ using PickleableWithDict::PickleableWithDict;
+ };
+
+ py::class_<PickleableWithDict>(m, "PickleableWithDict", py::dynamic_attr())
+ .def(py::init<std::string>())
+ .def_readwrite("value", &PickleableWithDict::value)
+ .def_readwrite("extra", &PickleableWithDict::extra)
+ .def("__getstate__", [](py::object self) {
+ /* Also include __dict__ in state */
+ return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__"));
+ })
+ .def("__setstate__", [](py::object self, py::tuple t) {
+ if (t.size() != 3)
+ throw std::runtime_error("Invalid state!");
+ /* Cast and construct */
+ auto& p = self.cast<PickleableWithDict&>();
+ new (&p) PickleableWithDict(t[0].cast<std::string>());
+
+ /* Assign C++ state */
+ p.extra = t[1].cast<int>();
+
+ /* Assign Python state */
+ self.attr("__dict__") = t[2];
+ });
+
+ py::class_<PickleableWithDictNew, PickleableWithDict>(m, "PickleableWithDictNew")
+ .def(py::init<std::string>())
+ .def(py::pickle(
+ [](py::object self) {
+ return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__"));
+ },
+ [](const py::tuple &t) {
+ if (t.size() != 3)
+ throw std::runtime_error("Invalid state!");
+
+ auto cpp_state = PickleableWithDictNew(t[0].cast<std::string>());
+ cpp_state.extra = t[1].cast<int>();
+
+ auto py_state = t[2].cast<py::dict>();
+ return std::make_pair(cpp_state, py_state);
+ }
+ ));
+#endif
+}
diff --git a/3rdparty/pybind11/tests/test_pickling.py b/3rdparty/pybind11/tests/test_pickling.py
new file mode 100644
index 00000000..5ae05aaa
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_pickling.py
@@ -0,0 +1,42 @@
+import pytest
+from pybind11_tests import pickling as m
+
+try:
+ import cPickle as pickle # Use cPickle on Python 2.7
+except ImportError:
+ import pickle
+
+
+@pytest.mark.parametrize("cls_name", ["Pickleable", "PickleableNew"])
+def test_roundtrip(cls_name):
+ cls = getattr(m, cls_name)
+ p = cls("test_value")
+ p.setExtra1(15)
+ p.setExtra2(48)
+
+ data = pickle.dumps(p, 2) # Must use pickle protocol >= 2
+ p2 = pickle.loads(data)
+ assert p2.value() == p.value()
+ assert p2.extra1() == p.extra1()
+ assert p2.extra2() == p.extra2()
+
+
+@pytest.unsupported_on_pypy
+@pytest.mark.parametrize("cls_name", ["PickleableWithDict", "PickleableWithDictNew"])
+def test_roundtrip_with_dict(cls_name):
+ cls = getattr(m, cls_name)
+ p = cls("test_value")
+ p.extra = 15
+ p.dynamic = "Attribute"
+
+ data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL)
+ p2 = pickle.loads(data)
+ assert p2.value == p.value
+ assert p2.extra == p.extra
+ assert p2.dynamic == p.dynamic
+
+
+def test_enum_pickle():
+ from pybind11_tests import enums as e
+ data = pickle.dumps(e.EOne, 2)
+ assert e.EOne == pickle.loads(data)
diff --git a/3rdparty/pybind11/tests/test_pytypes.cpp b/3rdparty/pybind11/tests/test_pytypes.cpp
new file mode 100644
index 00000000..244e1db0
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_pytypes.cpp
@@ -0,0 +1,310 @@
+/*
+ tests/test_pytypes.cpp -- Python type casters
+
+ Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+
+TEST_SUBMODULE(pytypes, m) {
+ // test_list
+ m.def("get_list", []() {
+ py::list list;
+ list.append("value");
+ py::print("Entry at position 0:", list[0]);
+ list[0] = py::str("overwritten");
+ list.insert(0, "inserted-0");
+ list.insert(2, "inserted-2");
+ return list;
+ });
+ m.def("print_list", [](py::list list) {
+ int index = 0;
+ for (auto item : list)
+ py::print("list item {}: {}"_s.format(index++, item));
+ });
+
+ // test_set
+ m.def("get_set", []() {
+ py::set set;
+ set.add(py::str("key1"));
+ set.add("key2");
+ set.add(std::string("key3"));
+ return set;
+ });
+ m.def("print_set", [](py::set set) {
+ for (auto item : set)
+ py::print("key:", item);
+ });
+ m.def("set_contains", [](py::set set, py::object key) {
+ return set.contains(key);
+ });
+ m.def("set_contains", [](py::set set, const char* key) {
+ return set.contains(key);
+ });
+
+ // test_dict
+ m.def("get_dict", []() { return py::dict("key"_a="value"); });
+ m.def("print_dict", [](py::dict dict) {
+ for (auto item : dict)
+ py::print("key: {}, value={}"_s.format(item.first, item.second));
+ });
+ m.def("dict_keyword_constructor", []() {
+ auto d1 = py::dict("x"_a=1, "y"_a=2);
+ auto d2 = py::dict("z"_a=3, **d1);
+ return d2;
+ });
+ m.def("dict_contains", [](py::dict dict, py::object val) {
+ return dict.contains(val);
+ });
+ m.def("dict_contains", [](py::dict dict, const char* val) {
+ return dict.contains(val);
+ });
+
+ // test_str
+ m.def("str_from_string", []() { return py::str(std::string("baz")); });
+ m.def("str_from_bytes", []() { return py::str(py::bytes("boo", 3)); });
+ m.def("str_from_object", [](const py::object& obj) { return py::str(obj); });
+ m.def("repr_from_object", [](const py::object& obj) { return py::repr(obj); });
+
+ m.def("str_format", []() {
+ auto s1 = "{} + {} = {}"_s.format(1, 2, 3);
+ auto s2 = "{a} + {b} = {c}"_s.format("a"_a=1, "b"_a=2, "c"_a=3);
+ return py::make_tuple(s1, s2);
+ });
+
+ // test_bytes
+ m.def("bytes_from_string", []() { return py::bytes(std::string("foo")); });
+ m.def("bytes_from_str", []() { return py::bytes(py::str("bar", 3)); });
+
+ // test_capsule
+ m.def("return_capsule_with_destructor", []() {
+ py::print("creating capsule");
+ return py::capsule([]() {
+ py::print("destructing capsule");
+ });
+ });
+
+ m.def("return_capsule_with_destructor_2", []() {
+ py::print("creating capsule");
+ return py::capsule((void *) 1234, [](void *ptr) {
+ py::print("destructing capsule: {}"_s.format((size_t) ptr));
+ });
+ });
+
+ m.def("return_capsule_with_name_and_destructor", []() {
+ auto capsule = py::capsule((void *) 1234, "pointer type description", [](PyObject *ptr) {
+ if (ptr) {
+ auto name = PyCapsule_GetName(ptr);
+ py::print("destructing capsule ({}, '{}')"_s.format(
+ (size_t) PyCapsule_GetPointer(ptr, name), name
+ ));
+ }
+ });
+ void *contents = capsule;
+ py::print("created capsule ({}, '{}')"_s.format((size_t) contents, capsule.name()));
+ return capsule;
+ });
+
+ // test_accessors
+ m.def("accessor_api", [](py::object o) {
+ auto d = py::dict();
+
+ d["basic_attr"] = o.attr("basic_attr");
+
+ auto l = py::list();
+ for (const auto &item : o.attr("begin_end")) {
+ l.append(item);
+ }
+ d["begin_end"] = l;
+
+ d["operator[object]"] = o.attr("d")["operator[object]"_s];
+ d["operator[char *]"] = o.attr("d")["operator[char *]"];
+
+ d["attr(object)"] = o.attr("sub").attr("attr_obj");
+ d["attr(char *)"] = o.attr("sub").attr("attr_char");
+ try {
+ o.attr("sub").attr("missing").ptr();
+ } catch (const py::error_already_set &) {
+ d["missing_attr_ptr"] = "raised"_s;
+ }
+ try {
+ o.attr("missing").attr("doesn't matter");
+ } catch (const py::error_already_set &) {
+ d["missing_attr_chain"] = "raised"_s;
+ }
+
+ d["is_none"] = o.attr("basic_attr").is_none();
+
+ d["operator()"] = o.attr("func")(1);
+ d["operator*"] = o.attr("func")(*o.attr("begin_end"));
+
+ // Test implicit conversion
+ py::list implicit_list = o.attr("begin_end");
+ d["implicit_list"] = implicit_list;
+ py::dict implicit_dict = o.attr("__dict__");
+ d["implicit_dict"] = implicit_dict;
+
+ return d;
+ });
+
+ m.def("tuple_accessor", [](py::tuple existing_t) {
+ try {
+ existing_t[0] = 1;
+ } catch (const py::error_already_set &) {
+ // --> Python system error
+ // Only new tuples (refcount == 1) are mutable
+ auto new_t = py::tuple(3);
+ for (size_t i = 0; i < new_t.size(); ++i) {
+ new_t[i] = i;
+ }
+ return new_t;
+ }
+ return py::tuple();
+ });
+
+ m.def("accessor_assignment", []() {
+ auto l = py::list(1);
+ l[0] = 0;
+
+ auto d = py::dict();
+ d["get"] = l[0];
+ auto var = l[0];
+ d["deferred_get"] = var;
+ l[0] = 1;
+ d["set"] = l[0];
+ var = 99; // this assignment should not overwrite l[0]
+ d["deferred_set"] = l[0];
+ d["var"] = var;
+
+ return d;
+ });
+
+ // test_constructors
+ m.def("default_constructors", []() {
+ return py::dict(
+ "str"_a=py::str(),
+ "bool"_a=py::bool_(),
+ "int"_a=py::int_(),
+ "float"_a=py::float_(),
+ "tuple"_a=py::tuple(),
+ "list"_a=py::list(),
+ "dict"_a=py::dict(),
+ "set"_a=py::set()
+ );
+ });
+
+ m.def("converting_constructors", [](py::dict d) {
+ return py::dict(
+ "str"_a=py::str(d["str"]),
+ "bool"_a=py::bool_(d["bool"]),
+ "int"_a=py::int_(d["int"]),
+ "float"_a=py::float_(d["float"]),
+ "tuple"_a=py::tuple(d["tuple"]),
+ "list"_a=py::list(d["list"]),
+ "dict"_a=py::dict(d["dict"]),
+ "set"_a=py::set(d["set"]),
+ "memoryview"_a=py::memoryview(d["memoryview"])
+ );
+ });
+
+ m.def("cast_functions", [](py::dict d) {
+ // When converting between Python types, obj.cast<T>() should be the same as T(obj)
+ return py::dict(
+ "str"_a=d["str"].cast<py::str>(),
+ "bool"_a=d["bool"].cast<py::bool_>(),
+ "int"_a=d["int"].cast<py::int_>(),
+ "float"_a=d["float"].cast<py::float_>(),
+ "tuple"_a=d["tuple"].cast<py::tuple>(),
+ "list"_a=d["list"].cast<py::list>(),
+ "dict"_a=d["dict"].cast<py::dict>(),
+ "set"_a=d["set"].cast<py::set>(),
+ "memoryview"_a=d["memoryview"].cast<py::memoryview>()
+ );
+ });
+
+ m.def("get_implicit_casting", []() {
+ py::dict d;
+ d["char*_i1"] = "abc";
+ const char *c2 = "abc";
+ d["char*_i2"] = c2;
+ d["char*_e"] = py::cast(c2);
+ d["char*_p"] = py::str(c2);
+
+ d["int_i1"] = 42;
+ int i = 42;
+ d["int_i2"] = i;
+ i++;
+ d["int_e"] = py::cast(i);
+ i++;
+ d["int_p"] = py::int_(i);
+
+ d["str_i1"] = std::string("str");
+ std::string s2("str1");
+ d["str_i2"] = s2;
+ s2[3] = '2';
+ d["str_e"] = py::cast(s2);
+ s2[3] = '3';
+ d["str_p"] = py::str(s2);
+
+ py::list l(2);
+ l[0] = 3;
+ l[1] = py::cast(6);
+ l.append(9);
+ l.append(py::cast(12));
+ l.append(py::int_(15));
+
+ return py::dict(
+ "d"_a=d,
+ "l"_a=l
+ );
+ });
+
+ // test_print
+ m.def("print_function", []() {
+ py::print("Hello, World!");
+ py::print(1, 2.0, "three", true, std::string("-- multiple args"));
+ auto args = py::make_tuple("and", "a", "custom", "separator");
+ py::print("*args", *args, "sep"_a="-");
+ py::print("no new line here", "end"_a=" -- ");
+ py::print("next print");
+
+ auto py_stderr = py::module::import("sys").attr("stderr");
+ py::print("this goes to stderr", "file"_a=py_stderr);
+
+ py::print("flush", "flush"_a=true);
+
+ py::print("{a} + {b} = {c}"_s.format("a"_a="py::print", "b"_a="str.format", "c"_a="this"));
+ });
+
+ m.def("print_failure", []() { py::print(42, UnregisteredType()); });
+
+ m.def("hash_function", [](py::object obj) { return py::hash(obj); });
+
+ m.def("test_number_protocol", [](py::object a, py::object b) {
+ py::list l;
+ l.append(a.equal(b));
+ l.append(a.not_equal(b));
+ l.append(a < b);
+ l.append(a <= b);
+ l.append(a > b);
+ l.append(a >= b);
+ l.append(a + b);
+ l.append(a - b);
+ l.append(a * b);
+ l.append(a / b);
+ l.append(a | b);
+ l.append(a & b);
+ l.append(a ^ b);
+ l.append(a >> b);
+ l.append(a << b);
+ return l;
+ });
+
+ m.def("test_list_slicing", [](py::list a) {
+ return a[py::slice(0, -1, 2)];
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_pytypes.py b/3rdparty/pybind11/tests/test_pytypes.py
new file mode 100644
index 00000000..0e8d6c33
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_pytypes.py
@@ -0,0 +1,263 @@
+from __future__ import division
+import pytest
+import sys
+
+from pybind11_tests import pytypes as m
+from pybind11_tests import debug_enabled
+
+
+def test_list(capture, doc):
+ with capture:
+ lst = m.get_list()
+ assert lst == ["inserted-0", "overwritten", "inserted-2"]
+
+ lst.append("value2")
+ m.print_list(lst)
+ 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_set(capture, doc):
+ s = m.get_set()
+ assert s == {"key1", "key2", "key3"}
+
+ with capture:
+ s.add("key4")
+ m.print_set(s)
+ assert capture.unordered == """
+ key: key1
+ key: key2
+ key: key3
+ key: key4
+ """
+
+ assert not m.set_contains(set([]), 42)
+ assert m.set_contains({42}, 42)
+ assert m.set_contains({"foo"}, "foo")
+
+ assert doc(m.get_list) == "get_list() -> list"
+ assert doc(m.print_list) == "print_list(arg0: list) -> None"
+
+
+def test_dict(capture, doc):
+ d = m.get_dict()
+ assert d == {"key": "value"}
+
+ with capture:
+ d["key2"] = "value2"
+ m.print_dict(d)
+ assert capture.unordered == """
+ key: key, value=value
+ key: key2, value=value2
+ """
+
+ assert not m.dict_contains({}, 42)
+ assert m.dict_contains({42: None}, 42)
+ assert m.dict_contains({"foo": None}, "foo")
+
+ assert doc(m.get_dict) == "get_dict() -> dict"
+ assert doc(m.print_dict) == "print_dict(arg0: dict) -> None"
+
+ assert m.dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3}
+
+
+def test_str(doc):
+ 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):
+ def __str__(self):
+ return "this is a str"
+
+ def __repr__(self):
+ return "this is a repr"
+
+ assert m.str_from_object(A()) == "this is a str"
+ assert m.repr_from_object(A()) == "this is a repr"
+
+ s1, s2 = m.str_format()
+ assert s1 == "1 + 2 = 3"
+ assert s1 == s2
+
+
+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"
+ )
+
+
+def test_capsule(capture):
+ pytest.gc_collect()
+ with capture:
+ a = m.return_capsule_with_destructor()
+ del a
+ pytest.gc_collect()
+ assert capture.unordered == """
+ creating capsule
+ destructing capsule
+ """
+
+ with capture:
+ a = m.return_capsule_with_destructor_2()
+ del a
+ pytest.gc_collect()
+ 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 == """
+ created capsule (1234, 'pointer type description')
+ destructing capsule (1234, 'pointer type description')
+ """
+
+
+def test_accessors():
+ class SubTestObject:
+ attr_obj = 1
+ attr_char = 2
+
+ class TestObject:
+ basic_attr = 1
+ begin_end = [1, 2, 3]
+ d = {"operator[object]": 1, "operator[char *]": 2}
+ sub = SubTestObject()
+
+ def func(self, x, *args):
+ return self.basic_attr + x + sum(args)
+
+ d = m.accessor_api(TestObject())
+ assert d["basic_attr"] == 1
+ assert d["begin_end"] == [1, 2, 3]
+ assert d["operator[object]"] == 1
+ assert d["operator[char *]"] == 2
+ assert d["attr(object)"] == 1
+ assert d["attr(char *)"] == 2
+ assert d["missing_attr_ptr"] == "raised"
+ assert d["missing_attr_chain"] == "raised"
+ assert d["is_none"] is False
+ assert d["operator()"] == 2
+ assert d["operator*"] == 7
+ assert d["implicit_list"] == [1, 2, 3]
+ assert all(x in TestObject.__dict__ for x in d["implicit_dict"])
+
+ assert m.tuple_accessor(tuple()) == (0, 1, 2)
+
+ d = m.accessor_assignment()
+ assert d["get"] == 0
+ assert d["deferred_get"] == 0
+ assert d["set"] == 1
+ assert d["deferred_set"] == 1
+ assert d["var"] == 99
+
+
+def test_constructors():
+ """C++ default and converting constructors are equivalent to type calls in Python"""
+ types = [str, bool, int, float, tuple, list, dict, set]
+ expected = {t.__name__: t() for t in types}
+ assert m.default_constructors() == expected
+
+ data = {
+ str: 42,
+ bool: "Not empty",
+ int: "42",
+ float: "+1e3",
+ tuple: range(3),
+ list: range(3),
+ dict: [("two", 2), ("one", 1), ("three", 3)],
+ set: [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()}
+
+ assert m.converting_constructors(inputs) == expected
+ assert m.cast_functions(inputs) == expected
+
+ # Converting constructors and cast functions should just reference rather
+ # than copy when no conversion is needed:
+ noconv1 = m.converting_constructors(expected)
+ for k in noconv1:
+ assert noconv1[k] is expected[k]
+
+ noconv2 = m.cast_functions(expected)
+ for k in noconv2:
+ assert noconv2[k] is expected[k]
+
+
+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['l'] == [3, 6, 9, 12, 15]
+
+
+def test_print(capture):
+ with capture:
+ m.print_function()
+ assert capture == """
+ Hello, World!
+ 1 2.0 three True -- multiple args
+ *args-and-a-custom-separator
+ no new line here -- next print
+ 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)"
+ )
+
+
+def test_hash():
+ class Hashable(object):
+ def __init__(self, value):
+ self.value = value
+
+ def __hash__(self):
+ return self.value
+
+ class Unhashable(object):
+ __hash__ = None
+
+ assert m.hash_function(Hashable(42)) == 42
+ with pytest.raises(TypeError):
+ m.hash_function(Unhashable())
+
+
+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]
+ assert m.test_number_protocol(a, b) == li
+
+
+def test_list_slicing():
+ li = list(range(100))
+ assert li[::2] == m.test_list_slicing(li)
diff --git a/3rdparty/pybind11/tests/test_sequences_and_iterators.cpp b/3rdparty/pybind11/tests/test_sequences_and_iterators.cpp
new file mode 100644
index 00000000..87ccf99d
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_sequences_and_iterators.cpp
@@ -0,0 +1,353 @@
+/*
+ tests/test_sequences_and_iterators.cpp -- supporting Pythons' sequence protocol, iterators,
+ etc.
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/operators.h>
+#include <pybind11/stl.h>
+
+template<typename T>
+class NonZeroIterator {
+ const T* ptr_;
+public:
+ NonZeroIterator(const T* ptr) : ptr_(ptr) {}
+ const T& operator*() const { return *ptr_; }
+ NonZeroIterator& operator++() { ++ptr_; return *this; }
+};
+
+class NonZeroSentinel {};
+
+template<typename A, typename B>
+bool operator==(const NonZeroIterator<std::pair<A, B>>& it, const NonZeroSentinel&) {
+ return !(*it).first || !(*it).second;
+}
+
+template <typename PythonType>
+py::list test_random_access_iterator(PythonType x) {
+ if (x.size() < 5)
+ throw py::value_error("Please provide at least 5 elements for testing.");
+
+ auto checks = py::list();
+ auto assert_equal = [&checks](py::handle a, py::handle b) {
+ auto result = PyObject_RichCompareBool(a.ptr(), b.ptr(), Py_EQ);
+ if (result == -1) { throw py::error_already_set(); }
+ checks.append(result != 0);
+ };
+
+ auto it = x.begin();
+ assert_equal(x[0], *it);
+ assert_equal(x[0], it[0]);
+ assert_equal(x[1], it[1]);
+
+ assert_equal(x[1], *(++it));
+ assert_equal(x[1], *(it++));
+ assert_equal(x[2], *it);
+ assert_equal(x[3], *(it += 1));
+ assert_equal(x[2], *(--it));
+ assert_equal(x[2], *(it--));
+ assert_equal(x[1], *it);
+ assert_equal(x[0], *(it -= 1));
+
+ assert_equal(it->attr("real"), x[0].attr("real"));
+ assert_equal((it + 1)->attr("real"), x[1].attr("real"));
+
+ assert_equal(x[1], *(it + 1));
+ assert_equal(x[1], *(1 + it));
+ it += 3;
+ assert_equal(x[1], *(it - 2));
+
+ checks.append(static_cast<std::size_t>(x.end() - x.begin()) == x.size());
+ checks.append((x.begin() + static_cast<std::ptrdiff_t>(x.size())) == x.end());
+ checks.append(x.begin() < x.end());
+
+ return checks;
+}
+
+TEST_SUBMODULE(sequences_and_iterators, m) {
+ // test_sliceable
+ class Sliceable{
+ public:
+ Sliceable(int n): size(n) {}
+ int start,stop,step;
+ int size;
+ };
+ py::class_<Sliceable>(m,"Sliceable")
+ .def(py::init<int>())
+ .def("__getitem__",[](const Sliceable &s, py::slice slice) {
+ ssize_t start, stop, step, slicelength;
+ if (!slice.compute(s.size, &start, &stop, &step, &slicelength))
+ throw py::error_already_set();
+ int istart = static_cast<int>(start);
+ int istop = static_cast<int>(stop);
+ int istep = static_cast<int>(step);
+ return std::make_tuple(istart,istop,istep);
+ })
+ ;
+
+ // test_sequence
+ class Sequence {
+ public:
+ Sequence(size_t size) : m_size(size) {
+ print_created(this, "of size", m_size);
+ m_data = new float[size];
+ memset(m_data, 0, sizeof(float) * size);
+ }
+ Sequence(const std::vector<float> &value) : m_size(value.size()) {
+ print_created(this, "of size", m_size, "from std::vector");
+ m_data = new float[m_size];
+ memcpy(m_data, &value[0], sizeof(float) * m_size);
+ }
+ Sequence(const Sequence &s) : m_size(s.m_size) {
+ print_copy_created(this);
+ m_data = new float[m_size];
+ memcpy(m_data, s.m_data, sizeof(float)*m_size);
+ }
+ Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) {
+ print_move_created(this);
+ s.m_size = 0;
+ s.m_data = nullptr;
+ }
+
+ ~Sequence() { print_destroyed(this); delete[] m_data; }
+
+ Sequence &operator=(const Sequence &s) {
+ if (&s != this) {
+ delete[] m_data;
+ m_size = s.m_size;
+ m_data = new float[m_size];
+ memcpy(m_data, s.m_data, sizeof(float)*m_size);
+ }
+ print_copy_assigned(this);
+ return *this;
+ }
+
+ Sequence &operator=(Sequence &&s) {
+ if (&s != this) {
+ delete[] m_data;
+ m_size = s.m_size;
+ m_data = s.m_data;
+ s.m_size = 0;
+ s.m_data = nullptr;
+ }
+ print_move_assigned(this);
+ return *this;
+ }
+
+ bool operator==(const Sequence &s) const {
+ if (m_size != s.size()) return false;
+ for (size_t i = 0; i < m_size; ++i)
+ if (m_data[i] != s[i])
+ return false;
+ return true;
+ }
+ bool operator!=(const Sequence &s) const { return !operator==(s); }
+
+ float operator[](size_t index) const { return m_data[index]; }
+ float &operator[](size_t index) { return m_data[index]; }
+
+ bool contains(float v) const {
+ for (size_t i = 0; i < m_size; ++i)
+ if (v == m_data[i])
+ return true;
+ return false;
+ }
+
+ Sequence reversed() const {
+ Sequence result(m_size);
+ for (size_t i = 0; i < m_size; ++i)
+ result[m_size - i - 1] = m_data[i];
+ return result;
+ }
+
+ size_t size() const { return m_size; }
+
+ const float *begin() const { return m_data; }
+ const float *end() const { return m_data+m_size; }
+
+ private:
+ size_t m_size;
+ float *m_data;
+ };
+ py::class_<Sequence>(m, "Sequence")
+ .def(py::init<size_t>())
+ .def(py::init<const std::vector<float>&>())
+ /// Bare bones interface
+ .def("__getitem__", [](const Sequence &s, size_t i) {
+ if (i >= s.size()) throw py::index_error();
+ return s[i];
+ })
+ .def("__setitem__", [](Sequence &s, size_t i, float v) {
+ if (i >= s.size()) throw py::index_error();
+ s[i] = v;
+ })
+ .def("__len__", &Sequence::size)
+ /// Optional sequence protocol operations
+ .def("__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); },
+ py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */)
+ .def("__contains__", [](const Sequence &s, float v) { return s.contains(v); })
+ .def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); })
+ /// Slicing protocol (optional)
+ .def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* {
+ size_t start, stop, step, slicelength;
+ if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
+ throw py::error_already_set();
+ Sequence *seq = new Sequence(slicelength);
+ for (size_t i = 0; i < slicelength; ++i) {
+ (*seq)[i] = s[start]; start += step;
+ }
+ return seq;
+ })
+ .def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) {
+ size_t start, stop, step, slicelength;
+ if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
+ throw py::error_already_set();
+ if (slicelength != value.size())
+ throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
+ for (size_t i = 0; i < slicelength; ++i) {
+ s[start] = value[i]; start += step;
+ }
+ })
+ /// Comparisons
+ .def(py::self == py::self)
+ .def(py::self != py::self)
+ // Could also define py::self + py::self for concatenation, etc.
+ ;
+
+ // test_map_iterator
+ // Interface of a map-like object that isn't (directly) an unordered_map, but provides some basic
+ // map-like functionality.
+ class StringMap {
+ public:
+ StringMap() = default;
+ StringMap(std::unordered_map<std::string, std::string> init)
+ : map(std::move(init)) {}
+
+ void set(std::string key, std::string val) { map[key] = val; }
+ std::string get(std::string key) const { return map.at(key); }
+ size_t size() const { return map.size(); }
+ private:
+ std::unordered_map<std::string, std::string> map;
+ public:
+ decltype(map.cbegin()) begin() const { return map.cbegin(); }
+ decltype(map.cend()) end() const { return map.cend(); }
+ };
+ py::class_<StringMap>(m, "StringMap")
+ .def(py::init<>())
+ .def(py::init<std::unordered_map<std::string, std::string>>())
+ .def("__getitem__", [](const StringMap &map, std::string key) {
+ try { return map.get(key); }
+ catch (const std::out_of_range&) {
+ throw py::key_error("key '" + key + "' does not exist");
+ }
+ })
+ .def("__setitem__", &StringMap::set)
+ .def("__len__", &StringMap::size)
+ .def("__iter__", [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); },
+ py::keep_alive<0, 1>())
+ .def("items", [](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); },
+ py::keep_alive<0, 1>())
+ ;
+
+ // test_generalized_iterators
+ class IntPairs {
+ public:
+ IntPairs(std::vector<std::pair<int, int>> data) : data_(std::move(data)) {}
+ const std::pair<int, int>* begin() const { return data_.data(); }
+ private:
+ std::vector<std::pair<int, int>> data_;
+ };
+ py::class_<IntPairs>(m, "IntPairs")
+ .def(py::init<std::vector<std::pair<int, int>>>())
+ .def("nonzero", [](const IntPairs& s) {
+ return py::make_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel());
+ }, py::keep_alive<0, 1>())
+ .def("nonzero_keys", [](const IntPairs& s) {
+ return py::make_key_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel());
+ }, py::keep_alive<0, 1>())
+ ;
+
+
+#if 0
+ // Obsolete: special data structure for exposing custom iterator types to python
+ // kept here for illustrative purposes because there might be some use cases which
+ // are not covered by the much simpler py::make_iterator
+
+ struct PySequenceIterator {
+ PySequenceIterator(const Sequence &seq, py::object ref) : seq(seq), ref(ref) { }
+
+ float next() {
+ if (index == seq.size())
+ throw py::stop_iteration();
+ return seq[index++];
+ }
+
+ const Sequence &seq;
+ py::object ref; // keep a reference
+ size_t index = 0;
+ };
+
+ py::class_<PySequenceIterator>(seq, "Iterator")
+ .def("__iter__", [](PySequenceIterator &it) -> PySequenceIterator& { return it; })
+ .def("__next__", &PySequenceIterator::next);
+
+ On the actual Sequence object, the iterator would be constructed as follows:
+ .def("__iter__", [](py::object s) { return PySequenceIterator(s.cast<const Sequence &>(), s); })
+#endif
+
+ // test_python_iterator_in_cpp
+ m.def("object_to_list", [](py::object o) {
+ auto l = py::list();
+ for (auto item : o) {
+ l.append(item);
+ }
+ return l;
+ });
+
+ m.def("iterator_to_list", [](py::iterator it) {
+ auto l = py::list();
+ while (it != py::iterator::sentinel()) {
+ l.append(*it);
+ ++it;
+ }
+ return l;
+ });
+
+ // Make sure that py::iterator works with std algorithms
+ m.def("count_none", [](py::object o) {
+ return std::count_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); });
+ });
+
+ m.def("find_none", [](py::object o) {
+ auto it = std::find_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); });
+ return it->is_none();
+ });
+
+ m.def("count_nonzeros", [](py::dict d) {
+ return std::count_if(d.begin(), d.end(), [](std::pair<py::handle, py::handle> p) {
+ return p.second.cast<int>() != 0;
+ });
+ });
+
+ m.def("tuple_iterator", &test_random_access_iterator<py::tuple>);
+ m.def("list_iterator", &test_random_access_iterator<py::list>);
+ m.def("sequence_iterator", &test_random_access_iterator<py::sequence>);
+
+ // test_iterator_passthrough
+ // #181: iterator passthrough did not compile
+ m.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
+ return py::make_iterator(std::begin(s), std::end(s));
+ });
+
+ // test_iterator_rvp
+ // #388: Can't make iterators via make_iterator() with different r/v policies
+ static std::vector<int> list = { 1, 2, 3 };
+ m.def("make_iterator_1", []() { return py::make_iterator<py::return_value_policy::copy>(list); });
+ m.def("make_iterator_2", []() { return py::make_iterator<py::return_value_policy::automatic>(list); });
+}
diff --git a/3rdparty/pybind11/tests/test_sequences_and_iterators.py b/3rdparty/pybind11/tests/test_sequences_and_iterators.py
new file mode 100644
index 00000000..6bd16064
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_sequences_and_iterators.py
@@ -0,0 +1,171 @@
+import pytest
+from pybind11_tests import sequences_and_iterators as m
+from pybind11_tests import ConstructorStats
+
+
+def isclose(a, b, rel_tol=1e-05, abs_tol=0.0):
+ """Like math.isclose() from Python 3.5"""
+ return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
+
+
+def allclose(a_list, b_list, rel_tol=1e-05, abs_tol=0.0):
+ return all(isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) for a, b in zip(a_list, b_list))
+
+
+def test_generalized_iterators():
+ assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero()) == [(1, 2), (3, 4)]
+ assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero()) == [(1, 2)]
+ assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero()) == []
+
+ assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_keys()) == [1, 3]
+ assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_keys()) == [1]
+ assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_keys()) == []
+
+ # __next__ must continue to raise StopIteration
+ it = m.IntPairs([(0, 0)]).nonzero()
+ for _ in range(3):
+ with pytest.raises(StopIteration):
+ next(it)
+
+ it = m.IntPairs([(0, 0)]).nonzero_keys()
+ for _ in range(3):
+ with pytest.raises(StopIteration):
+ next(it)
+
+
+def test_sliceable():
+ sliceable = m.Sliceable(100)
+ assert sliceable[::] == (0, 100, 1)
+ assert sliceable[10::] == (10, 100, 1)
+ assert sliceable[:10:] == (0, 10, 1)
+ assert sliceable[::10] == (0, 100, 10)
+ assert sliceable[-10::] == (90, 100, 1)
+ assert sliceable[:-10:] == (0, 90, 1)
+ assert sliceable[::-10] == (99, -1, -10)
+ assert sliceable[50:60:1] == (50, 60, 1)
+ assert sliceable[50:60:-1] == (50, 60, -1)
+
+
+def test_sequence():
+ cstats = ConstructorStats.get(m.Sequence)
+
+ s = m.Sequence(5)
+ assert cstats.values() == ['of size', '5']
+
+ assert "Sequence" in repr(s)
+ assert len(s) == 5
+ assert s[0] == 0 and s[3] == 0
+ assert 12.34 not in s
+ s[0], s[3] = 12.34, 56.78
+ assert 12.34 in s
+ assert isclose(s[0], 12.34) and isclose(s[3], 56.78)
+
+ rev = reversed(s)
+ assert cstats.values() == ['of size', '5']
+
+ rev2 = s[::-1]
+ assert cstats.values() == ['of size', '5']
+
+ it = iter(m.Sequence(0))
+ for _ in range(3): # __next__ must continue to raise StopIteration
+ with pytest.raises(StopIteration):
+ next(it)
+ assert cstats.values() == ['of size', '0']
+
+ expected = [0, 56.78, 0, 0, 12.34]
+ assert allclose(rev, expected)
+ assert allclose(rev2, expected)
+ assert rev == rev2
+
+ rev[0::2] = m.Sequence([2.0, 2.0, 2.0])
+ assert cstats.values() == ['of size', '3', 'from std::vector']
+
+ assert allclose(rev, [2, 56.78, 2, 0, 2])
+
+ assert cstats.alive() == 4
+ del it
+ assert cstats.alive() == 3
+ del s
+ assert cstats.alive() == 2
+ del rev
+ assert cstats.alive() == 1
+ del rev2
+ assert cstats.alive() == 0
+
+ assert cstats.values() == []
+ assert cstats.default_constructions == 0
+ assert cstats.copy_constructions == 0
+ assert cstats.move_constructions >= 1
+ assert cstats.copy_assignments == 0
+ assert cstats.move_assignments == 0
+
+
+def test_map_iterator():
+ sm = m.StringMap({'hi': 'bye', 'black': 'white'})
+ assert sm['hi'] == 'bye'
+ assert len(sm) == 2
+ assert sm['black'] == 'white'
+
+ with pytest.raises(KeyError):
+ assert sm['orange']
+ sm['orange'] = 'banana'
+ assert sm['orange'] == 'banana'
+
+ expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'}
+ for k in sm:
+ assert sm[k] == expected[k]
+ for k, v in sm.items():
+ assert v == expected[k]
+
+ it = iter(m.StringMap({}))
+ for _ in range(3): # __next__ must continue to raise StopIteration
+ with pytest.raises(StopIteration):
+ next(it)
+
+
+def test_python_iterator_in_cpp():
+ t = (1, 2, 3)
+ assert m.object_to_list(t) == [1, 2, 3]
+ assert m.object_to_list(iter(t)) == [1, 2, 3]
+ assert m.iterator_to_list(iter(t)) == [1, 2, 3]
+
+ with pytest.raises(TypeError) as excinfo:
+ m.object_to_list(1)
+ assert "object is not iterable" in str(excinfo.value)
+
+ with pytest.raises(TypeError) as excinfo:
+ m.iterator_to_list(1)
+ assert "incompatible function arguments" in str(excinfo.value)
+
+ def bad_next_call():
+ raise RuntimeError("py::iterator::advance() should propagate errors")
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.iterator_to_list(iter(bad_next_call, None))
+ assert str(excinfo.value) == "py::iterator::advance() should propagate errors"
+
+ lst = [1, None, 0, None]
+ assert m.count_none(lst) == 2
+ assert m.find_none(lst) is True
+ assert m.count_nonzeros({"a": 0, "b": 1, "c": 2}) == 2
+
+ r = range(5)
+ assert all(m.tuple_iterator(tuple(r)))
+ assert all(m.list_iterator(list(r)))
+ assert all(m.sequence_iterator(r))
+
+
+def test_iterator_passthrough():
+ """#181: iterator passthrough did not compile"""
+ from pybind11_tests.sequences_and_iterators import iterator_passthrough
+
+ assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15]
+
+
+def test_iterator_rvp():
+ """#388: Can't make iterators via make_iterator() with different r/v policies """
+ import pybind11_tests.sequences_and_iterators as m
+
+ assert list(m.make_iterator_1()) == [1, 2, 3]
+ assert list(m.make_iterator_2()) == [1, 2, 3]
+ assert not isinstance(m.make_iterator_1(), type(m.make_iterator_2()))
diff --git a/3rdparty/pybind11/tests/test_smart_ptr.cpp b/3rdparty/pybind11/tests/test_smart_ptr.cpp
new file mode 100644
index 00000000..87c9be8c
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_smart_ptr.cpp
@@ -0,0 +1,366 @@
+/*
+ tests/test_smart_ptr.cpp -- binding classes with custom reference counting,
+ implicit conversions between types
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#if defined(_MSC_VER) && _MSC_VER < 1910
+# pragma warning(disable: 4702) // unreachable code in system header
+#endif
+
+#include "pybind11_tests.h"
+#include "object.h"
+
+// Make pybind aware of the ref-counted wrapper type (s):
+
+// ref<T> is a wrapper for 'Object' which uses intrusive reference counting
+// It is always possible to construct a ref<T> from an Object* pointer without
+// possible inconsistencies, hence the 'true' argument at the end.
+PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true);
+// Make pybind11 aware of the non-standard getter member function
+namespace pybind11 { namespace detail {
+ template <typename T>
+ struct holder_helper<ref<T>> {
+ static const T *get(const ref<T> &p) { return p.get_ptr(); }
+ };
+}}
+
+// The following is not required anymore for std::shared_ptr, but it should compile without error:
+PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
+
+// This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the
+// holder size to trigger the non-simple-layout internal instance layout for single inheritance with
+// large holder type:
+template <typename T> class huge_unique_ptr {
+ std::unique_ptr<T> ptr;
+ uint64_t padding[10];
+public:
+ huge_unique_ptr(T *p) : ptr(p) {};
+ T *get() { return ptr.get(); }
+};
+PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>);
+
+// Simple custom holder that works like unique_ptr
+template <typename T>
+class custom_unique_ptr {
+ std::unique_ptr<T> impl;
+public:
+ custom_unique_ptr(T* p) : impl(p) { }
+ T* get() const { return impl.get(); }
+ T* release_ptr() { return impl.release(); }
+};
+PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
+
+// Simple custom holder that works like shared_ptr and has operator& overload
+// To obtain address of an instance of this holder pybind should use std::addressof
+// Attempt to get address via operator& may leads to segmentation fault
+template <typename T>
+class shared_ptr_with_addressof_operator {
+ std::shared_ptr<T> impl;
+public:
+ shared_ptr_with_addressof_operator( ) = default;
+ shared_ptr_with_addressof_operator(T* p) : impl(p) { }
+ T* get() const { return impl.get(); }
+ T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); }
+};
+PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>);
+
+// Simple custom holder that works like unique_ptr and has operator& overload
+// To obtain address of an instance of this holder pybind should use std::addressof
+// Attempt to get address via operator& may leads to segmentation fault
+template <typename T>
+class unique_ptr_with_addressof_operator {
+ std::unique_ptr<T> impl;
+public:
+ unique_ptr_with_addressof_operator() = default;
+ unique_ptr_with_addressof_operator(T* p) : impl(p) { }
+ T* get() const { return impl.get(); }
+ T* release_ptr() { return impl.release(); }
+ T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); }
+};
+PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>);
+
+
+TEST_SUBMODULE(smart_ptr, m) {
+
+ // test_smart_ptr
+
+ // Object implementation in `object.h`
+ py::class_<Object, ref<Object>> obj(m, "Object");
+ obj.def("getRefCount", &Object::getRefCount);
+
+ // Custom object with builtin reference counting (see 'object.h' for the implementation)
+ class MyObject1 : public Object {
+ public:
+ MyObject1(int value) : value(value) { print_created(this, toString()); }
+ std::string toString() const { return "MyObject1[" + std::to_string(value) + "]"; }
+ protected:
+ virtual ~MyObject1() { print_destroyed(this); }
+ private:
+ int value;
+ };
+ py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj)
+ .def(py::init<int>());
+ py::implicitly_convertible<py::int_, MyObject1>();
+
+ m.def("make_object_1", []() -> Object * { return new MyObject1(1); });
+ m.def("make_object_2", []() -> ref<Object> { return new MyObject1(2); });
+ m.def("make_myobject1_1", []() -> MyObject1 * { return new MyObject1(4); });
+ m.def("make_myobject1_2", []() -> ref<MyObject1> { return new MyObject1(5); });
+ m.def("print_object_1", [](const Object *obj) { py::print(obj->toString()); });
+ m.def("print_object_2", [](ref<Object> obj) { py::print(obj->toString()); });
+ m.def("print_object_3", [](const ref<Object> &obj) { py::print(obj->toString()); });
+ m.def("print_object_4", [](const ref<Object> *obj) { py::print((*obj)->toString()); });
+ m.def("print_myobject1_1", [](const MyObject1 *obj) { py::print(obj->toString()); });
+ m.def("print_myobject1_2", [](ref<MyObject1> obj) { py::print(obj->toString()); });
+ m.def("print_myobject1_3", [](const ref<MyObject1> &obj) { py::print(obj->toString()); });
+ m.def("print_myobject1_4", [](const ref<MyObject1> *obj) { py::print((*obj)->toString()); });
+
+ // Expose constructor stats for the ref type
+ m.def("cstats_ref", &ConstructorStats::get<ref_tag>);
+
+
+ // Object managed by a std::shared_ptr<>
+ class MyObject2 {
+ public:
+ MyObject2(const MyObject2 &) = default;
+ MyObject2(int value) : value(value) { print_created(this, toString()); }
+ std::string toString() const { return "MyObject2[" + std::to_string(value) + "]"; }
+ virtual ~MyObject2() { print_destroyed(this); }
+ private:
+ int value;
+ };
+ py::class_<MyObject2, std::shared_ptr<MyObject2>>(m, "MyObject2")
+ .def(py::init<int>());
+ m.def("make_myobject2_1", []() { return new MyObject2(6); });
+ m.def("make_myobject2_2", []() { return std::make_shared<MyObject2>(7); });
+ m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); });
+ m.def("print_myobject2_2", [](std::shared_ptr<MyObject2> obj) { py::print(obj->toString()); });
+ m.def("print_myobject2_3", [](const std::shared_ptr<MyObject2> &obj) { py::print(obj->toString()); });
+ m.def("print_myobject2_4", [](const std::shared_ptr<MyObject2> *obj) { py::print((*obj)->toString()); });
+
+ // Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<>
+ class MyObject3 : public std::enable_shared_from_this<MyObject3> {
+ public:
+ MyObject3(const MyObject3 &) = default;
+ MyObject3(int value) : value(value) { print_created(this, toString()); }
+ std::string toString() const { return "MyObject3[" + std::to_string(value) + "]"; }
+ virtual ~MyObject3() { print_destroyed(this); }
+ private:
+ int value;
+ };
+ py::class_<MyObject3, std::shared_ptr<MyObject3>>(m, "MyObject3")
+ .def(py::init<int>());
+ m.def("make_myobject3_1", []() { return new MyObject3(8); });
+ m.def("make_myobject3_2", []() { return std::make_shared<MyObject3>(9); });
+ m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); });
+ m.def("print_myobject3_2", [](std::shared_ptr<MyObject3> obj) { py::print(obj->toString()); });
+ m.def("print_myobject3_3", [](const std::shared_ptr<MyObject3> &obj) { py::print(obj->toString()); });
+ m.def("print_myobject3_4", [](const std::shared_ptr<MyObject3> *obj) { py::print((*obj)->toString()); });
+
+ // test_smart_ptr_refcounting
+ m.def("test_object1_refcounting", []() {
+ ref<MyObject1> o = new MyObject1(0);
+ bool good = o->getRefCount() == 1;
+ py::object o2 = py::cast(o, py::return_value_policy::reference);
+ // always request (partial) ownership for objects with intrusive
+ // reference counting even when using the 'reference' RVP
+ good &= o->getRefCount() == 2;
+ return good;
+ });
+
+ // test_unique_nodelete
+ // Object with a private destructor
+ class MyObject4 {
+ public:
+ MyObject4(int value) : value{value} { print_created(this); }
+ int value;
+ private:
+ ~MyObject4() { print_destroyed(this); }
+ };
+ py::class_<MyObject4, std::unique_ptr<MyObject4, py::nodelete>>(m, "MyObject4")
+ .def(py::init<int>())
+ .def_readwrite("value", &MyObject4::value);
+
+ // test_unique_deleter
+ // Object with std::unique_ptr<T, D> where D is not matching the base class
+ // Object with a protected destructor
+ class MyObject4a {
+ public:
+ MyObject4a(int i) {
+ value = i;
+ print_created(this);
+ };
+ int value;
+ protected:
+ virtual ~MyObject4a() { print_destroyed(this); }
+ };
+ py::class_<MyObject4a, std::unique_ptr<MyObject4a, py::nodelete>>(m, "MyObject4a")
+ .def(py::init<int>())
+ .def_readwrite("value", &MyObject4a::value);
+
+ // Object derived but with public destructor and no Deleter in default holder
+ class MyObject4b : public MyObject4a {
+ public:
+ MyObject4b(int i) : MyObject4a(i) { print_created(this); }
+ ~MyObject4b() { print_destroyed(this); }
+ };
+ py::class_<MyObject4b, MyObject4a>(m, "MyObject4b")
+ .def(py::init<int>());
+
+ // test_large_holder
+ class MyObject5 { // managed by huge_unique_ptr
+ public:
+ MyObject5(int value) : value{value} { print_created(this); }
+ ~MyObject5() { print_destroyed(this); }
+ int value;
+ };
+ py::class_<MyObject5, huge_unique_ptr<MyObject5>>(m, "MyObject5")
+ .def(py::init<int>())
+ .def_readwrite("value", &MyObject5::value);
+
+ // test_shared_ptr_and_references
+ struct SharedPtrRef {
+ struct A {
+ A() { print_created(this); }
+ A(const A &) { print_copy_created(this); }
+ A(A &&) { print_move_created(this); }
+ ~A() { print_destroyed(this); }
+ };
+
+ A value = {};
+ std::shared_ptr<A> shared = std::make_shared<A>();
+ };
+ using A = SharedPtrRef::A;
+ py::class_<A, std::shared_ptr<A>>(m, "A");
+ py::class_<SharedPtrRef>(m, "SharedPtrRef")
+ .def(py::init<>())
+ .def_readonly("ref", &SharedPtrRef::value)
+ .def_property_readonly("copy", [](const SharedPtrRef &s) { return s.value; },
+ py::return_value_policy::copy)
+ .def_readonly("holder_ref", &SharedPtrRef::shared)
+ .def_property_readonly("holder_copy", [](const SharedPtrRef &s) { return s.shared; },
+ py::return_value_policy::copy)
+ .def("set_ref", [](SharedPtrRef &, const A &) { return true; })
+ .def("set_holder", [](SharedPtrRef &, std::shared_ptr<A>) { return true; });
+
+ // test_shared_ptr_from_this_and_references
+ struct SharedFromThisRef {
+ struct B : std::enable_shared_from_this<B> {
+ B() { print_created(this); }
+ B(const B &) : std::enable_shared_from_this<B>() { print_copy_created(this); }
+ B(B &&) : std::enable_shared_from_this<B>() { print_move_created(this); }
+ ~B() { print_destroyed(this); }
+ };
+
+ B value = {};
+ std::shared_ptr<B> shared = std::make_shared<B>();
+ };
+ using B = SharedFromThisRef::B;
+ py::class_<B, std::shared_ptr<B>>(m, "B");
+ py::class_<SharedFromThisRef>(m, "SharedFromThisRef")
+ .def(py::init<>())
+ .def_readonly("bad_wp", &SharedFromThisRef::value)
+ .def_property_readonly("ref", [](const SharedFromThisRef &s) -> const B & { return *s.shared; })
+ .def_property_readonly("copy", [](const SharedFromThisRef &s) { return s.value; },
+ py::return_value_policy::copy)
+ .def_readonly("holder_ref", &SharedFromThisRef::shared)
+ .def_property_readonly("holder_copy", [](const SharedFromThisRef &s) { return s.shared; },
+ py::return_value_policy::copy)
+ .def("set_ref", [](SharedFromThisRef &, const B &) { return true; })
+ .def("set_holder", [](SharedFromThisRef &, std::shared_ptr<B>) { return true; });
+
+ // Issue #865: shared_from_this doesn't work with virtual inheritance
+ struct SharedFromThisVBase : std::enable_shared_from_this<SharedFromThisVBase> {
+ SharedFromThisVBase() = default;
+ SharedFromThisVBase(const SharedFromThisVBase &) = default;
+ virtual ~SharedFromThisVBase() = default;
+ };
+ struct SharedFromThisVirt : virtual SharedFromThisVBase {};
+ static std::shared_ptr<SharedFromThisVirt> sft(new SharedFromThisVirt());
+ py::class_<SharedFromThisVirt, std::shared_ptr<SharedFromThisVirt>>(m, "SharedFromThisVirt")
+ .def_static("get", []() { return sft.get(); });
+
+ // test_move_only_holder
+ struct C {
+ C() { print_created(this); }
+ ~C() { print_destroyed(this); }
+ };
+ py::class_<C, custom_unique_ptr<C>>(m, "TypeWithMoveOnlyHolder")
+ .def_static("make", []() { return custom_unique_ptr<C>(new C); });
+
+ // test_holder_with_addressof_operator
+ struct TypeForHolderWithAddressOf {
+ TypeForHolderWithAddressOf() { print_created(this); }
+ TypeForHolderWithAddressOf(const TypeForHolderWithAddressOf &) { print_copy_created(this); }
+ TypeForHolderWithAddressOf(TypeForHolderWithAddressOf &&) { print_move_created(this); }
+ ~TypeForHolderWithAddressOf() { print_destroyed(this); }
+ std::string toString() const {
+ return "TypeForHolderWithAddressOf[" + std::to_string(value) + "]";
+ }
+ int value = 42;
+ };
+ using HolderWithAddressOf = shared_ptr_with_addressof_operator<TypeForHolderWithAddressOf>;
+ py::class_<TypeForHolderWithAddressOf, HolderWithAddressOf>(m, "TypeForHolderWithAddressOf")
+ .def_static("make", []() { return HolderWithAddressOf(new TypeForHolderWithAddressOf); })
+ .def("get", [](const HolderWithAddressOf &self) { return self.get(); })
+ .def("print_object_1", [](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); })
+ .def("print_object_2", [](HolderWithAddressOf obj) { py::print(obj.get()->toString()); })
+ .def("print_object_3", [](const HolderWithAddressOf &obj) { py::print(obj.get()->toString()); })
+ .def("print_object_4", [](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); });
+
+ // test_move_only_holder_with_addressof_operator
+ struct TypeForMoveOnlyHolderWithAddressOf {
+ TypeForMoveOnlyHolderWithAddressOf(int value) : value{value} { print_created(this); }
+ ~TypeForMoveOnlyHolderWithAddressOf() { print_destroyed(this); }
+ std::string toString() const {
+ return "MoveOnlyHolderWithAddressOf[" + std::to_string(value) + "]";
+ }
+ int value;
+ };
+ using MoveOnlyHolderWithAddressOf = unique_ptr_with_addressof_operator<TypeForMoveOnlyHolderWithAddressOf>;
+ py::class_<TypeForMoveOnlyHolderWithAddressOf, MoveOnlyHolderWithAddressOf>(m, "TypeForMoveOnlyHolderWithAddressOf")
+ .def_static("make", []() { return MoveOnlyHolderWithAddressOf(new TypeForMoveOnlyHolderWithAddressOf(0)); })
+ .def_readwrite("value", &TypeForMoveOnlyHolderWithAddressOf::value)
+ .def("print_object", [](const TypeForMoveOnlyHolderWithAddressOf *obj) { py::print(obj->toString()); });
+
+ // test_smart_ptr_from_default
+ struct HeldByDefaultHolder { };
+ py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder")
+ .def(py::init<>())
+ .def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {});
+
+ // test_shared_ptr_gc
+ // #187: issue involving std::shared_ptr<> return value policy & garbage collection
+ struct ElementBase {
+ virtual ~ElementBase() { } /* Force creation of virtual table */
+ };
+ py::class_<ElementBase, std::shared_ptr<ElementBase>>(m, "ElementBase");
+
+ struct ElementA : ElementBase {
+ ElementA(int v) : v(v) { }
+ int value() { return v; }
+ int v;
+ };
+ py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m, "ElementA")
+ .def(py::init<int>())
+ .def("value", &ElementA::value);
+
+ struct ElementList {
+ void add(std::shared_ptr<ElementBase> e) { l.push_back(e); }
+ std::vector<std::shared_ptr<ElementBase>> l;
+ };
+ py::class_<ElementList, std::shared_ptr<ElementList>>(m, "ElementList")
+ .def(py::init<>())
+ .def("add", &ElementList::add)
+ .def("get", [](ElementList &el) {
+ py::list list;
+ for (auto &e : el.l)
+ list.append(py::cast(e));
+ return list;
+ });
+}
diff --git a/3rdparty/pybind11/tests/test_smart_ptr.py b/3rdparty/pybind11/tests/test_smart_ptr.py
new file mode 100644
index 00000000..c6627043
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_smart_ptr.py
@@ -0,0 +1,286 @@
+import pytest
+from pybind11_tests import smart_ptr as m
+from pybind11_tests import ConstructorStats
+
+
+def test_smart_ptr(capture):
+ # Object1
+ for i, o in enumerate([m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1):
+ assert o.getRefCount() == 1
+ with capture:
+ m.print_object_1(o)
+ m.print_object_2(o)
+ m.print_object_3(o)
+ m.print_object_4(o)
+ assert capture == "MyObject1[{i}]\n".format(i=i) * 4
+
+ for i, o in enumerate([m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7],
+ start=4):
+ print(o)
+ with capture:
+ if not isinstance(o, int):
+ m.print_object_1(o)
+ m.print_object_2(o)
+ m.print_object_3(o)
+ m.print_object_4(o)
+ m.print_myobject1_1(o)
+ m.print_myobject1_2(o)
+ m.print_myobject1_3(o)
+ m.print_myobject1_4(o)
+ assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8)
+
+ cstats = ConstructorStats.get(m.MyObject1)
+ assert cstats.alive() == 0
+ expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4
+ assert cstats.values() == expected_values
+ assert cstats.default_constructions == 0
+ assert cstats.copy_constructions == 0
+ # assert cstats.move_constructions >= 0 # Doesn't invoke any
+ assert cstats.copy_assignments == 0
+ assert cstats.move_assignments == 0
+
+ # Object2
+ for i, o in zip([8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]):
+ print(o)
+ with capture:
+ m.print_myobject2_1(o)
+ m.print_myobject2_2(o)
+ m.print_myobject2_3(o)
+ m.print_myobject2_4(o)
+ assert capture == "MyObject2[{i}]\n".format(i=i) * 4
+
+ cstats = ConstructorStats.get(m.MyObject2)
+ assert cstats.alive() == 1
+ o = None
+ assert cstats.alive() == 0
+ assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]']
+ assert cstats.default_constructions == 0
+ assert cstats.copy_constructions == 0
+ # assert cstats.move_constructions >= 0 # Doesn't invoke any
+ assert cstats.copy_assignments == 0
+ assert cstats.move_assignments == 0
+
+ # Object3
+ for i, o in zip([9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]):
+ print(o)
+ with capture:
+ m.print_myobject3_1(o)
+ m.print_myobject3_2(o)
+ m.print_myobject3_3(o)
+ m.print_myobject3_4(o)
+ assert capture == "MyObject3[{i}]\n".format(i=i) * 4
+
+ cstats = ConstructorStats.get(m.MyObject3)
+ assert cstats.alive() == 1
+ o = None
+ assert cstats.alive() == 0
+ assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]']
+ assert cstats.default_constructions == 0
+ assert cstats.copy_constructions == 0
+ # assert cstats.move_constructions >= 0 # Doesn't invoke any
+ assert cstats.copy_assignments == 0
+ assert cstats.move_assignments == 0
+
+ # Object
+ cstats = ConstructorStats.get(m.Object)
+ assert cstats.alive() == 0
+ assert cstats.values() == []
+ assert cstats.default_constructions == 10
+ assert cstats.copy_constructions == 0
+ # assert cstats.move_constructions >= 0 # Doesn't invoke any
+ assert cstats.copy_assignments == 0
+ assert cstats.move_assignments == 0
+
+ # ref<>
+ cstats = m.cstats_ref()
+ assert cstats.alive() == 0
+ assert cstats.values() == ['from pointer'] * 10
+ assert cstats.default_constructions == 30
+ assert cstats.copy_constructions == 12
+ # assert cstats.move_constructions >= 0 # Doesn't invoke any
+ assert cstats.copy_assignments == 30
+ assert cstats.move_assignments == 0
+
+
+def test_smart_ptr_refcounting():
+ assert m.test_object1_refcounting()
+
+
+def test_unique_nodelete():
+ o = m.MyObject4(23)
+ assert o.value == 23
+ cstats = ConstructorStats.get(m.MyObject4)
+ assert cstats.alive() == 1
+ del o
+ assert cstats.alive() == 1 # Leak, but that's intentional
+
+
+def test_unique_nodelete4a():
+ o = m.MyObject4a(23)
+ assert o.value == 23
+ cstats = ConstructorStats.get(m.MyObject4a)
+ assert cstats.alive() == 1
+ del o
+ assert cstats.alive() == 1 # Leak, but that's intentional
+
+
+def test_unique_deleter():
+ o = m.MyObject4b(23)
+ assert o.value == 23
+ cstats4a = ConstructorStats.get(m.MyObject4a)
+ assert cstats4a.alive() == 2 # Two because of previous test
+ cstats4b = ConstructorStats.get(m.MyObject4b)
+ assert cstats4b.alive() == 1
+ del o
+ assert cstats4a.alive() == 1 # Should now only be one leftover from previous test
+ assert cstats4b.alive() == 0 # Should be deleted
+
+
+def test_large_holder():
+ o = m.MyObject5(5)
+ assert o.value == 5
+ cstats = ConstructorStats.get(m.MyObject5)
+ assert cstats.alive() == 1
+ del o
+ assert cstats.alive() == 0
+
+
+def test_shared_ptr_and_references():
+ s = m.SharedPtrRef()
+ stats = ConstructorStats.get(m.A)
+ assert stats.alive() == 2
+
+ ref = s.ref # init_holder_helper(holder_ptr=false, owned=false)
+ assert stats.alive() == 2
+ assert s.set_ref(ref)
+ with pytest.raises(RuntimeError) as excinfo:
+ assert s.set_holder(ref)
+ assert "Unable to cast from non-held to held instance" in str(excinfo.value)
+
+ copy = s.copy # init_holder_helper(holder_ptr=false, owned=true)
+ assert stats.alive() == 3
+ assert s.set_ref(copy)
+ assert s.set_holder(copy)
+
+ holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false)
+ assert stats.alive() == 3
+ assert s.set_ref(holder_ref)
+ assert s.set_holder(holder_ref)
+
+ holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true)
+ assert stats.alive() == 3
+ assert s.set_ref(holder_copy)
+ assert s.set_holder(holder_copy)
+
+ del ref, copy, holder_ref, holder_copy, s
+ assert stats.alive() == 0
+
+
+def test_shared_ptr_from_this_and_references():
+ s = m.SharedFromThisRef()
+ stats = ConstructorStats.get(m.B)
+ assert stats.alive() == 2
+
+ ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
+ assert stats.alive() == 2
+ assert s.set_ref(ref)
+ assert s.set_holder(ref) # std::enable_shared_from_this can create a holder from a reference
+
+ bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
+ assert stats.alive() == 2
+ assert s.set_ref(bad_wp)
+ with pytest.raises(RuntimeError) as excinfo:
+ assert s.set_holder(bad_wp)
+ assert "Unable to cast from non-held to held instance" in str(excinfo.value)
+
+ copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false)
+ assert stats.alive() == 3
+ assert s.set_ref(copy)
+ assert s.set_holder(copy)
+
+ holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
+ assert stats.alive() == 3
+ assert s.set_ref(holder_ref)
+ assert s.set_holder(holder_ref)
+
+ holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
+ assert stats.alive() == 3
+ assert s.set_ref(holder_copy)
+ assert s.set_holder(holder_copy)
+
+ del ref, bad_wp, copy, holder_ref, holder_copy, s
+ assert stats.alive() == 0
+
+ z = m.SharedFromThisVirt.get()
+ y = m.SharedFromThisVirt.get()
+ assert y is z
+
+
+def test_move_only_holder():
+ a = m.TypeWithMoveOnlyHolder.make()
+ stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder)
+ assert stats.alive() == 1
+ del a
+ assert stats.alive() == 0
+
+
+def test_holder_with_addressof_operator():
+ # this test must not throw exception from c++
+ a = m.TypeForHolderWithAddressOf.make()
+ a.print_object_1()
+ a.print_object_2()
+ a.print_object_3()
+ a.print_object_4()
+
+ stats = ConstructorStats.get(m.TypeForHolderWithAddressOf)
+ assert stats.alive() == 1
+
+ np = m.TypeForHolderWithAddressOf.make()
+ assert stats.alive() == 2
+ del a
+ assert stats.alive() == 1
+ del np
+ assert stats.alive() == 0
+
+ b = m.TypeForHolderWithAddressOf.make()
+ c = b
+ assert b.get() is c.get()
+ assert stats.alive() == 1
+
+ del b
+ assert stats.alive() == 1
+
+ del c
+ assert stats.alive() == 0
+
+
+def test_move_only_holder_with_addressof_operator():
+ a = m.TypeForMoveOnlyHolderWithAddressOf.make()
+ a.print_object()
+
+ stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf)
+ assert stats.alive() == 1
+
+ a.value = 42
+ assert a.value == 42
+
+ del a
+ assert stats.alive() == 0
+
+
+def test_smart_ptr_from_default():
+ instance = m.HeldByDefaultHolder()
+ with pytest.raises(RuntimeError) as excinfo:
+ m.HeldByDefaultHolder.load_shared_ptr(instance)
+ assert "Unable to load a custom holder type from a " \
+ "default-holder instance" in str(excinfo.value)
+
+
+def test_shared_ptr_gc():
+ """#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
+ el = m.ElementList()
+ for i in range(10):
+ el.add(m.ElementA(i))
+ pytest.gc_collect()
+ for i, v in enumerate(el.get()):
+ assert i == v.value()
diff --git a/3rdparty/pybind11/tests/test_stl.cpp b/3rdparty/pybind11/tests/test_stl.cpp
new file mode 100644
index 00000000..207c9fb2
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_stl.cpp
@@ -0,0 +1,284 @@
+/*
+ tests/test_stl.cpp -- STL type casters
+
+ Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/stl.h>
+
+#include <vector>
+#include <string>
+
+// Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14
+#if PYBIND11_HAS_VARIANT
+using std::variant;
+#elif defined(PYBIND11_TEST_BOOST) && (!defined(_MSC_VER) || _MSC_VER >= 1910)
+# include <boost/variant.hpp>
+# define PYBIND11_HAS_VARIANT 1
+using boost::variant;
+
+namespace pybind11 { namespace detail {
+template <typename... Ts>
+struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};
+
+template <>
+struct visit_helper<boost::variant> {
+ template <typename... Args>
+ static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) {
+ return boost::apply_visitor(args...);
+ }
+};
+}} // namespace pybind11::detail
+#endif
+
+PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>);
+
+/// Issue #528: templated constructor
+struct TplCtorClass {
+ template <typename T> TplCtorClass(const T &) { }
+ bool operator==(const TplCtorClass &) const { return true; }
+};
+
+namespace std {
+ template <>
+ struct hash<TplCtorClass> { size_t operator()(const TplCtorClass &) const { return 0; } };
+}
+
+
+TEST_SUBMODULE(stl, m) {
+ // test_vector
+ m.def("cast_vector", []() { return std::vector<int>{1}; });
+ m.def("load_vector", [](const std::vector<int> &v) { return v.at(0) == 1 && v.at(1) == 2; });
+ // `std::vector<bool>` is special because it returns proxy objects instead of references
+ m.def("cast_bool_vector", []() { return std::vector<bool>{true, false}; });
+ m.def("load_bool_vector", [](const std::vector<bool> &v) {
+ return v.at(0) == true && v.at(1) == false;
+ });
+ // Unnumbered regression (caused by #936): pointers to stl containers aren't castable
+ static std::vector<RValueCaster> lvv{2};
+ m.def("cast_ptr_vector", []() { return &lvv; });
+
+ // test_deque
+ m.def("cast_deque", []() { return std::deque<int>{1}; });
+ m.def("load_deque", [](const std::deque<int> &v) { return v.at(0) == 1 && v.at(1) == 2; });
+
+ // test_array
+ m.def("cast_array", []() { return std::array<int, 2> {{1 , 2}}; });
+ m.def("load_array", [](const std::array<int, 2> &a) { return a[0] == 1 && a[1] == 2; });
+
+ // test_valarray
+ m.def("cast_valarray", []() { return std::valarray<int>{1, 4, 9}; });
+ m.def("load_valarray", [](const std::valarray<int>& v) {
+ return v.size() == 3 && v[0] == 1 && v[1] == 4 && v[2] == 9;
+ });
+
+ // test_map
+ m.def("cast_map", []() { return std::map<std::string, std::string>{{"key", "value"}}; });
+ m.def("load_map", [](const std::map<std::string, std::string> &map) {
+ return map.at("key") == "value" && map.at("key2") == "value2";
+ });
+
+ // test_set
+ m.def("cast_set", []() { return std::set<std::string>{"key1", "key2"}; });
+ m.def("load_set", [](const std::set<std::string> &set) {
+ return set.count("key1") && set.count("key2") && set.count("key3");
+ });
+
+ // test_recursive_casting
+ m.def("cast_rv_vector", []() { return std::vector<RValueCaster>{2}; });
+ m.def("cast_rv_array", []() { return std::array<RValueCaster, 3>(); });
+ // NB: map and set keys are `const`, so while we technically do move them (as `const Type &&`),
+ // casters don't typically do anything with that, which means they fall to the `const Type &`
+ // caster.
+ m.def("cast_rv_map", []() { return std::unordered_map<std::string, RValueCaster>{{"a", RValueCaster{}}}; });
+ m.def("cast_rv_nested", []() {
+ std::vector<std::array<std::list<std::unordered_map<std::string, RValueCaster>>, 2>> v;
+ v.emplace_back(); // add an array
+ v.back()[0].emplace_back(); // add a map to the array
+ v.back()[0].back().emplace("b", RValueCaster{});
+ v.back()[0].back().emplace("c", RValueCaster{});
+ v.back()[1].emplace_back(); // add a map to the array
+ v.back()[1].back().emplace("a", RValueCaster{});
+ return v;
+ });
+ static std::array<RValueCaster, 2> lva;
+ static std::unordered_map<std::string, RValueCaster> lvm{{"a", RValueCaster{}}, {"b", RValueCaster{}}};
+ static std::unordered_map<std::string, std::vector<std::list<std::array<RValueCaster, 2>>>> lvn;
+ lvn["a"].emplace_back(); // add a list
+ lvn["a"].back().emplace_back(); // add an array
+ lvn["a"].emplace_back(); // another list
+ lvn["a"].back().emplace_back(); // add an array
+ lvn["b"].emplace_back(); // add a list
+ lvn["b"].back().emplace_back(); // add an array
+ lvn["b"].back().emplace_back(); // add another array
+ m.def("cast_lv_vector", []() -> const decltype(lvv) & { return lvv; });
+ m.def("cast_lv_array", []() -> const decltype(lva) & { return lva; });
+ m.def("cast_lv_map", []() -> const decltype(lvm) & { return lvm; });
+ m.def("cast_lv_nested", []() -> const decltype(lvn) & { return lvn; });
+ // #853:
+ m.def("cast_unique_ptr_vector", []() {
+ std::vector<std::unique_ptr<UserType>> v;
+ v.emplace_back(new UserType{7});
+ v.emplace_back(new UserType{42});
+ return v;
+ });
+
+ // test_move_out_container
+ struct MoveOutContainer {
+ struct Value { int value; };
+ std::list<Value> move_list() const { return {{0}, {1}, {2}}; }
+ };
+ py::class_<MoveOutContainer::Value>(m, "MoveOutContainerValue")
+ .def_readonly("value", &MoveOutContainer::Value::value);
+ py::class_<MoveOutContainer>(m, "MoveOutContainer")
+ .def(py::init<>())
+ .def_property_readonly("move_list", &MoveOutContainer::move_list);
+
+ // Class that can be move- and copy-constructed, but not assigned
+ struct NoAssign {
+ int value;
+
+ explicit NoAssign(int value = 0) : value(value) { }
+ NoAssign(const NoAssign &) = default;
+ NoAssign(NoAssign &&) = default;
+
+ NoAssign &operator=(const NoAssign &) = delete;
+ NoAssign &operator=(NoAssign &&) = delete;
+ };
+ py::class_<NoAssign>(m, "NoAssign", "Class with no C++ assignment operators")
+ .def(py::init<>())
+ .def(py::init<int>());
+
+#ifdef PYBIND11_HAS_OPTIONAL
+ // test_optional
+ m.attr("has_optional") = true;
+
+ using opt_int = std::optional<int>;
+ using opt_no_assign = std::optional<NoAssign>;
+ m.def("double_or_zero", [](const opt_int& x) -> int {
+ return x.value_or(0) * 2;
+ });
+ m.def("half_or_none", [](int x) -> opt_int {
+ return x ? opt_int(x / 2) : opt_int();
+ });
+ m.def("test_nullopt", [](opt_int x) {
+ return x.value_or(42);
+ }, py::arg_v("x", std::nullopt, "None"));
+ m.def("test_no_assign", [](const opt_no_assign &x) {
+ return x ? x->value : 42;
+ }, py::arg_v("x", std::nullopt, "None"));
+
+ m.def("nodefer_none_optional", [](std::optional<int>) { return true; });
+ m.def("nodefer_none_optional", [](py::none) { return false; });
+#endif
+
+#ifdef PYBIND11_HAS_EXP_OPTIONAL
+ // test_exp_optional
+ m.attr("has_exp_optional") = true;
+
+ using exp_opt_int = std::experimental::optional<int>;
+ using exp_opt_no_assign = std::experimental::optional<NoAssign>;
+ m.def("double_or_zero_exp", [](const exp_opt_int& x) -> int {
+ return x.value_or(0) * 2;
+ });
+ m.def("half_or_none_exp", [](int x) -> exp_opt_int {
+ return x ? exp_opt_int(x / 2) : exp_opt_int();
+ });
+ m.def("test_nullopt_exp", [](exp_opt_int x) {
+ return x.value_or(42);
+ }, py::arg_v("x", std::experimental::nullopt, "None"));
+ m.def("test_no_assign_exp", [](const exp_opt_no_assign &x) {
+ return x ? x->value : 42;
+ }, py::arg_v("x", std::experimental::nullopt, "None"));
+#endif
+
+#ifdef PYBIND11_HAS_VARIANT
+ static_assert(std::is_same<py::detail::variant_caster_visitor::result_type, py::handle>::value,
+ "visitor::result_type is required by boost::variant in C++11 mode");
+
+ struct visitor {
+ using result_type = const char *;
+
+ result_type operator()(int) { return "int"; }
+ result_type operator()(std::string) { return "std::string"; }
+ result_type operator()(double) { return "double"; }
+ result_type operator()(std::nullptr_t) { return "std::nullptr_t"; }
+ };
+
+ // test_variant
+ m.def("load_variant", [](variant<int, std::string, double, std::nullptr_t> v) {
+ return py::detail::visit_helper<variant>::call(visitor(), v);
+ });
+ m.def("load_variant_2pass", [](variant<double, int> v) {
+ return py::detail::visit_helper<variant>::call(visitor(), v);
+ });
+ m.def("cast_variant", []() {
+ using V = variant<int, std::string>;
+ return py::make_tuple(V(5), V("Hello"));
+ });
+#endif
+
+ // #528: templated constructor
+ // (no python tests: the test here is that this compiles)
+ m.def("tpl_ctor_vector", [](std::vector<TplCtorClass> &) {});
+ m.def("tpl_ctor_map", [](std::unordered_map<TplCtorClass, TplCtorClass> &) {});
+ m.def("tpl_ctor_set", [](std::unordered_set<TplCtorClass> &) {});
+#if defined(PYBIND11_HAS_OPTIONAL)
+ m.def("tpl_constr_optional", [](std::optional<TplCtorClass> &) {});
+#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
+ m.def("tpl_constr_optional", [](std::experimental::optional<TplCtorClass> &) {});
+#endif
+
+ // test_vec_of_reference_wrapper
+ // #171: Can't return STL structures containing reference wrapper
+ m.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<UserType> p4) {
+ static UserType p1{1}, p2{2}, p3{3};
+ return std::vector<std::reference_wrapper<UserType>> {
+ std::ref(p1), std::ref(p2), std::ref(p3), p4
+ };
+ });
+
+ // test_stl_pass_by_pointer
+ m.def("stl_pass_by_pointer", [](std::vector<int>* v) { return *v; }, "v"_a=nullptr);
+
+ // #1258: pybind11/stl.h converts string to vector<string>
+ m.def("func_with_string_or_vector_string_arg_overload", [](std::vector<std::string>) { return 1; });
+ m.def("func_with_string_or_vector_string_arg_overload", [](std::list<std::string>) { return 2; });
+ m.def("func_with_string_or_vector_string_arg_overload", [](std::string) { return 3; });
+
+ class Placeholder {
+ public:
+ Placeholder() { print_created(this); }
+ Placeholder(const Placeholder &) = delete;
+ ~Placeholder() { print_destroyed(this); }
+ };
+ py::class_<Placeholder>(m, "Placeholder");
+
+ /// test_stl_vector_ownership
+ m.def("test_stl_ownership",
+ []() {
+ std::vector<Placeholder *> result;
+ result.push_back(new Placeholder());
+ return result;
+ },
+ py::return_value_policy::take_ownership);
+
+ m.def("array_cast_sequence", [](std::array<int, 3> x) { return x; });
+
+ /// test_issue_1561
+ struct Issue1561Inner { std::string data; };
+ struct Issue1561Outer { std::vector<Issue1561Inner> list; };
+
+ py::class_<Issue1561Inner>(m, "Issue1561Inner")
+ .def(py::init<std::string>())
+ .def_readwrite("data", &Issue1561Inner::data);
+
+ py::class_<Issue1561Outer>(m, "Issue1561Outer")
+ .def(py::init<>())
+ .def_readwrite("list", &Issue1561Outer::list);
+}
diff --git a/3rdparty/pybind11/tests/test_stl.py b/3rdparty/pybind11/tests/test_stl.py
new file mode 100644
index 00000000..2335cb9f
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_stl.py
@@ -0,0 +1,241 @@
+import pytest
+
+from pybind11_tests import stl as m
+from pybind11_tests import UserType
+from pybind11_tests import ConstructorStats
+
+
+def test_vector(doc):
+ """std::vector <-> list"""
+ lst = m.cast_vector()
+ assert lst == [1]
+ lst.append(2)
+ assert m.load_vector(lst)
+ assert m.load_vector(tuple(lst))
+
+ assert m.cast_bool_vector() == [True, False]
+ assert m.load_bool_vector([True, False])
+
+ assert doc(m.cast_vector) == "cast_vector() -> List[int]"
+ assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool"
+
+ # Test regression caused by 936: pointers to stl containers weren't castable
+ assert m.cast_ptr_vector() == ["lvalue", "lvalue"]
+
+
+def test_deque(doc):
+ """std::deque <-> list"""
+ lst = m.cast_deque()
+ assert lst == [1]
+ lst.append(2)
+ assert m.load_deque(lst)
+ assert m.load_deque(tuple(lst))
+
+
+def test_array(doc):
+ """std::array <-> list"""
+ lst = m.cast_array()
+ assert lst == [1, 2]
+ assert m.load_array(lst)
+
+ assert doc(m.cast_array) == "cast_array() -> List[int[2]]"
+ assert doc(m.load_array) == "load_array(arg0: List[int[2]]) -> bool"
+
+
+def test_valarray(doc):
+ """std::valarray <-> list"""
+ lst = m.cast_valarray()
+ assert lst == [1, 4, 9]
+ assert m.load_valarray(lst)
+
+ assert doc(m.cast_valarray) == "cast_valarray() -> List[int]"
+ assert doc(m.load_valarray) == "load_valarray(arg0: List[int]) -> bool"
+
+
+def test_map(doc):
+ """std::map <-> dict"""
+ d = m.cast_map()
+ assert d == {"key": "value"}
+ assert "key" in d
+ d["key2"] = "value2"
+ assert "key2" in d
+ assert m.load_map(d)
+
+ assert doc(m.cast_map) == "cast_map() -> Dict[str, str]"
+ assert doc(m.load_map) == "load_map(arg0: Dict[str, str]) -> bool"
+
+
+def test_set(doc):
+ """std::set <-> set"""
+ s = m.cast_set()
+ assert s == {"key1", "key2"}
+ s.add("key3")
+ assert m.load_set(s)
+
+ assert doc(m.cast_set) == "cast_set() -> Set[str]"
+ assert doc(m.load_set) == "load_set(arg0: Set[str]) -> bool"
+
+
+def test_recursive_casting():
+ """Tests that stl casters preserve lvalue/rvalue context for container values"""
+ assert m.cast_rv_vector() == ["rvalue", "rvalue"]
+ assert m.cast_lv_vector() == ["lvalue", "lvalue"]
+ assert m.cast_rv_array() == ["rvalue", "rvalue", "rvalue"]
+ assert m.cast_lv_array() == ["lvalue", "lvalue"]
+ assert m.cast_rv_map() == {"a": "rvalue"}
+ assert m.cast_lv_map() == {"a": "lvalue", "b": "lvalue"}
+ assert m.cast_rv_nested() == [[[{"b": "rvalue", "c": "rvalue"}], [{"a": "rvalue"}]]]
+ assert m.cast_lv_nested() == {
+ "a": [[["lvalue", "lvalue"]], [["lvalue", "lvalue"]]],
+ "b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]]
+ }
+
+ # Issue #853 test case:
+ z = m.cast_unique_ptr_vector()
+ assert z[0].value == 7 and z[1].value == 42
+
+
+def test_move_out_container():
+ """Properties use the `reference_internal` policy by default. If the underlying function
+ returns an rvalue, the policy is automatically changed to `move` to avoid referencing
+ a temporary. In case the return value is a container of user-defined types, the policy
+ also needs to be applied to the elements, not just the container."""
+ c = m.MoveOutContainer()
+ moved_out_list = c.move_list
+ assert [x.value for x in moved_out_list] == [0, 1, 2]
+
+
+@pytest.mark.skipif(not hasattr(m, "has_optional"), reason='no <optional>')
+def test_optional():
+ assert m.double_or_zero(None) == 0
+ assert m.double_or_zero(42) == 84
+ pytest.raises(TypeError, m.double_or_zero, 'foo')
+
+ assert m.half_or_none(0) is None
+ assert m.half_or_none(42) == 21
+ pytest.raises(TypeError, m.half_or_none, 'foo')
+
+ assert m.test_nullopt() == 42
+ assert m.test_nullopt(None) == 42
+ assert m.test_nullopt(42) == 42
+ assert m.test_nullopt(43) == 43
+
+ assert m.test_no_assign() == 42
+ assert m.test_no_assign(None) == 42
+ assert m.test_no_assign(m.NoAssign(43)) == 43
+ pytest.raises(TypeError, m.test_no_assign, 43)
+
+ assert m.nodefer_none_optional(None)
+
+
+@pytest.mark.skipif(not hasattr(m, "has_exp_optional"), reason='no <experimental/optional>')
+def test_exp_optional():
+ assert m.double_or_zero_exp(None) == 0
+ assert m.double_or_zero_exp(42) == 84
+ pytest.raises(TypeError, m.double_or_zero_exp, 'foo')
+
+ assert m.half_or_none_exp(0) is None
+ assert m.half_or_none_exp(42) == 21
+ pytest.raises(TypeError, m.half_or_none_exp, 'foo')
+
+ assert m.test_nullopt_exp() == 42
+ assert m.test_nullopt_exp(None) == 42
+ assert m.test_nullopt_exp(42) == 42
+ assert m.test_nullopt_exp(43) == 43
+
+ assert m.test_no_assign_exp() == 42
+ assert m.test_no_assign_exp(None) == 42
+ assert m.test_no_assign_exp(m.NoAssign(43)) == 43
+ pytest.raises(TypeError, m.test_no_assign_exp, 43)
+
+
+@pytest.mark.skipif(not hasattr(m, "load_variant"), reason='no <variant>')
+def test_variant(doc):
+ assert m.load_variant(1) == "int"
+ assert m.load_variant("1") == "std::string"
+ assert m.load_variant(1.0) == "double"
+ assert m.load_variant(None) == "std::nullptr_t"
+
+ assert m.load_variant_2pass(1) == "int"
+ assert m.load_variant_2pass(1.0) == "double"
+
+ assert m.cast_variant() == (5, "Hello")
+
+ assert doc(m.load_variant) == "load_variant(arg0: Union[int, str, float, None]) -> str"
+
+
+def test_vec_of_reference_wrapper():
+ """#171: Can't return reference wrappers (or STL structures containing them)"""
+ assert str(m.return_vec_of_reference_wrapper(UserType(4))) == \
+ "[UserType(1), UserType(2), UserType(3), UserType(4)]"
+
+
+def test_stl_pass_by_pointer(msg):
+ """Passing nullptr or None to an STL container pointer is not expected to work"""
+ with pytest.raises(TypeError) as excinfo:
+ m.stl_pass_by_pointer() # default value is `nullptr`
+ assert msg(excinfo.value) == """
+ stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:
+ 1. (v: List[int] = None) -> List[int]
+
+ Invoked with:
+ """ # noqa: E501 line too long
+
+ with pytest.raises(TypeError) as excinfo:
+ m.stl_pass_by_pointer(None)
+ assert msg(excinfo.value) == """
+ stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:
+ 1. (v: List[int] = None) -> List[int]
+
+ Invoked with: None
+ """ # noqa: E501 line too long
+
+ assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3]
+
+
+def test_missing_header_message():
+ """Trying convert `list` to a `std::vector`, or vice versa, without including
+ <pybind11/stl.h> should result in a helpful suggestion in the error message"""
+ import pybind11_cross_module_tests as cm
+
+ expected_message = ("Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,\n"
+ "<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic\n"
+ "conversions are optional and require extra headers to be included\n"
+ "when compiling your pybind11 module.")
+
+ with pytest.raises(TypeError) as excinfo:
+ cm.missing_header_arg([1.0, 2.0, 3.0])
+ assert expected_message in str(excinfo.value)
+
+ with pytest.raises(TypeError) as excinfo:
+ cm.missing_header_return()
+ assert expected_message in str(excinfo.value)
+
+
+def test_function_with_string_and_vector_string_arg():
+ """Check if a string is NOT implicitly converted to a list, which was the
+ behavior before fix of issue #1258"""
+ assert m.func_with_string_or_vector_string_arg_overload(('A', 'B', )) == 2
+ assert m.func_with_string_or_vector_string_arg_overload(['A', 'B']) == 2
+ assert m.func_with_string_or_vector_string_arg_overload('A') == 3
+
+
+def test_stl_ownership():
+ cstats = ConstructorStats.get(m.Placeholder)
+ assert cstats.alive() == 0
+ r = m.test_stl_ownership()
+ assert len(r) == 1
+ del r
+ assert cstats.alive() == 0
+
+
+def test_array_cast_sequence():
+ assert m.array_cast_sequence((1, 2, 3)) == [1, 2, 3]
+
+
+def test_issue_1561():
+ """ check fix for issue #1561 """
+ bar = m.Issue1561Outer()
+ bar.list = [m.Issue1561Inner('bar')]
+ bar.list
+ assert bar.list[0].data == 'bar'
diff --git a/3rdparty/pybind11/tests/test_stl_binders.cpp b/3rdparty/pybind11/tests/test_stl_binders.cpp
new file mode 100644
index 00000000..86888740
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_stl_binders.cpp
@@ -0,0 +1,129 @@
+/*
+ tests/test_stl_binders.cpp -- Usage of stl_binders functions
+
+ Copyright (c) 2016 Sergey Lyskov
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+#include <pybind11/stl_bind.h>
+#include <pybind11/numpy.h>
+#include <map>
+#include <deque>
+#include <unordered_map>
+
+class El {
+public:
+ El() = delete;
+ El(int v) : a(v) { }
+
+ int a;
+};
+
+std::ostream & operator<<(std::ostream &s, El const&v) {
+ s << "El{" << v.a << '}';
+ return s;
+}
+
+/// Issue #487: binding std::vector<E> with E non-copyable
+class E_nc {
+public:
+ explicit E_nc(int i) : value{i} {}
+ E_nc(const E_nc &) = delete;
+ E_nc &operator=(const E_nc &) = delete;
+ E_nc(E_nc &&) = default;
+ E_nc &operator=(E_nc &&) = default;
+
+ int value;
+};
+
+template <class Container> Container *one_to_n(int n) {
+ auto v = new Container();
+ for (int i = 1; i <= n; i++)
+ v->emplace_back(i);
+ return v;
+}
+
+template <class Map> Map *times_ten(int n) {
+ auto m = new Map();
+ for (int i = 1; i <= n; i++)
+ m->emplace(int(i), E_nc(10*i));
+ return m;
+}
+
+template <class NestMap> NestMap *times_hundred(int n) {
+ auto m = new NestMap();
+ for (int i = 1; i <= n; i++)
+ for (int j = 1; j <= n; j++)
+ (*m)[i].emplace(int(j*10), E_nc(100*j));
+ return m;
+}
+
+TEST_SUBMODULE(stl_binders, m) {
+ // test_vector_int
+ py::bind_vector<std::vector<unsigned int>>(m, "VectorInt", py::buffer_protocol());
+
+ // test_vector_custom
+ py::class_<El>(m, "El")
+ .def(py::init<int>());
+ py::bind_vector<std::vector<El>>(m, "VectorEl");
+ py::bind_vector<std::vector<std::vector<El>>>(m, "VectorVectorEl");
+
+ // test_map_string_double
+ py::bind_map<std::map<std::string, double>>(m, "MapStringDouble");
+ py::bind_map<std::unordered_map<std::string, double>>(m, "UnorderedMapStringDouble");
+
+ // test_map_string_double_const
+ py::bind_map<std::map<std::string, double const>>(m, "MapStringDoubleConst");
+ py::bind_map<std::unordered_map<std::string, double const>>(m, "UnorderedMapStringDoubleConst");
+
+ py::class_<E_nc>(m, "ENC")
+ .def(py::init<int>())
+ .def_readwrite("value", &E_nc::value);
+
+ // test_noncopyable_containers
+ py::bind_vector<std::vector<E_nc>>(m, "VectorENC");
+ m.def("get_vnc", &one_to_n<std::vector<E_nc>>, py::return_value_policy::reference);
+ py::bind_vector<std::deque<E_nc>>(m, "DequeENC");
+ m.def("get_dnc", &one_to_n<std::deque<E_nc>>, py::return_value_policy::reference);
+ py::bind_map<std::map<int, E_nc>>(m, "MapENC");
+ m.def("get_mnc", &times_ten<std::map<int, E_nc>>, py::return_value_policy::reference);
+ py::bind_map<std::unordered_map<int, E_nc>>(m, "UmapENC");
+ m.def("get_umnc", &times_ten<std::unordered_map<int, E_nc>>, py::return_value_policy::reference);
+ // Issue #1885: binding nested std::map<X, Container<E>> with E non-copyable
+ py::bind_map<std::map<int, std::vector<E_nc>>>(m, "MapVecENC");
+ m.def("get_nvnc", [](int n)
+ {
+ auto m = new std::map<int, std::vector<E_nc>>();
+ for (int i = 1; i <= n; i++)
+ for (int j = 1; j <= n; j++)
+ (*m)[i].emplace_back(j);
+ return m;
+ }, py::return_value_policy::reference);
+ py::bind_map<std::map<int, std::map<int, E_nc>>>(m, "MapMapENC");
+ m.def("get_nmnc", &times_hundred<std::map<int, std::map<int, E_nc>>>, py::return_value_policy::reference);
+ py::bind_map<std::unordered_map<int, std::unordered_map<int, E_nc>>>(m, "UmapUmapENC");
+ m.def("get_numnc", &times_hundred<std::unordered_map<int, std::unordered_map<int, E_nc>>>, py::return_value_policy::reference);
+
+ // test_vector_buffer
+ py::bind_vector<std::vector<unsigned char>>(m, "VectorUChar", py::buffer_protocol());
+ // no dtype declared for this version:
+ struct VUndeclStruct { bool w; uint32_t x; double y; bool z; };
+ m.def("create_undeclstruct", [m] () mutable {
+ py::bind_vector<std::vector<VUndeclStruct>>(m, "VectorUndeclStruct", py::buffer_protocol());
+ });
+
+ // The rest depends on numpy:
+ try { py::module::import("numpy"); }
+ catch (...) { return; }
+
+ // test_vector_buffer_numpy
+ struct VStruct { bool w; uint32_t x; double y; bool z; };
+ PYBIND11_NUMPY_DTYPE(VStruct, w, x, y, z);
+ py::class_<VStruct>(m, "VStruct").def_readwrite("x", &VStruct::x);
+ py::bind_vector<std::vector<VStruct>>(m, "VectorStruct", py::buffer_protocol());
+ m.def("get_vectorstruct", [] {return std::vector<VStruct> {{0, 5, 3.0, 1}, {1, 30, -1e4, 0}};});
+}
diff --git a/3rdparty/pybind11/tests/test_stl_binders.py b/3rdparty/pybind11/tests/test_stl_binders.py
new file mode 100644
index 00000000..c7b7e853
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_stl_binders.py
@@ -0,0 +1,276 @@
+import pytest
+import sys
+from pybind11_tests import stl_binders as m
+
+with pytest.suppress(ImportError):
+ import numpy as np
+
+
+def test_vector_int():
+ v_int = m.VectorInt([0, 0])
+ assert len(v_int) == 2
+ assert bool(v_int) is True
+
+ # test construction from a generator
+ v_int1 = m.VectorInt(x for x in range(5))
+ assert v_int1 == m.VectorInt([0, 1, 2, 3, 4])
+
+ v_int2 = m.VectorInt([0, 0])
+ assert v_int == v_int2
+ v_int2[1] = 1
+ assert v_int != v_int2
+
+ v_int2.append(2)
+ v_int2.insert(0, 1)
+ v_int2.insert(0, 2)
+ v_int2.insert(0, 3)
+ v_int2.insert(6, 3)
+ assert str(v_int2) == "VectorInt[3, 2, 1, 0, 1, 2, 3]"
+ with pytest.raises(IndexError):
+ v_int2.insert(8, 4)
+
+ v_int.append(99)
+ v_int2[2:-2] = v_int
+ assert v_int2 == m.VectorInt([3, 2, 0, 0, 99, 2, 3])
+ del v_int2[1:3]
+ assert v_int2 == m.VectorInt([3, 0, 99, 2, 3])
+ del v_int2[0]
+ assert v_int2 == m.VectorInt([0, 99, 2, 3])
+
+ v_int2.extend(m.VectorInt([4, 5]))
+ assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5])
+
+ v_int2.extend([6, 7])
+ assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7])
+
+ # test error handling, and that the vector is unchanged
+ with pytest.raises(RuntimeError):
+ v_int2.extend([8, 'a'])
+
+ assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7])
+
+ # test extending from a generator
+ v_int2.extend(x for x in range(5))
+ assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4])
+
+ # test negative indexing
+ assert v_int2[-1] == 4
+
+ # insert with negative index
+ v_int2.insert(-1, 88)
+ assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 88, 4])
+
+ # delete negative index
+ del v_int2[-1]
+ assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 88])
+
+ v_int2.clear()
+ assert len(v_int2) == 0
+
+# related to the PyPy's buffer protocol.
+@pytest.unsupported_on_pypy
+def test_vector_buffer():
+ b = bytearray([1, 2, 3, 4])
+ v = m.VectorUChar(b)
+ assert v[1] == 2
+ v[2] = 5
+ mv = memoryview(v) # We expose the buffer interface
+ if sys.version_info.major > 2:
+ assert mv[2] == 5
+ mv[2] = 6
+ else:
+ assert mv[2] == '\x05'
+ mv[2] = '\x06'
+ assert v[2] == 6
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.create_undeclstruct() # Undeclared struct contents, no buffer interface
+ assert "NumPy type info missing for " in str(excinfo.value)
+
+
+@pytest.unsupported_on_pypy
+@pytest.requires_numpy
+def test_vector_buffer_numpy():
+ a = np.array([1, 2, 3, 4], dtype=np.int32)
+ with pytest.raises(TypeError):
+ m.VectorInt(a)
+
+ a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], dtype=np.uintc)
+ v = m.VectorInt(a[0, :])
+ assert len(v) == 4
+ assert v[2] == 3
+ ma = np.asarray(v)
+ ma[2] = 5
+ assert v[2] == 5
+
+ v = m.VectorInt(a[:, 1])
+ assert len(v) == 3
+ assert v[2] == 10
+
+ v = m.get_vectorstruct()
+ assert v[0].x == 5
+ ma = np.asarray(v)
+ ma[1]['x'] = 99
+ assert v[1].x == 99
+
+ v = m.VectorStruct(np.zeros(3, dtype=np.dtype([('w', 'bool'), ('x', 'I'),
+ ('y', 'float64'), ('z', 'bool')], align=True)))
+ assert len(v) == 3
+
+
+def test_vector_bool():
+ import pybind11_cross_module_tests as cm
+
+ vv_c = cm.VectorBool()
+ for i in range(10):
+ vv_c.append(i % 2 == 0)
+ for i in range(10):
+ assert vv_c[i] == (i % 2 == 0)
+ assert str(vv_c) == "VectorBool[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]"
+
+
+def test_vector_custom():
+ v_a = m.VectorEl()
+ v_a.append(m.El(1))
+ v_a.append(m.El(2))
+ assert str(v_a) == "VectorEl[El{1}, El{2}]"
+
+ vv_a = m.VectorVectorEl()
+ vv_a.append(v_a)
+ vv_b = vv_a[0]
+ assert str(vv_b) == "VectorEl[El{1}, El{2}]"
+
+
+def test_map_string_double():
+ mm = m.MapStringDouble()
+ mm['a'] = 1
+ mm['b'] = 2.5
+
+ assert list(mm) == ['a', 'b']
+ assert list(mm.items()) == [('a', 1), ('b', 2.5)]
+ assert str(mm) == "MapStringDouble{a: 1, b: 2.5}"
+
+ um = m.UnorderedMapStringDouble()
+ um['ua'] = 1.1
+ um['ub'] = 2.6
+
+ assert sorted(list(um)) == ['ua', 'ub']
+ assert sorted(list(um.items())) == [('ua', 1.1), ('ub', 2.6)]
+ assert "UnorderedMapStringDouble" in str(um)
+
+
+def test_map_string_double_const():
+ mc = m.MapStringDoubleConst()
+ mc['a'] = 10
+ mc['b'] = 20.5
+ assert str(mc) == "MapStringDoubleConst{a: 10, b: 20.5}"
+
+ umc = m.UnorderedMapStringDoubleConst()
+ umc['a'] = 11
+ umc['b'] = 21.5
+
+ str(umc)
+
+
+def test_noncopyable_containers():
+ # std::vector
+ vnc = m.get_vnc(5)
+ for i in range(0, 5):
+ assert vnc[i].value == i + 1
+
+ for i, j in enumerate(vnc, start=1):
+ assert j.value == i
+
+ # std::deque
+ dnc = m.get_dnc(5)
+ for i in range(0, 5):
+ assert dnc[i].value == i + 1
+
+ i = 1
+ for j in dnc:
+ assert(j.value == i)
+ i += 1
+
+ # std::map
+ mnc = m.get_mnc(5)
+ for i in range(1, 6):
+ assert mnc[i].value == 10 * i
+
+ vsum = 0
+ for k, v in mnc.items():
+ assert v.value == 10 * k
+ vsum += v.value
+
+ assert vsum == 150
+
+ # std::unordered_map
+ mnc = m.get_umnc(5)
+ for i in range(1, 6):
+ assert mnc[i].value == 10 * i
+
+ vsum = 0
+ for k, v in mnc.items():
+ assert v.value == 10 * k
+ vsum += v.value
+
+ assert vsum == 150
+
+ # nested std::map<std::vector>
+ nvnc = m.get_nvnc(5)
+ for i in range(1, 6):
+ for j in range(0, 5):
+ assert nvnc[i][j].value == j + 1
+
+ for k, v in nvnc.items():
+ for i, j in enumerate(v, start=1):
+ assert j.value == i
+
+ # nested std::map<std::map>
+ nmnc = m.get_nmnc(5)
+ for i in range(1, 6):
+ for j in range(10, 60, 10):
+ assert nmnc[i][j].value == 10 * j
+
+ vsum = 0
+ for k_o, v_o in nmnc.items():
+ for k_i, v_i in v_o.items():
+ assert v_i.value == 10 * k_i
+ vsum += v_i.value
+
+ assert vsum == 7500
+
+ # nested std::unordered_map<std::unordered_map>
+ numnc = m.get_numnc(5)
+ for i in range(1, 6):
+ for j in range(10, 60, 10):
+ assert numnc[i][j].value == 10 * j
+
+ vsum = 0
+ for k_o, v_o in numnc.items():
+ for k_i, v_i in v_o.items():
+ assert v_i.value == 10 * k_i
+ vsum += v_i.value
+
+ assert vsum == 7500
+
+
+def test_map_delitem():
+ mm = m.MapStringDouble()
+ mm['a'] = 1
+ mm['b'] = 2.5
+
+ assert list(mm) == ['a', 'b']
+ assert list(mm.items()) == [('a', 1), ('b', 2.5)]
+ del mm['a']
+ assert list(mm) == ['b']
+ assert list(mm.items()) == [('b', 2.5)]
+
+ um = m.UnorderedMapStringDouble()
+ um['ua'] = 1.1
+ um['ub'] = 2.6
+
+ assert sorted(list(um)) == ['ua', 'ub']
+ assert sorted(list(um.items())) == [('ua', 1.1), ('ub', 2.6)]
+ del um['ua']
+ assert sorted(list(um)) == ['ub']
+ assert sorted(list(um.items())) == [('ub', 2.6)]
diff --git a/3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp b/3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp
new file mode 100644
index 00000000..272e460c
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp
@@ -0,0 +1,136 @@
+/*
+ tests/test_tagbased_polymorphic.cpp -- test of polymorphic_type_hook
+
+ Copyright (c) 2018 Hudson River Trading LLC <opensource@hudson-trading.com>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include <pybind11/stl.h>
+
+struct Animal
+{
+ enum class Kind {
+ Unknown = 0,
+ Dog = 100, Labrador, Chihuahua, LastDog = 199,
+ Cat = 200, Panther, LastCat = 299
+ };
+ static const std::type_info* type_of_kind(Kind kind);
+ static std::string name_of_kind(Kind kind);
+
+ const Kind kind;
+ const std::string name;
+
+ protected:
+ Animal(const std::string& _name, Kind _kind)
+ : kind(_kind), name(_name)
+ {}
+};
+
+struct Dog : Animal
+{
+ Dog(const std::string& _name, Kind _kind = Kind::Dog) : Animal(_name, _kind) {}
+ std::string bark() const { return name_of_kind(kind) + " " + name + " goes " + sound; }
+ std::string sound = "WOOF!";
+};
+
+struct Labrador : Dog
+{
+ Labrador(const std::string& _name, int _excitement = 9001)
+ : Dog(_name, Kind::Labrador), excitement(_excitement) {}
+ int excitement;
+};
+
+struct Chihuahua : Dog
+{
+ Chihuahua(const std::string& _name) : Dog(_name, Kind::Chihuahua) { sound = "iyiyiyiyiyi"; }
+ std::string bark() const { return Dog::bark() + " and runs in circles"; }
+};
+
+struct Cat : Animal
+{
+ Cat(const std::string& _name, Kind _kind = Kind::Cat) : Animal(_name, _kind) {}
+ std::string purr() const { return "mrowr"; }
+};
+
+struct Panther : Cat
+{
+ Panther(const std::string& _name) : Cat(_name, Kind::Panther) {}
+ std::string purr() const { return "mrrrRRRRRR"; }
+};
+
+std::vector<std::unique_ptr<Animal>> create_zoo()
+{
+ std::vector<std::unique_ptr<Animal>> ret;
+ ret.emplace_back(new Labrador("Fido", 15000));
+
+ // simulate some new type of Dog that the Python bindings
+ // haven't been updated for; it should still be considered
+ // a Dog, not just an Animal.
+ ret.emplace_back(new Dog("Ginger", Dog::Kind(150)));
+
+ ret.emplace_back(new Chihuahua("Hertzl"));
+ ret.emplace_back(new Cat("Tiger", Cat::Kind::Cat));
+ ret.emplace_back(new Panther("Leo"));
+ return ret;
+}
+
+const std::type_info* Animal::type_of_kind(Kind kind)
+{
+ switch (kind) {
+ case Kind::Unknown: break;
+
+ case Kind::Dog: break;
+ case Kind::Labrador: return &typeid(Labrador);
+ case Kind::Chihuahua: return &typeid(Chihuahua);
+ case Kind::LastDog: break;
+
+ case Kind::Cat: break;
+ case Kind::Panther: return &typeid(Panther);
+ case Kind::LastCat: break;
+ }
+
+ if (kind >= Kind::Dog && kind <= Kind::LastDog) return &typeid(Dog);
+ if (kind >= Kind::Cat && kind <= Kind::LastCat) return &typeid(Cat);
+ return nullptr;
+}
+
+std::string Animal::name_of_kind(Kind kind)
+{
+ std::string raw_name = type_of_kind(kind)->name();
+ py::detail::clean_type_id(raw_name);
+ return raw_name;
+}
+
+namespace pybind11 {
+ template <typename itype>
+ struct polymorphic_type_hook<itype, detail::enable_if_t<std::is_base_of<Animal, itype>::value>>
+ {
+ static const void *get(const itype *src, const std::type_info*& type)
+ { type = src ? Animal::type_of_kind(src->kind) : nullptr; return src; }
+ };
+}
+
+TEST_SUBMODULE(tagbased_polymorphic, m) {
+ py::class_<Animal>(m, "Animal")
+ .def_readonly("name", &Animal::name);
+ py::class_<Dog, Animal>(m, "Dog")
+ .def(py::init<std::string>())
+ .def_readwrite("sound", &Dog::sound)
+ .def("bark", &Dog::bark);
+ py::class_<Labrador, Dog>(m, "Labrador")
+ .def(py::init<std::string, int>(), "name"_a, "excitement"_a = 9001)
+ .def_readwrite("excitement", &Labrador::excitement);
+ py::class_<Chihuahua, Dog>(m, "Chihuahua")
+ .def(py::init<std::string>())
+ .def("bark", &Chihuahua::bark);
+ py::class_<Cat, Animal>(m, "Cat")
+ .def(py::init<std::string>())
+ .def("purr", &Cat::purr);
+ py::class_<Panther, Cat>(m, "Panther")
+ .def(py::init<std::string>())
+ .def("purr", &Panther::purr);
+ m.def("create_zoo", &create_zoo);
+};
diff --git a/3rdparty/pybind11/tests/test_tagbased_polymorphic.py b/3rdparty/pybind11/tests/test_tagbased_polymorphic.py
new file mode 100644
index 00000000..2574d7de
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_tagbased_polymorphic.py
@@ -0,0 +1,20 @@
+from pybind11_tests import tagbased_polymorphic as m
+
+
+def test_downcast():
+ zoo = m.create_zoo()
+ assert [type(animal) for animal in zoo] == [
+ m.Labrador, m.Dog, m.Chihuahua, m.Cat, m.Panther
+ ]
+ assert [animal.name for animal in zoo] == [
+ "Fido", "Ginger", "Hertzl", "Tiger", "Leo"
+ ]
+ zoo[1].sound = "woooooo"
+ assert [dog.bark() for dog in zoo[:3]] == [
+ "Labrador Fido goes WOOF!",
+ "Dog Ginger goes woooooo",
+ "Chihuahua Hertzl goes iyiyiyiyiyi and runs in circles"
+ ]
+ assert [cat.purr() for cat in zoo[3:]] == ["mrowr", "mrrrRRRRRR"]
+ zoo[0].excitement -= 1000
+ assert zoo[0].excitement == 14000
diff --git a/3rdparty/pybind11/tests/test_union.cpp b/3rdparty/pybind11/tests/test_union.cpp
new file mode 100644
index 00000000..7b98ea21
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_union.cpp
@@ -0,0 +1,22 @@
+/*
+ tests/test_class.cpp -- test py::class_ definitions and basic functionality
+
+ Copyright (c) 2019 Roland Dreier <roland.dreier@gmail.com>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+TEST_SUBMODULE(union_, m) {
+ union TestUnion {
+ int value_int;
+ unsigned value_uint;
+ };
+
+ py::class_<TestUnion>(m, "TestUnion")
+ .def(py::init<>())
+ .def_readonly("as_int", &TestUnion::value_int)
+ .def_readwrite("as_uint", &TestUnion::value_uint);
+}
diff --git a/3rdparty/pybind11/tests/test_union.py b/3rdparty/pybind11/tests/test_union.py
new file mode 100644
index 00000000..e1866e70
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_union.py
@@ -0,0 +1,8 @@
+from pybind11_tests import union_ as m
+
+
+def test_union():
+ instance = m.TestUnion()
+
+ instance.as_uint = 10
+ assert instance.as_int == 10
diff --git a/3rdparty/pybind11/tests/test_virtual_functions.cpp b/3rdparty/pybind11/tests/test_virtual_functions.cpp
new file mode 100644
index 00000000..ccf018d9
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_virtual_functions.cpp
@@ -0,0 +1,479 @@
+/*
+ tests/test_virtual_functions.cpp -- overriding virtual functions from Python
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/functional.h>
+#include <thread>
+
+/* This is an example class that we'll want to be able to extend from Python */
+class ExampleVirt {
+public:
+ ExampleVirt(int state) : state(state) { print_created(this, state); }
+ ExampleVirt(const ExampleVirt &e) : state(e.state) { print_copy_created(this); }
+ ExampleVirt(ExampleVirt &&e) : state(e.state) { print_move_created(this); e.state = 0; }
+ virtual ~ExampleVirt() { print_destroyed(this); }
+
+ virtual int run(int value) {
+ py::print("Original implementation of "
+ "ExampleVirt::run(state={}, value={}, str1={}, str2={})"_s.format(state, value, get_string1(), *get_string2()));
+ return state + value;
+ }
+
+ virtual bool run_bool() = 0;
+ virtual void pure_virtual() = 0;
+
+ // Returning a reference/pointer to a type converted from python (numbers, strings, etc.) is a
+ // bit trickier, because the actual int& or std::string& or whatever only exists temporarily, so
+ // we have to handle it specially in the trampoline class (see below).
+ virtual const std::string &get_string1() { return str1; }
+ virtual const std::string *get_string2() { return &str2; }
+
+private:
+ int state;
+ const std::string str1{"default1"}, str2{"default2"};
+};
+
+/* This is a wrapper class that must be generated */
+class PyExampleVirt : public ExampleVirt {
+public:
+ using ExampleVirt::ExampleVirt; /* Inherit constructors */
+
+ int run(int value) override {
+ /* Generate wrapping code that enables native function overloading */
+ PYBIND11_OVERLOAD(
+ int, /* Return type */
+ ExampleVirt, /* Parent class */
+ run, /* Name of function */
+ value /* Argument(s) */
+ );
+ }
+
+ bool run_bool() override {
+ PYBIND11_OVERLOAD_PURE(
+ bool, /* Return type */
+ ExampleVirt, /* Parent class */
+ run_bool, /* Name of function */
+ /* This function has no arguments. The trailing comma
+ in the previous line is needed for some compilers */
+ );
+ }
+
+ void pure_virtual() override {
+ PYBIND11_OVERLOAD_PURE(
+ void, /* Return type */
+ ExampleVirt, /* Parent class */
+ pure_virtual, /* Name of function */
+ /* This function has no arguments. The trailing comma
+ in the previous line is needed for some compilers */
+ );
+ }
+
+ // We can return reference types for compatibility with C++ virtual interfaces that do so, but
+ // note they have some significant limitations (see the documentation).
+ const std::string &get_string1() override {
+ PYBIND11_OVERLOAD(
+ const std::string &, /* Return type */
+ ExampleVirt, /* Parent class */
+ get_string1, /* Name of function */
+ /* (no arguments) */
+ );
+ }
+
+ const std::string *get_string2() override {
+ PYBIND11_OVERLOAD(
+ const std::string *, /* Return type */
+ ExampleVirt, /* Parent class */
+ get_string2, /* Name of function */
+ /* (no arguments) */
+ );
+ }
+
+};
+
+class NonCopyable {
+public:
+ NonCopyable(int a, int b) : value{new int(a*b)} { print_created(this, a, b); }
+ NonCopyable(NonCopyable &&o) { value = std::move(o.value); print_move_created(this); }
+ NonCopyable(const NonCopyable &) = delete;
+ NonCopyable() = delete;
+ void operator=(const NonCopyable &) = delete;
+ void operator=(NonCopyable &&) = delete;
+ std::string get_value() const {
+ if (value) return std::to_string(*value); else return "(null)";
+ }
+ ~NonCopyable() { print_destroyed(this); }
+
+private:
+ std::unique_ptr<int> value;
+};
+
+// This is like the above, but is both copy and movable. In effect this means it should get moved
+// when it is not referenced elsewhere, but copied if it is still referenced.
+class Movable {
+public:
+ Movable(int a, int b) : value{a+b} { print_created(this, a, b); }
+ Movable(const Movable &m) { value = m.value; print_copy_created(this); }
+ Movable(Movable &&m) { value = std::move(m.value); print_move_created(this); }
+ std::string get_value() const { return std::to_string(value); }
+ ~Movable() { print_destroyed(this); }
+private:
+ int value;
+};
+
+class NCVirt {
+public:
+ virtual ~NCVirt() { }
+ virtual NonCopyable get_noncopyable(int a, int b) { return NonCopyable(a, b); }
+ virtual Movable get_movable(int a, int b) = 0;
+
+ std::string print_nc(int a, int b) { return get_noncopyable(a, b).get_value(); }
+ std::string print_movable(int a, int b) { return get_movable(a, b).get_value(); }
+};
+class NCVirtTrampoline : public NCVirt {
+#if !defined(__INTEL_COMPILER)
+ NonCopyable get_noncopyable(int a, int b) override {
+ PYBIND11_OVERLOAD(NonCopyable, NCVirt, get_noncopyable, a, b);
+ }
+#endif
+ Movable get_movable(int a, int b) override {
+ PYBIND11_OVERLOAD_PURE(Movable, NCVirt, get_movable, a, b);
+ }
+};
+
+struct Base {
+ /* for some reason MSVC2015 can't compile this if the function is pure virtual */
+ virtual std::string dispatch() const { return {}; };
+ virtual ~Base() = default;
+};
+
+struct DispatchIssue : Base {
+ virtual std::string dispatch() const {
+ PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
+ }
+};
+
+static void test_gil() {
+ {
+ py::gil_scoped_acquire lock;
+ py::print("1st lock acquired");
+
+ }
+
+ {
+ py::gil_scoped_acquire lock;
+ py::print("2nd lock acquired");
+ }
+
+}
+
+static void test_gil_from_thread() {
+ py::gil_scoped_release release;
+
+ std::thread t(test_gil);
+ t.join();
+}
+
+
+// Forward declaration (so that we can put the main tests here; the inherited virtual approaches are
+// rather long).
+void initialize_inherited_virtuals(py::module &m);
+
+TEST_SUBMODULE(virtual_functions, m) {
+ // test_override
+ py::class_<ExampleVirt, PyExampleVirt>(m, "ExampleVirt")
+ .def(py::init<int>())
+ /* Reference original class in function definitions */
+ .def("run", &ExampleVirt::run)
+ .def("run_bool", &ExampleVirt::run_bool)
+ .def("pure_virtual", &ExampleVirt::pure_virtual);
+
+ py::class_<NonCopyable>(m, "NonCopyable")
+ .def(py::init<int, int>());
+
+ py::class_<Movable>(m, "Movable")
+ .def(py::init<int, int>());
+
+ // test_move_support
+#if !defined(__INTEL_COMPILER)
+ py::class_<NCVirt, NCVirtTrampoline>(m, "NCVirt")
+ .def(py::init<>())
+ .def("get_noncopyable", &NCVirt::get_noncopyable)
+ .def("get_movable", &NCVirt::get_movable)
+ .def("print_nc", &NCVirt::print_nc)
+ .def("print_movable", &NCVirt::print_movable);
+#endif
+
+ m.def("runExampleVirt", [](ExampleVirt *ex, int value) { return ex->run(value); });
+ m.def("runExampleVirtBool", [](ExampleVirt* ex) { return ex->run_bool(); });
+ m.def("runExampleVirtVirtual", [](ExampleVirt *ex) { ex->pure_virtual(); });
+
+ m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
+ initialize_inherited_virtuals(m);
+
+ // test_alias_delay_initialization1
+ // don't invoke Python dispatch classes by default when instantiating C++ classes
+ // that were not extended on the Python side
+ struct A {
+ virtual ~A() {}
+ virtual void f() { py::print("A.f()"); }
+ };
+
+ struct PyA : A {
+ PyA() { py::print("PyA.PyA()"); }
+ ~PyA() { py::print("PyA.~PyA()"); }
+
+ void f() override {
+ py::print("PyA.f()");
+ // This convolution just gives a `void`, but tests that PYBIND11_TYPE() works to protect
+ // a type containing a ,
+ PYBIND11_OVERLOAD(PYBIND11_TYPE(typename std::enable_if<true, void>::type), A, f);
+ }
+ };
+
+ py::class_<A, PyA>(m, "A")
+ .def(py::init<>())
+ .def("f", &A::f);
+
+ m.def("call_f", [](A *a) { a->f(); });
+
+ // test_alias_delay_initialization2
+ // ... unless we explicitly request it, as in this example:
+ struct A2 {
+ virtual ~A2() {}
+ virtual void f() { py::print("A2.f()"); }
+ };
+
+ struct PyA2 : A2 {
+ PyA2() { py::print("PyA2.PyA2()"); }
+ ~PyA2() { py::print("PyA2.~PyA2()"); }
+ void f() override {
+ py::print("PyA2.f()");
+ PYBIND11_OVERLOAD(void, A2, f);
+ }
+ };
+
+ py::class_<A2, PyA2>(m, "A2")
+ .def(py::init_alias<>())
+ .def(py::init([](int) { return new PyA2(); }))
+ .def("f", &A2::f);
+
+ m.def("call_f", [](A2 *a2) { a2->f(); });
+
+ // test_dispatch_issue
+ // #159: virtual function dispatch has problems with similar-named functions
+ py::class_<Base, DispatchIssue>(m, "DispatchIssue")
+ .def(py::init<>())
+ .def("dispatch", &Base::dispatch);
+
+ m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
+
+ // test_override_ref
+ // #392/397: overriding reference-returning functions
+ class OverrideTest {
+ public:
+ struct A { std::string value = "hi"; };
+ std::string v;
+ A a;
+ explicit OverrideTest(const std::string &v) : v{v} {}
+ virtual std::string str_value() { return v; }
+ virtual std::string &str_ref() { return v; }
+ virtual A A_value() { return a; }
+ virtual A &A_ref() { return a; }
+ virtual ~OverrideTest() = default;
+ };
+
+ class PyOverrideTest : public OverrideTest {
+ public:
+ using OverrideTest::OverrideTest;
+ std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
+ // Not allowed (uncommenting should hit a static_assert failure): we can't get a reference
+ // to a python numeric value, since we only copy values in the numeric type caster:
+// std::string &str_ref() override { PYBIND11_OVERLOAD(std::string &, OverrideTest, str_ref); }
+ // But we can work around it like this:
+ private:
+ std::string _tmp;
+ std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); }
+ public:
+ std::string &str_ref() override { return _tmp = str_ref_helper(); }
+
+ A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); }
+ A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); }
+ };
+
+ py::class_<OverrideTest::A>(m, "OverrideTest_A")
+ .def_readwrite("value", &OverrideTest::A::value);
+ py::class_<OverrideTest, PyOverrideTest>(m, "OverrideTest")
+ .def(py::init<const std::string &>())
+ .def("str_value", &OverrideTest::str_value)
+// .def("str_ref", &OverrideTest::str_ref)
+ .def("A_value", &OverrideTest::A_value)
+ .def("A_ref", &OverrideTest::A_ref);
+}
+
+
+// Inheriting virtual methods. We do two versions here: the repeat-everything version and the
+// templated trampoline versions mentioned in docs/advanced.rst.
+//
+// These base classes are exactly the same, but we technically need distinct
+// classes for this example code because we need to be able to bind them
+// properly (pybind11, sensibly, doesn't allow us to bind the same C++ class to
+// multiple python classes).
+class A_Repeat {
+#define A_METHODS \
+public: \
+ virtual int unlucky_number() = 0; \
+ virtual std::string say_something(unsigned times) { \
+ std::string s = ""; \
+ for (unsigned i = 0; i < times; ++i) \
+ s += "hi"; \
+ return s; \
+ } \
+ std::string say_everything() { \
+ return say_something(1) + " " + std::to_string(unlucky_number()); \
+ }
+A_METHODS
+ virtual ~A_Repeat() = default;
+};
+class B_Repeat : public A_Repeat {
+#define B_METHODS \
+public: \
+ int unlucky_number() override { return 13; } \
+ std::string say_something(unsigned times) override { \
+ return "B says hi " + std::to_string(times) + " times"; \
+ } \
+ virtual double lucky_number() { return 7.0; }
+B_METHODS
+};
+class C_Repeat : public B_Repeat {
+#define C_METHODS \
+public: \
+ int unlucky_number() override { return 4444; } \
+ double lucky_number() override { return 888; }
+C_METHODS
+};
+class D_Repeat : public C_Repeat {
+#define D_METHODS // Nothing overridden.
+D_METHODS
+};
+
+// Base classes for templated inheritance trampolines. Identical to the repeat-everything version:
+class A_Tpl { A_METHODS; virtual ~A_Tpl() = default; };
+class B_Tpl : public A_Tpl { B_METHODS };
+class C_Tpl : public B_Tpl { C_METHODS };
+class D_Tpl : public C_Tpl { D_METHODS };
+
+
+// Inheritance approach 1: each trampoline gets every virtual method (11 in total)
+class PyA_Repeat : public A_Repeat {
+public:
+ using A_Repeat::A_Repeat;
+ int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, A_Repeat, unlucky_number, ); }
+ std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, A_Repeat, say_something, times); }
+};
+class PyB_Repeat : public B_Repeat {
+public:
+ using B_Repeat::B_Repeat;
+ int unlucky_number() override { PYBIND11_OVERLOAD(int, B_Repeat, unlucky_number, ); }
+ std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, B_Repeat, say_something, times); }
+ double lucky_number() override { PYBIND11_OVERLOAD(double, B_Repeat, lucky_number, ); }
+};
+class PyC_Repeat : public C_Repeat {
+public:
+ using C_Repeat::C_Repeat;
+ int unlucky_number() override { PYBIND11_OVERLOAD(int, C_Repeat, unlucky_number, ); }
+ std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, C_Repeat, say_something, times); }
+ double lucky_number() override { PYBIND11_OVERLOAD(double, C_Repeat, lucky_number, ); }
+};
+class PyD_Repeat : public D_Repeat {
+public:
+ using D_Repeat::D_Repeat;
+ int unlucky_number() override { PYBIND11_OVERLOAD(int, D_Repeat, unlucky_number, ); }
+ std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, D_Repeat, say_something, times); }
+ double lucky_number() override { PYBIND11_OVERLOAD(double, D_Repeat, lucky_number, ); }
+};
+
+// Inheritance approach 2: templated trampoline classes.
+//
+// Advantages:
+// - we have only 2 (template) class and 4 method declarations (one per virtual method, plus one for
+// any override of a pure virtual method), versus 4 classes and 6 methods (MI) or 4 classes and 11
+// methods (repeat).
+// - Compared to MI, we also don't have to change the non-trampoline inheritance to virtual, and can
+// properly inherit constructors.
+//
+// Disadvantage:
+// - the compiler must still generate and compile 14 different methods (more, even, than the 11
+// required for the repeat approach) instead of the 6 required for MI. (If there was no pure
+// method (or no pure method override), the number would drop down to the same 11 as the repeat
+// approach).
+template <class Base = A_Tpl>
+class PyA_Tpl : public Base {
+public:
+ using Base::Base; // Inherit constructors
+ int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, Base, unlucky_number, ); }
+ std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, Base, say_something, times); }
+};
+template <class Base = B_Tpl>
+class PyB_Tpl : public PyA_Tpl<Base> {
+public:
+ using PyA_Tpl<Base>::PyA_Tpl; // Inherit constructors (via PyA_Tpl's inherited constructors)
+ int unlucky_number() override { PYBIND11_OVERLOAD(int, Base, unlucky_number, ); }
+ double lucky_number() override { PYBIND11_OVERLOAD(double, Base, lucky_number, ); }
+};
+// Since C_Tpl and D_Tpl don't declare any new virtual methods, we don't actually need these (we can
+// use PyB_Tpl<C_Tpl> and PyB_Tpl<D_Tpl> for the trampoline classes instead):
+/*
+template <class Base = C_Tpl> class PyC_Tpl : public PyB_Tpl<Base> {
+public:
+ using PyB_Tpl<Base>::PyB_Tpl;
+};
+template <class Base = D_Tpl> class PyD_Tpl : public PyC_Tpl<Base> {
+public:
+ using PyC_Tpl<Base>::PyC_Tpl;
+};
+*/
+
+void initialize_inherited_virtuals(py::module &m) {
+ // test_inherited_virtuals
+
+ // Method 1: repeat
+ py::class_<A_Repeat, PyA_Repeat>(m, "A_Repeat")
+ .def(py::init<>())
+ .def("unlucky_number", &A_Repeat::unlucky_number)
+ .def("say_something", &A_Repeat::say_something)
+ .def("say_everything", &A_Repeat::say_everything);
+ py::class_<B_Repeat, A_Repeat, PyB_Repeat>(m, "B_Repeat")
+ .def(py::init<>())
+ .def("lucky_number", &B_Repeat::lucky_number);
+ py::class_<C_Repeat, B_Repeat, PyC_Repeat>(m, "C_Repeat")
+ .def(py::init<>());
+ py::class_<D_Repeat, C_Repeat, PyD_Repeat>(m, "D_Repeat")
+ .def(py::init<>());
+
+ // test_
+ // Method 2: Templated trampolines
+ py::class_<A_Tpl, PyA_Tpl<>>(m, "A_Tpl")
+ .def(py::init<>())
+ .def("unlucky_number", &A_Tpl::unlucky_number)
+ .def("say_something", &A_Tpl::say_something)
+ .def("say_everything", &A_Tpl::say_everything);
+ py::class_<B_Tpl, A_Tpl, PyB_Tpl<>>(m, "B_Tpl")
+ .def(py::init<>())
+ .def("lucky_number", &B_Tpl::lucky_number);
+ py::class_<C_Tpl, B_Tpl, PyB_Tpl<C_Tpl>>(m, "C_Tpl")
+ .def(py::init<>());
+ py::class_<D_Tpl, C_Tpl, PyB_Tpl<D_Tpl>>(m, "D_Tpl")
+ .def(py::init<>());
+
+
+ // Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
+ m.def("test_gil", &test_gil);
+ m.def("test_gil_from_thread", &test_gil_from_thread);
+};
diff --git a/3rdparty/pybind11/tests/test_virtual_functions.py b/3rdparty/pybind11/tests/test_virtual_functions.py
new file mode 100644
index 00000000..5ce9abd3
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_virtual_functions.py
@@ -0,0 +1,377 @@
+import pytest
+
+from pybind11_tests import virtual_functions as m
+from pybind11_tests import ConstructorStats
+
+
+def test_override(capture, msg):
+ class ExtendedExampleVirt(m.ExampleVirt):
+ def __init__(self, state):
+ super(ExtendedExampleVirt, self).__init__(state + 1)
+ self.data = "Hello world"
+
+ def run(self, value):
+ print('ExtendedExampleVirt::run(%i), calling parent..' % value)
+ return super(ExtendedExampleVirt, self).run(value + 1)
+
+ def run_bool(self):
+ print('ExtendedExampleVirt::run_bool()')
+ return False
+
+ def get_string1(self):
+ return "override1"
+
+ def pure_virtual(self):
+ print('ExtendedExampleVirt::pure_virtual(): %s' % self.data)
+
+ class ExtendedExampleVirt2(ExtendedExampleVirt):
+ def __init__(self, state):
+ super(ExtendedExampleVirt2, self).__init__(state + 1)
+
+ def get_string2(self):
+ return "override2"
+
+ ex12 = m.ExampleVirt(10)
+ with capture:
+ assert m.runExampleVirt(ex12, 20) == 30
+ assert capture == """
+ Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)
+ """ # noqa: E501 line too long
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.runExampleVirtVirtual(ex12)
+ assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
+
+ ex12p = ExtendedExampleVirt(10)
+ with capture:
+ assert m.runExampleVirt(ex12p, 20) == 32
+ assert capture == """
+ ExtendedExampleVirt::run(20), calling parent..
+ Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)
+ """ # noqa: E501 line too long
+ with capture:
+ assert m.runExampleVirtBool(ex12p) is False
+ assert capture == "ExtendedExampleVirt::run_bool()"
+ with capture:
+ m.runExampleVirtVirtual(ex12p)
+ assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world"
+
+ ex12p2 = ExtendedExampleVirt2(15)
+ with capture:
+ assert m.runExampleVirt(ex12p2, 50) == 68
+ assert capture == """
+ ExtendedExampleVirt::run(50), calling parent..
+ Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)
+ """ # noqa: E501 line too long
+
+ cstats = ConstructorStats.get(m.ExampleVirt)
+ assert cstats.alive() == 3
+ del ex12, ex12p, ex12p2
+ assert cstats.alive() == 0
+ assert cstats.values() == ['10', '11', '17']
+ assert cstats.copy_constructions == 0
+ assert cstats.move_constructions >= 0
+
+
+def test_alias_delay_initialization1(capture):
+ """`A` only initializes its trampoline class when we inherit from it
+
+ If we just create and use an A instance directly, the trampoline initialization is
+ bypassed and we only initialize an A() instead (for performance reasons).
+ """
+ class B(m.A):
+ def __init__(self):
+ super(B, self).__init__()
+
+ def f(self):
+ print("In python f()")
+
+ # C++ version
+ with capture:
+ a = m.A()
+ m.call_f(a)
+ del a
+ pytest.gc_collect()
+ assert capture == "A.f()"
+
+ # Python version
+ with capture:
+ b = B()
+ m.call_f(b)
+ del b
+ pytest.gc_collect()
+ assert capture == """
+ PyA.PyA()
+ PyA.f()
+ In python f()
+ PyA.~PyA()
+ """
+
+
+def test_alias_delay_initialization2(capture):
+ """`A2`, unlike the above, is configured to always initialize the alias
+
+ While the extra initialization and extra class layer has small virtual dispatch
+ performance penalty, it also allows us to do more things with the trampoline
+ class such as defining local variables and performing construction/destruction.
+ """
+ class B2(m.A2):
+ def __init__(self):
+ super(B2, self).__init__()
+
+ def f(self):
+ print("In python B2.f()")
+
+ # No python subclass version
+ with capture:
+ a2 = m.A2()
+ m.call_f(a2)
+ del a2
+ pytest.gc_collect()
+ a3 = m.A2(1)
+ m.call_f(a3)
+ del a3
+ pytest.gc_collect()
+ assert capture == """
+ PyA2.PyA2()
+ PyA2.f()
+ A2.f()
+ PyA2.~PyA2()
+ PyA2.PyA2()
+ PyA2.f()
+ A2.f()
+ PyA2.~PyA2()
+ """
+
+ # Python subclass version
+ with capture:
+ b2 = B2()
+ m.call_f(b2)
+ del b2
+ pytest.gc_collect()
+ assert capture == """
+ PyA2.PyA2()
+ PyA2.f()
+ In python B2.f()
+ PyA2.~PyA2()
+ """
+
+
+# PyPy: Reference count > 1 causes call with noncopyable instance
+# to fail in ncv1.print_nc()
+@pytest.unsupported_on_pypy
+@pytest.mark.skipif(not hasattr(m, "NCVirt"), reason="NCVirt test broken on ICPC")
+def test_move_support():
+ class NCVirtExt(m.NCVirt):
+ def get_noncopyable(self, a, b):
+ # Constructs and returns a new instance:
+ nc = m.NonCopyable(a * a, b * b)
+ return nc
+
+ def get_movable(self, a, b):
+ # Return a referenced copy
+ self.movable = m.Movable(a, b)
+ return self.movable
+
+ class NCVirtExt2(m.NCVirt):
+ def get_noncopyable(self, a, b):
+ # Keep a reference: this is going to throw an exception
+ self.nc = m.NonCopyable(a, b)
+ return self.nc
+
+ def get_movable(self, a, b):
+ # Return a new instance without storing it
+ return m.Movable(a, b)
+
+ ncv1 = NCVirtExt()
+ assert ncv1.print_nc(2, 3) == "36"
+ assert ncv1.print_movable(4, 5) == "9"
+ ncv2 = NCVirtExt2()
+ assert ncv2.print_movable(7, 7) == "14"
+ # Don't check the exception message here because it differs under debug/non-debug mode
+ with pytest.raises(RuntimeError):
+ ncv2.print_nc(9, 9)
+
+ nc_stats = ConstructorStats.get(m.NonCopyable)
+ mv_stats = ConstructorStats.get(m.Movable)
+ assert nc_stats.alive() == 1
+ assert mv_stats.alive() == 1
+ del ncv1, ncv2
+ assert nc_stats.alive() == 0
+ assert mv_stats.alive() == 0
+ assert nc_stats.values() == ['4', '9', '9', '9']
+ assert mv_stats.values() == ['4', '5', '7', '7']
+ assert nc_stats.copy_constructions == 0
+ assert mv_stats.copy_constructions == 1
+ assert nc_stats.move_constructions >= 0
+ assert mv_stats.move_constructions >= 0
+
+
+def test_dispatch_issue(msg):
+ """#159: virtual function dispatch has problems with similar-named functions"""
+ class PyClass1(m.DispatchIssue):
+ def dispatch(self):
+ return "Yay.."
+
+ class PyClass2(m.DispatchIssue):
+ def dispatch(self):
+ with pytest.raises(RuntimeError) as excinfo:
+ super(PyClass2, self).dispatch()
+ assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
+
+ p = PyClass1()
+ return m.dispatch_issue_go(p)
+
+ b = PyClass2()
+ assert m.dispatch_issue_go(b) == "Yay.."
+
+
+def test_override_ref():
+ """#392/397: overriding reference-returning functions"""
+ o = m.OverrideTest("asdf")
+
+ # Not allowed (see associated .cpp comment)
+ # i = o.str_ref()
+ # assert o.str_ref() == "asdf"
+ assert o.str_value() == "asdf"
+
+ assert o.A_value().value == "hi"
+ a = o.A_ref()
+ assert a.value == "hi"
+ a.value = "bye"
+ assert a.value == "bye"
+
+
+def test_inherited_virtuals():
+ class AR(m.A_Repeat):
+ def unlucky_number(self):
+ return 99
+
+ class AT(m.A_Tpl):
+ def unlucky_number(self):
+ return 999
+
+ obj = AR()
+ assert obj.say_something(3) == "hihihi"
+ assert obj.unlucky_number() == 99
+ assert obj.say_everything() == "hi 99"
+
+ obj = AT()
+ assert obj.say_something(3) == "hihihi"
+ assert obj.unlucky_number() == 999
+ assert obj.say_everything() == "hi 999"
+
+ for obj in [m.B_Repeat(), m.B_Tpl()]:
+ assert obj.say_something(3) == "B says hi 3 times"
+ assert obj.unlucky_number() == 13
+ assert obj.lucky_number() == 7.0
+ assert obj.say_everything() == "B says hi 1 times 13"
+
+ for obj in [m.C_Repeat(), m.C_Tpl()]:
+ assert obj.say_something(3) == "B says hi 3 times"
+ assert obj.unlucky_number() == 4444
+ assert obj.lucky_number() == 888.0
+ assert obj.say_everything() == "B says hi 1 times 4444"
+
+ class CR(m.C_Repeat):
+ def lucky_number(self):
+ return m.C_Repeat.lucky_number(self) + 1.25
+
+ obj = CR()
+ assert obj.say_something(3) == "B says hi 3 times"
+ assert obj.unlucky_number() == 4444
+ assert obj.lucky_number() == 889.25
+ assert obj.say_everything() == "B says hi 1 times 4444"
+
+ class CT(m.C_Tpl):
+ pass
+
+ obj = CT()
+ assert obj.say_something(3) == "B says hi 3 times"
+ assert obj.unlucky_number() == 4444
+ assert obj.lucky_number() == 888.0
+ assert obj.say_everything() == "B says hi 1 times 4444"
+
+ class CCR(CR):
+ def lucky_number(self):
+ return CR.lucky_number(self) * 10
+
+ obj = CCR()
+ assert obj.say_something(3) == "B says hi 3 times"
+ assert obj.unlucky_number() == 4444
+ assert obj.lucky_number() == 8892.5
+ assert obj.say_everything() == "B says hi 1 times 4444"
+
+ class CCT(CT):
+ def lucky_number(self):
+ return CT.lucky_number(self) * 1000
+
+ obj = CCT()
+ assert obj.say_something(3) == "B says hi 3 times"
+ assert obj.unlucky_number() == 4444
+ assert obj.lucky_number() == 888000.0
+ assert obj.say_everything() == "B says hi 1 times 4444"
+
+ class DR(m.D_Repeat):
+ def unlucky_number(self):
+ return 123
+
+ def lucky_number(self):
+ return 42.0
+
+ for obj in [m.D_Repeat(), m.D_Tpl()]:
+ assert obj.say_something(3) == "B says hi 3 times"
+ assert obj.unlucky_number() == 4444
+ assert obj.lucky_number() == 888.0
+ assert obj.say_everything() == "B says hi 1 times 4444"
+
+ obj = DR()
+ assert obj.say_something(3) == "B says hi 3 times"
+ assert obj.unlucky_number() == 123
+ assert obj.lucky_number() == 42.0
+ assert obj.say_everything() == "B says hi 1 times 123"
+
+ class DT(m.D_Tpl):
+ def say_something(self, times):
+ return "DT says:" + (' quack' * times)
+
+ def unlucky_number(self):
+ return 1234
+
+ def lucky_number(self):
+ return -4.25
+
+ obj = DT()
+ assert obj.say_something(3) == "DT says: quack quack quack"
+ assert obj.unlucky_number() == 1234
+ assert obj.lucky_number() == -4.25
+ assert obj.say_everything() == "DT says: quack 1234"
+
+ class DT2(DT):
+ def say_something(self, times):
+ return "DT2: " + ('QUACK' * times)
+
+ def unlucky_number(self):
+ return -3
+
+ class BT(m.B_Tpl):
+ def say_something(self, times):
+ return "BT" * times
+
+ def unlucky_number(self):
+ return -7
+
+ def lucky_number(self):
+ return -1.375
+
+ obj = BT()
+ assert obj.say_something(3) == "BTBTBT"
+ assert obj.unlucky_number() == -7
+ assert obj.lucky_number() == -1.375
+ assert obj.say_everything() == "BT -7"
+
+
+def test_issue_1454():
+ # Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
+ m.test_gil()
+ m.test_gil_from_thread()