aboutsummaryrefslogtreecommitdiffstats
path: root/3rdparty/pybind11/tests
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2022-09-14 09:28:47 +0200
committergatecat <gatecat@ds0.me>2022-09-14 09:28:47 +0200
commita72f898ff4c4237424c468044a6db9d6953b541e (patch)
tree1c4a543f661dd1b281aecf4660388491702fa8d8 /3rdparty/pybind11/tests
parentf1349e114f3a16ccd002e8513339e18f5be4d31b (diff)
downloadnextpnr-a72f898ff4c4237424c468044a6db9d6953b541e.tar.gz
nextpnr-a72f898ff4c4237424c468044a6db9d6953b541e.tar.bz2
nextpnr-a72f898ff4c4237424c468044a6db9d6953b541e.zip
3rdparty: Bump vendored pybind11 version for py3.11 support
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to '3rdparty/pybind11/tests')
-rw-r--r--3rdparty/pybind11/tests/CMakeLists.txt337
-rw-r--r--3rdparty/pybind11/tests/conftest.py31
-rw-r--r--3rdparty/pybind11/tests/constructor_stats.h143
-rw-r--r--3rdparty/pybind11/tests/cross_module_gil_utils.cpp48
-rw-r--r--3rdparty/pybind11/tests/cross_module_interleaved_error_already_set.cpp51
-rw-r--r--3rdparty/pybind11/tests/env.py20
-rw-r--r--3rdparty/pybind11/tests/extra_python_package/test_files.py164
-rw-r--r--3rdparty/pybind11/tests/extra_setuptools/test_setuphelper.py68
-rw-r--r--3rdparty/pybind11/tests/local_bindings.h52
-rw-r--r--3rdparty/pybind11/tests/object.h112
-rw-r--r--3rdparty/pybind11/tests/pybind11_cross_module_tests.cpp90
-rw-r--r--3rdparty/pybind11/tests/pybind11_tests.cpp54
-rw-r--r--3rdparty/pybind11/tests/pybind11_tests.h54
-rw-r--r--3rdparty/pybind11/tests/pytest.ini13
-rw-r--r--3rdparty/pybind11/tests/requirements.txt17
-rw-r--r--3rdparty/pybind11/tests/test_async.cpp5
-rw-r--r--3rdparty/pybind11/tests/test_async.py1
-rw-r--r--3rdparty/pybind11/tests/test_buffers.cpp134
-rw-r--r--3rdparty/pybind11/tests/test_buffers.py23
-rw-r--r--3rdparty/pybind11/tests/test_builtin_casters.cpp337
-rw-r--r--3rdparty/pybind11/tests/test_builtin_casters.py319
-rw-r--r--3rdparty/pybind11/tests/test_call_policies.cpp44
-rw-r--r--3rdparty/pybind11/tests/test_call_policies.py34
-rw-r--r--3rdparty/pybind11/tests/test_callbacks.cpp181
-rw-r--r--3rdparty/pybind11/tests/test_callbacks.py57
-rw-r--r--3rdparty/pybind11/tests/test_chrono.cpp33
-rw-r--r--3rdparty/pybind11/tests/test_chrono.py41
-rw-r--r--3rdparty/pybind11/tests/test_class.cpp392
-rw-r--r--3rdparty/pybind11/tests/test_class.py23
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt7
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/embed.cpp8
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt6
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt3
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt3
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt8
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt5
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt5
-rw-r--r--3rdparty/pybind11/tests/test_cmake_build/test.py6
-rw-r--r--3rdparty/pybind11/tests/test_const_name.cpp55
-rw-r--r--3rdparty/pybind11/tests/test_const_name.py29
-rw-r--r--3rdparty/pybind11/tests/test_constants_and_functions.cpp116
-rw-r--r--3rdparty/pybind11/tests/test_constants_and_functions.py12
-rw-r--r--3rdparty/pybind11/tests/test_copy_move.cpp236
-rw-r--r--3rdparty/pybind11/tests/test_copy_move.py13
-rw-r--r--3rdparty/pybind11/tests/test_custom_type_casters.cpp174
-rw-r--r--3rdparty/pybind11/tests/test_custom_type_casters.py12
-rw-r--r--3rdparty/pybind11/tests/test_custom_type_setup.cpp41
-rw-r--r--3rdparty/pybind11/tests/test_custom_type_setup.py48
-rw-r--r--3rdparty/pybind11/tests/test_docstring_options.cpp63
-rw-r--r--3rdparty/pybind11/tests/test_docstring_options.py4
-rw-r--r--3rdparty/pybind11/tests/test_eigen.cpp269
-rw-r--r--3rdparty/pybind11/tests/test_eigen.py91
-rw-r--r--3rdparty/pybind11/tests/test_embed/CMakeLists.txt8
-rw-r--r--3rdparty/pybind11/tests/test_embed/catch.cpp29
-rw-r--r--3rdparty/pybind11/tests/test_embed/external_module.cpp11
-rw-r--r--3rdparty/pybind11/tests/test_embed/test_interpreter.cpp180
-rw-r--r--3rdparty/pybind11/tests/test_embed/test_interpreter.py8
-rw-r--r--3rdparty/pybind11/tests/test_embed/test_trampoline.py16
-rw-r--r--3rdparty/pybind11/tests/test_enum.cpp106
-rw-r--r--3rdparty/pybind11/tests/test_enum.py69
-rw-r--r--3rdparty/pybind11/tests/test_eval.cpp53
-rw-r--r--3rdparty/pybind11/tests/test_eval.py21
-rw-r--r--3rdparty/pybind11/tests/test_eval_call.py1
-rw-r--r--3rdparty/pybind11/tests/test_exceptions.cpp232
-rw-r--r--3rdparty/pybind11/tests/test_exceptions.h13
-rw-r--r--3rdparty/pybind11/tests/test_exceptions.py196
-rw-r--r--3rdparty/pybind11/tests/test_factory_constructors.cpp323
-rw-r--r--3rdparty/pybind11/tests/test_factory_constructors.py24
-rw-r--r--3rdparty/pybind11/tests/test_gil_scoped.cpp49
-rw-r--r--3rdparty/pybind11/tests/test_gil_scoped.py1
-rw-r--r--3rdparty/pybind11/tests/test_iostream.cpp95
-rw-r--r--3rdparty/pybind11/tests/test_iostream.py155
-rw-r--r--3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp282
-rw-r--r--3rdparty/pybind11/tests/test_kwargs_and_defaults.py123
-rw-r--r--3rdparty/pybind11/tests/test_local_bindings.cpp47
-rw-r--r--3rdparty/pybind11/tests/test_local_bindings.py6
-rw-r--r--3rdparty/pybind11/tests/test_methods_and_attributes.cpp322
-rw-r--r--3rdparty/pybind11/tests/test_methods_and_attributes.py94
-rw-r--r--3rdparty/pybind11/tests/test_modules.cpp72
-rw-r--r--3rdparty/pybind11/tests/test_modules.py52
-rw-r--r--3rdparty/pybind11/tests/test_multiple_inheritance.cpp277
-rw-r--r--3rdparty/pybind11/tests/test_multiple_inheritance.py148
-rw-r--r--3rdparty/pybind11/tests/test_numpy_array.cpp470
-rw-r--r--3rdparty/pybind11/tests/test_numpy_array.py74
-rw-r--r--3rdparty/pybind11/tests/test_numpy_dtypes.cpp399
-rw-r--r--3rdparty/pybind11/tests/test_numpy_dtypes.py71
-rw-r--r--3rdparty/pybind11/tests/test_numpy_vectorize.cpp94
-rw-r--r--3rdparty/pybind11/tests/test_numpy_vectorize.py2
-rw-r--r--3rdparty/pybind11/tests/test_opaque_types.cpp20
-rw-r--r--3rdparty/pybind11/tests/test_opaque_types.py8
-rw-r--r--3rdparty/pybind11/tests/test_operator_overloading.cpp198
-rw-r--r--3rdparty/pybind11/tests/test_operator_overloading.py15
-rw-r--r--3rdparty/pybind11/tests/test_pickling.cpp110
-rw-r--r--3rdparty/pybind11/tests/test_pickling.py60
-rw-r--r--3rdparty/pybind11/tests/test_pytypes.cpp671
-rw-r--r--3rdparty/pybind11/tests/test_pytypes.py517
-rw-r--r--3rdparty/pybind11/tests/test_sequences_and_iterators.cpp420
-rw-r--r--3rdparty/pybind11/tests/test_sequences_and_iterators.py78
-rw-r--r--3rdparty/pybind11/tests/test_smart_ptr.cpp512
-rw-r--r--3rdparty/pybind11/tests/test_smart_ptr.py29
-rw-r--r--3rdparty/pybind11/tests/test_stl.cpp403
-rw-r--r--3rdparty/pybind11/tests/test_stl.py123
-rw-r--r--3rdparty/pybind11/tests/test_stl_binders.cpp111
-rw-r--r--3rdparty/pybind11/tests/test_stl_binders.py48
-rw-r--r--3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp117
-rw-r--r--3rdparty/pybind11/tests/test_tagbased_polymorphic.py1
-rw-r--r--3rdparty/pybind11/tests/test_thread.cpp66
-rw-r--r--3rdparty/pybind11/tests/test_thread.py42
-rw-r--r--3rdparty/pybind11/tests/test_union.py1
-rw-r--r--3rdparty/pybind11/tests/test_virtual_functions.cpp341
-rw-r--r--3rdparty/pybind11/tests/test_virtual_functions.py78
-rw-r--r--3rdparty/pybind11/tests/valgrind-numpy-scipy.supp140
-rw-r--r--3rdparty/pybind11/tests/valgrind-python.supp117
113 files changed, 8912 insertions, 3529 deletions
diff --git a/3rdparty/pybind11/tests/CMakeLists.txt b/3rdparty/pybind11/tests/CMakeLists.txt
index dae8b5ad..7296cd1b 100644
--- a/3rdparty/pybind11/tests/CMakeLists.txt
+++ b/3rdparty/pybind11/tests/CMakeLists.txt
@@ -10,27 +10,34 @@ cmake_minimum_required(VERSION 3.4)
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround:
-if(${CMAKE_VERSION} VERSION_LESS 3.18)
+if(${CMAKE_VERSION} VERSION_LESS 3.21)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
- cmake_policy(VERSION 3.18)
+ cmake_policy(VERSION 3.21)
endif()
# Only needed for CMake < 3.5 support
include(CMakeParseArguments)
-# Filter out items; print an optional message if any items filtered
+# Filter out items; print an optional message if any items filtered. This ignores extensions.
#
# Usage:
# pybind11_filter_tests(LISTNAME file1.cpp file2.cpp ... MESSAGE "")
#
-macro(PYBIND11_FILTER_TESTS LISTNAME)
+macro(pybind11_filter_tests LISTNAME)
cmake_parse_arguments(ARG "" "MESSAGE" "" ${ARGN})
set(PYBIND11_FILTER_TESTS_FOUND OFF)
+ # Make a list of the test without any extensions, for easier filtering.
+ set(_TMP_ACTUAL_LIST "${${LISTNAME}};") # enforce ';' at the end to allow matching last item.
+ string(REGEX REPLACE "\\.[^.;]*;" ";" LIST_WITHOUT_EXTENSIONS "${_TMP_ACTUAL_LIST}")
foreach(filename IN LISTS ARG_UNPARSED_ARGUMENTS)
- list(FIND ${LISTNAME} ${filename} _FILE_FOUND)
+ string(REGEX REPLACE "\\.[^.]*$" "" filename_no_ext ${filename})
+ # Search in the list without extensions.
+ list(FIND LIST_WITHOUT_EXTENSIONS ${filename_no_ext} _FILE_FOUND)
if(_FILE_FOUND GREATER -1)
- list(REMOVE_AT ${LISTNAME} ${_FILE_FOUND})
+ list(REMOVE_AT ${LISTNAME} ${_FILE_FOUND}) # And remove from the list with extensions.
+ list(REMOVE_AT LIST_WITHOUT_EXTENSIONS ${_FILE_FOUND}
+ )# And our search list, to ensure it is in sync.
set(PYBIND11_FILTER_TESTS_FOUND ON)
endif()
endforeach()
@@ -39,6 +46,26 @@ macro(PYBIND11_FILTER_TESTS LISTNAME)
endif()
endmacro()
+macro(possibly_uninitialized)
+ foreach(VARNAME ${ARGN})
+ if(NOT DEFINED "${VARNAME}")
+ set("${VARNAME}" "")
+ endif()
+ endforeach()
+endmacro()
+
+# Function to add additional targets if any of the provided tests are found.
+# Needles; Specifies the test names to look for.
+# Additions; Specifies the additional test targets to add when any of the needles are found.
+macro(tests_extra_targets needles additions)
+ # Add the index for this relation to the index extra targets map.
+ list(LENGTH PYBIND11_TEST_EXTRA_TARGETS PYBIND11_TEST_EXTRA_TARGETS_LEN)
+ list(APPEND PYBIND11_TEST_EXTRA_TARGETS ${PYBIND11_TEST_EXTRA_TARGETS_LEN})
+ # Add the test names to look for, and the associated test target additions.
+ set(PYBIND11_TEST_EXTRA_TARGETS_NEEDLES_${PYBIND11_TEST_EXTRA_TARGETS_LEN} ${needles})
+ set(PYBIND11_TEST_EXTRA_TARGETS_ADDITION_${PYBIND11_TEST_EXTRA_TARGETS_LEN} ${additions})
+endmacro()
+
# New Python support
if(DEFINED Python_EXECUTABLE)
set(PYTHON_EXECUTABLE "${Python_EXECUTABLE}")
@@ -67,7 +94,7 @@ if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
find_package(pybind11 REQUIRED CONFIG)
endif()
-if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+if(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting tests build type to MinSizeRel as none was specified")
set(CMAKE_BUILD_TYPE
MinSizeRel
@@ -84,52 +111,67 @@ if(PYBIND11_CUDA_TESTS)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
endif()
-# Full set of test files (you can override these; see below)
+# Full set of test files (you can override these; see below, overrides ignore extension)
+# Any test that has no extension is both .py and .cpp, so 'foo' will add 'foo.cpp' and 'foo.py'.
+# Any test that has an extension is exclusively that and handled as such.
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_custom_type_casters.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)
+ test_async
+ test_buffers
+ test_builtin_casters
+ test_call_policies
+ test_callbacks
+ test_chrono
+ test_class
+ test_const_name
+ test_constants_and_functions
+ test_copy_move
+ test_custom_type_casters
+ test_custom_type_setup
+ test_docstring_options
+ test_eigen
+ test_enum
+ test_eval
+ test_exceptions
+ test_factory_constructors
+ test_gil_scoped
+ test_iostream
+ test_kwargs_and_defaults
+ test_local_bindings
+ test_methods_and_attributes
+ test_modules
+ test_multiple_inheritance
+ test_numpy_array
+ test_numpy_dtypes
+ test_numpy_vectorize
+ test_opaque_types
+ test_operator_overloading
+ test_pickling
+ test_pytypes
+ test_sequences_and_iterators
+ test_smart_ptr
+ test_stl
+ test_stl_binders
+ test_tagbased_polymorphic
+ test_thread
+ test_union
+ test_virtual_functions)
# Invoking cmake with something like:
# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.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})
+ # Instead of doing a direct override here, we iterate over the overrides without extension and
+ # match them against entries from the PYBIND11_TEST_FILES, anything that not matches goes into the filter list.
+ string(REGEX REPLACE "\\.[^.;]*;" ";" TEST_OVERRIDE_NO_EXT "${PYBIND11_TEST_OVERRIDE};")
+ string(REGEX REPLACE "\\.[^.;]*;" ";" TEST_FILES_NO_EXT "${PYBIND11_TEST_FILES};")
+ # This allows the override to be done with extensions, preserving backwards compatibility.
+ foreach(test_name ${TEST_FILES_NO_EXT})
+ if(NOT ${test_name} IN_LIST TEST_OVERRIDE_NO_EXT
+ )# If not in the whitelist, add to be filtered out.
+ list(APPEND PYBIND11_TEST_FILTER ${test_name})
+ endif()
+ endforeach()
endif()
# You can also filter tests:
@@ -137,11 +179,6 @@ if(PYBIND11_TEST_FILTER)
pybind11_filter_tests(PYBIND11_TEST_FILES ${PYBIND11_TEST_FILTER})
endif()
-if(PYTHON_VERSION VERSION_LESS 3.5)
- pybind11_filter_tests(PYBIND11_TEST_FILES test_async.cpp MESSAGE
- "Skipping test_async on Python 2")
-endif()
-
# Skip tests for CUDA check:
# /pybind11/tests/test_constants_and_functions.cpp(125):
# error: incompatible exception specifications
@@ -151,15 +188,47 @@ if(PYBIND11_CUDA_TESTS)
"Skipping test_constants_and_functions due to incompatible exception specifications")
endif()
-string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")
+# Now that the test filtering is complete, we need to split the list into the test for PYTEST
+# and the list for the cpp targets.
+set(PYBIND11_CPPTEST_FILES "")
+set(PYBIND11_PYTEST_FILES "")
+
+foreach(test_name ${PYBIND11_TEST_FILES})
+ if(test_name MATCHES "\\.py$") # Ends in .py, purely python test.
+ list(APPEND PYBIND11_PYTEST_FILES ${test_name})
+ elseif(test_name MATCHES "\\.cpp$") # Ends in .cpp, purely cpp test.
+ list(APPEND PYBIND11_CPPTEST_FILES ${test_name})
+ elseif(NOT test_name MATCHES "\\.") # No extension specified, assume both, add extension.
+ list(APPEND PYBIND11_PYTEST_FILES ${test_name}.py)
+ list(APPEND PYBIND11_CPPTEST_FILES ${test_name}.cpp)
+ else()
+ message(WARNING "Unhanded test extension in test: ${test_name}")
+ endif()
+endforeach()
+set(PYBIND11_TEST_FILES ${PYBIND11_CPPTEST_FILES})
+list(SORT PYBIND11_PYTEST_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)
+tests_extra_targets("test_exceptions.py;test_local_bindings.py;test_stl.py;test_stl_binders.py"
+ "pybind11_cross_module_tests")
+
+# And add additional targets for other tests.
+tests_extra_targets("test_exceptions.py" "cross_module_interleaved_error_already_set")
+tests_extra_targets("test_gil_scoped.py" "cross_module_gil_utils")
-set(PYBIND11_CROSS_MODULE_GIL_TESTS test_gil_scoped.py)
+set(PYBIND11_EIGEN_REPO
+ "https://gitlab.com/libeigen/eigen.git"
+ CACHE STRING "Eigen repository to use for tests")
+# Always use a hash for reconfigure speed and security reasons
+# Include the version number for pretty printing (keep in sync)
+set(PYBIND11_EIGEN_VERSION_AND_HASH
+ "3.4.0;929bc0e191d0927b1735b9a1ddc0e8b77e3a25ec"
+ CACHE STRING "Eigen version to use for tests, format: VERSION;HASH")
+
+list(GET PYBIND11_EIGEN_VERSION_AND_HASH 0 PYBIND11_EIGEN_VERSION_STRING)
+list(GET PYBIND11_EIGEN_VERSION_AND_HASH 1 PYBIND11_EIGEN_VERSION_HASH)
# 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"
@@ -174,22 +243,26 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
message(FATAL_ERROR "CMake 3.11+ required when using DOWNLOAD_EIGEN")
endif()
- set(EIGEN3_VERSION_STRING "3.3.8")
-
include(FetchContent)
FetchContent_Declare(
eigen
- GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
- GIT_TAG ${EIGEN3_VERSION_STRING})
+ GIT_REPOSITORY "${PYBIND11_EIGEN_REPO}"
+ GIT_TAG "${PYBIND11_EIGEN_VERSION_HASH}")
FetchContent_GetProperties(eigen)
if(NOT eigen_POPULATED)
- message(STATUS "Downloading Eigen")
+ message(
+ STATUS
+ "Downloading Eigen ${PYBIND11_EIGEN_VERSION_STRING} (${PYBIND11_EIGEN_VERSION_HASH}) from ${PYBIND11_EIGEN_REPO}"
+ )
FetchContent_Populate(eigen)
endif()
set(EIGEN3_INCLUDE_DIR ${eigen_SOURCE_DIR})
set(EIGEN3_FOUND TRUE)
+ # When getting locally, the version is not visible from a superprojet,
+ # so just force it.
+ set(EIGEN3_VERSION "${PYBIND11_EIGEN_VERSION_STRING}")
else()
find_package(Eigen3 3.2.7 QUIET CONFIG)
@@ -217,7 +290,8 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
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, use -DDOWNLOAD_EIGEN on CMake 3.11+ to download")
+ message(
+ STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN=ON on CMake 3.11+ to download")
endif()
endif()
@@ -238,10 +312,47 @@ if(Boost_FOUND)
endif()
endif()
+# Check if we need to add -lstdc++fs or -lc++fs or nothing
+if(DEFINED CMAKE_CXX_STANDARD AND CMAKE_CXX_STANDARD LESS 17)
+ set(STD_FS_NO_LIB_NEEDED TRUE)
+elseif(MSVC)
+ set(STD_FS_NO_LIB_NEEDED TRUE)
+else()
+ file(
+ WRITE ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
+ "#include <filesystem>\nint main(int argc, char ** argv) {\n std::filesystem::path p(argv[0]);\n return p.string().length();\n}"
+ )
+ try_compile(
+ STD_FS_NO_LIB_NEEDED ${CMAKE_CURRENT_BINARY_DIR}
+ SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
+ COMPILE_DEFINITIONS -std=c++17)
+ try_compile(
+ STD_FS_NEEDS_STDCXXFS ${CMAKE_CURRENT_BINARY_DIR}
+ SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
+ COMPILE_DEFINITIONS -std=c++17
+ LINK_LIBRARIES stdc++fs)
+ try_compile(
+ STD_FS_NEEDS_CXXFS ${CMAKE_CURRENT_BINARY_DIR}
+ SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
+ COMPILE_DEFINITIONS -std=c++17
+ LINK_LIBRARIES c++fs)
+endif()
+
+if(${STD_FS_NEEDS_STDCXXFS})
+ set(STD_FS_LIB stdc++fs)
+elseif(${STD_FS_NEEDS_CXXFS})
+ set(STD_FS_LIB c++fs)
+elseif(${STD_FS_NO_LIB_NEEDED})
+ set(STD_FS_LIB "")
+else()
+ message(WARNING "Unknown C++17 compiler - not passing -lstdc++fs")
+ set(STD_FS_LIB "")
+endif()
+
# Compile with compiler warnings turned on
function(pybind11_enable_warnings target_name)
if(MSVC)
- target_compile_options(${target_name} PRIVATE /W4)
+ target_compile_options(${target_name} PRIVATE /W4 /wd4189)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)" AND NOT PYBIND11_CUDA_TESTS)
target_compile_options(
${target_name}
@@ -259,40 +370,35 @@ function(pybind11_enable_warnings target_name)
target_compile_options(${target_name} PRIVATE /WX)
elseif(PYBIND11_CUDA_TESTS)
target_compile_options(${target_name} PRIVATE "SHELL:-Werror all-warnings")
- elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)")
+ elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang|IntelLLVM)")
target_compile_options(${target_name} PRIVATE -Werror)
- endif()
- endif()
-
- # Needs to be readded since the ordering requires these to be after the ones above
- if(CMAKE_CXX_STANDARD
- AND CMAKE_CXX_COMPILER_ID MATCHES "Clang"
- AND PYTHON_VERSION VERSION_LESS 3.0)
- if(CMAKE_CXX_STANDARD LESS 17)
- target_compile_options(${target_name} PUBLIC -Wno-deprecated-register)
- else()
- target_compile_options(${target_name} PUBLIC -Wno-register)
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
+ if(CMAKE_CXX_STANDARD EQUAL 17) # See PR #3570
+ target_compile_options(${target_name} PRIVATE -Wno-conversion)
+ endif()
+ target_compile_options(
+ ${target_name}
+ PRIVATE
+ -Werror-all
+ # "Inlining inhibited by limit max-size", "Inlining inhibited by limit max-total-size"
+ -diag-disable 11074,11076)
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()
+# Check if any tests need extra targets by iterating through the mappings registered.
+foreach(i ${PYBIND11_TEST_EXTRA_TARGETS})
+ foreach(needle ${PYBIND11_TEST_EXTRA_TARGETS_NEEDLES_${i}})
+ if(needle IN_LIST PYBIND11_PYTEST_FILES)
+ # Add all the additional targets to the test list. List join in newer cmake.
+ foreach(extra_target ${PYBIND11_TEST_EXTRA_TARGETS_ADDITION_${i}})
+ list(APPEND test_targets ${extra_target})
+ endforeach()
+ break() # Breaks out of the needle search, continues with the next mapping.
+ endif()
+ endforeach()
endforeach()
# Support CUDA testing by forcing the target file to compile with NVCC
@@ -341,18 +447,31 @@ foreach(target ${test_targets})
target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST)
endif()
+ target_link_libraries(${target} PRIVATE ${STD_FS_LIB})
+
# 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
"${CMAKE_CURRENT_BINARY_DIR}")
- foreach(config ${CMAKE_CONFIGURATION_TYPES})
- string(TOUPPER ${config} config)
- set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config}
- "${CMAKE_CURRENT_BINARY_DIR}")
- endforeach()
+
+ if(DEFINED CMAKE_CONFIGURATION_TYPES)
+ foreach(config ${CMAKE_CONFIGURATION_TYPES})
+ string(TOUPPER ${config} config)
+ set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config}
+ "${CMAKE_CURRENT_BINARY_DIR}")
+ endforeach()
+ endif()
endif()
endforeach()
+# Provide nice organisation in IDEs
+if(NOT CMAKE_VERSION VERSION_LESS 3.8)
+ source_group(
+ TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include"
+ PREFIX "Header Files"
+ FILES ${PYBIND11_HEADERS})
+endif()
+
# Make sure pytest is found or produce a warning
pybind11_find_import(pytest VERSION 3.1)
@@ -370,12 +489,17 @@ endif()
string(REPLACE "test_" "${CMAKE_CURRENT_SOURCE_DIR}/test_" PYBIND11_ABS_PYTEST_FILES
"${PYBIND11_PYTEST_FILES}")
+set(PYBIND11_TEST_PREFIX_COMMAND
+ ""
+ CACHE STRING "Put this before pytest, use for checkers and such")
+
# A single command to compile and run the tests
add_custom_target(
pytest
- COMMAND ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_ABS_PYTEST_FILES}
+ COMMAND ${PYBIND11_TEST_PREFIX_COMMAND} ${PYTHON_EXECUTABLE} -m pytest
+ ${PYBIND11_ABS_PYTEST_FILES}
DEPENDS ${test_targets}
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
USES_TERMINAL)
if(PYBIND11_TEST_OVERRIDE)
@@ -386,6 +510,27 @@ if(PYBIND11_TEST_OVERRIDE)
"Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect")
endif()
+# cmake-format: off
+add_custom_target(
+ memcheck
+ COMMAND
+ PYTHONMALLOC=malloc
+ valgrind
+ --leak-check=full
+ --show-leak-kinds=definite,indirect
+ --errors-for-leak-kinds=definite,indirect
+ --error-exitcode=1
+ --read-var-info=yes
+ --track-origins=yes
+ --suppressions="${CMAKE_CURRENT_SOURCE_DIR}/valgrind-python.supp"
+ --suppressions="${CMAKE_CURRENT_SOURCE_DIR}/valgrind-numpy-scipy.supp"
+ --gen-suppressions=all
+ ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_ABS_PYTEST_FILES}
+ DEPENDS ${test_targets}
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+ USES_TERMINAL)
+# cmake-format: on
+
# Add a check target to run all the tests, starting with pytest (we add dependencies to this below)
add_custom_target(check DEPENDS pytest)
diff --git a/3rdparty/pybind11/tests/conftest.py b/3rdparty/pybind11/tests/conftest.py
index 362eb806..02ce263a 100644
--- a/3rdparty/pybind11/tests/conftest.py
+++ b/3rdparty/pybind11/tests/conftest.py
@@ -1,8 +1,7 @@
-# -*- coding: utf-8 -*-
"""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.
+Adds docstring and exceptions message sanitizers.
"""
import contextlib
@@ -13,19 +12,14 @@ import textwrap
import pytest
-import env
-
# Early diagnostic for failed imports
-import pybind11_tests # noqa: F401
+import pybind11_tests
-_unicode_marker = re.compile(r"u(\'[^\']*\')")
_long_marker = re.compile(r"([0-9])L")
_hexadecimal = re.compile(r"0x[0-9a-fA-F]+")
# Avoid collecting Python3 only files
collect_ignore = []
-if env.PY2:
- collect_ignore.append("test_async.py")
def _strip_and_dedent(s):
@@ -45,7 +39,7 @@ def _make_explanation(a, b):
]
-class Output(object):
+class Output:
"""Basic output post-processing and comparison"""
def __init__(self, string):
@@ -83,7 +77,7 @@ class Unordered(Output):
return False
-class Capture(object):
+class Capture:
def __init__(self, capfd):
self.capfd = capfd
self.out = ""
@@ -126,7 +120,7 @@ def capture(capsys):
return Capture(capsys)
-class SanitizedString(object):
+class SanitizedString:
def __init__(self, sanitizer):
self.sanitizer = sanitizer
self.string = ""
@@ -149,9 +143,7 @@ class SanitizedString(object):
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
@@ -206,3 +198,16 @@ def gc_collect():
def pytest_configure():
pytest.suppress = suppress
pytest.gc_collect = gc_collect
+
+
+def pytest_report_header(config):
+ del config # Unused.
+ assert (
+ pybind11_tests.compiler_info is not None
+ ), "Please update pybind11_tests.cpp if this assert fails."
+ return (
+ "C++ Info:"
+ f" {pybind11_tests.compiler_info}"
+ f" {pybind11_tests.cpp_std}"
+ f" {pybind11_tests.PYBIND11_INTERNALS_ID}"
+ )
diff --git a/3rdparty/pybind11/tests/constructor_stats.h b/3rdparty/pybind11/tests/constructor_stats.h
index 805968a0..937f6c23 100644
--- a/3rdparty/pybind11/tests/constructor_stats.h
+++ b/3rdparty/pybind11/tests/constructor_stats.h
@@ -56,7 +56,8 @@ 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)
+ 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.
@@ -65,15 +66,18 @@ inspection/testing in python) by using the functions with `print_` replaced with
*/
#include "pybind11_tests.h"
-#include <unordered_map>
+
#include <list>
-#include <typeindex>
#include <sstream>
+#include <typeindex>
+#include <unordered_map>
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)
+ 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;
@@ -96,26 +100,26 @@ public:
default_constructions++;
}
- void created(void *inst) {
- ++_instances[inst];
- }
+ void created(void *inst) { ++_instances[inst]; }
void destroyed(void *inst) {
- if (--_instances[inst] < 0)
+ 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);
+ PyObject *result = PyRun_String("import gc\n"
+ "for i in range(2):\n"
+ " gc.collect()\n",
+ Py_file_input,
+ globals,
+ globals);
if (result == nullptr)
throw py::error_already_set();
Py_DECREF(result);
@@ -127,15 +131,18 @@ public:
int alive() {
gc();
int total = 0;
- for (const auto &p : _instances)
- if (p.second > 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) {
+ template <typename T, typename... Tmore>
+ void value(const T &v, Tmore &&...args) {
std::ostringstream oss;
oss << v;
_values.push_back(oss.str());
@@ -145,19 +152,22 @@ public:
// Move out stored values
py::list values() {
py::list l;
- for (const auto &v : _values) l.append(py::cast(v));
+ 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 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() {
+ template <typename T>
+ static ConstructorStats &get() {
#if defined(PYPY_VERSION)
gc();
#endif
@@ -165,11 +175,12 @@ public:
}
// Gets constructor stats from a Python class
- static ConstructorStats& get(py::object 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);
+ 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) {
@@ -179,17 +190,23 @@ public:
t1 = &p.first;
}
}
+ } catch (const std::out_of_range &) {
+ }
+ if (!t1) {
+ throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
}
- 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 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;
+ 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;
}
@@ -198,78 +215,108 @@ public:
// 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) {
+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) {
+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) {
+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) {
+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) {
+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) {
+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)); }
+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); }
+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,
+ 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
+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
+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) {
+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) {
+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) {
+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) {
+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
+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) {
+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
index 07db9f6e..1436c35d 100644
--- a/3rdparty/pybind11/tests/cross_module_gil_utils.cpp
+++ b/3rdparty/pybind11/tests/cross_module_gil_utils.cpp
@@ -7,6 +7,7 @@
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
@@ -24,50 +25,21 @@ 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
+ PyModuleDef_HEAD_INIT, kModuleName, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr};
-} // namespace
+} // namespace
-extern "C" PYBIND11_EXPORT
-#if PY_MAJOR_VERSION >= 3
-PyObject* PyInit_cross_module_gil_utils()
-#else
-void initcross_module_gil_utils()
-#endif
-{
+extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() {
- PyObject* m =
-#if PY_MAJOR_VERSION >= 3
- PyModule_Create(&moduledef);
-#else
- Py_InitModule(kModuleName, module_methods);
-#endif
+ PyObject *m = PyModule_Create(&moduledef);
- 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 (m != nullptr) {
+ 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/cross_module_interleaved_error_already_set.cpp b/3rdparty/pybind11/tests/cross_module_interleaved_error_already_set.cpp
new file mode 100644
index 00000000..fdd9939e
--- /dev/null
+++ b/3rdparty/pybind11/tests/cross_module_interleaved_error_already_set.cpp
@@ -0,0 +1,51 @@
+/*
+ Copyright (c) 2022 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>
+
+// This file mimics a DSO that makes pybind11 calls but does not define a PYBIND11_MODULE,
+// so that the first call of cross_module_error_already_set() triggers the first call of
+// pybind11::detail::get_internals().
+
+namespace {
+
+namespace py = pybind11;
+
+void interleaved_error_already_set() {
+ PyErr_SetString(PyExc_RuntimeError, "1st error.");
+ try {
+ throw py::error_already_set();
+ } catch (const py::error_already_set &) {
+ // The 2nd error could be conditional in a real application.
+ PyErr_SetString(PyExc_RuntimeError, "2nd error.");
+ } // Here the 1st error is destroyed before the 2nd error is fetched.
+ // The error_already_set dtor triggers a pybind11::detail::get_internals()
+ // call via pybind11::gil_scoped_acquire.
+ if (PyErr_Occurred()) {
+ throw py::error_already_set();
+ }
+}
+
+constexpr char kModuleName[] = "cross_module_interleaved_error_already_set";
+
+struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT, kModuleName, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr};
+
+} // namespace
+
+extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_interleaved_error_already_set() {
+ PyObject *m = PyModule_Create(&moduledef);
+ if (m != nullptr) {
+ static_assert(sizeof(&interleaved_error_already_set) == sizeof(void *),
+ "Function pointer must have the same size as void *");
+ PyModule_AddObject(
+ m,
+ "funcaddr",
+ PyLong_FromVoidPtr(reinterpret_cast<void *>(&interleaved_error_already_set)));
+ }
+ return m;
+}
diff --git a/3rdparty/pybind11/tests/env.py b/3rdparty/pybind11/tests/env.py
index 5cded441..0345df65 100644
--- a/3rdparty/pybind11/tests/env.py
+++ b/3rdparty/pybind11/tests/env.py
@@ -1,7 +1,8 @@
-# -*- coding: utf-8 -*-
import platform
import sys
+import pytest
+
LINUX = sys.platform.startswith("linux")
MACOS = sys.platform.startswith("darwin")
WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
@@ -9,6 +10,19 @@ WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
CPYTHON = platform.python_implementation() == "CPython"
PYPY = platform.python_implementation() == "PyPy"
-PY2 = sys.version_info.major == 2
-PY = sys.version_info
+def deprecated_call():
+ """
+ pytest.deprecated_call() seems broken in pytest<3.9.x; concretely, it
+ doesn't work on CPython 3.8.0 with pytest==3.3.2 on Ubuntu 18.04 (#2922).
+
+ This is a narrowed reimplementation of the following PR :(
+ https://github.com/pytest-dev/pytest/pull/4104
+ """
+ # TODO: Remove this when testing requires pytest>=3.9.
+ pieces = pytest.__version__.split(".")
+ pytest_major_minor = (int(pieces[0]), int(pieces[1]))
+ if pytest_major_minor < (3, 9):
+ return pytest.warns((DeprecationWarning, PendingDeprecationWarning))
+ else:
+ return pytest.deprecated_call()
diff --git a/3rdparty/pybind11/tests/extra_python_package/test_files.py b/3rdparty/pybind11/tests/extra_python_package/test_files.py
index cbd4bff1..8e1ddd85 100644
--- a/3rdparty/pybind11/tests/extra_python_package/test_files.py
+++ b/3rdparty/pybind11/tests/extra_python_package/test_files.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
import contextlib
import os
import string
@@ -13,6 +12,16 @@ import zipfile
DIR = os.path.abspath(os.path.dirname(__file__))
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
+PKGCONFIG = """\
+prefix=${{pcfiledir}}/../../
+includedir=${{prefix}}/include
+
+Name: pybind11
+Description: Seamless operability between C++11 and Python
+Version: {VERSION}
+Cflags: -I${{includedir}}
+"""
+
main_headers = {
"include/pybind11/attr.h",
@@ -25,6 +34,7 @@ main_headers = {
"include/pybind11/embed.h",
"include/pybind11/eval.h",
"include/pybind11/functional.h",
+ "include/pybind11/gil.h",
"include/pybind11/iostream.h",
"include/pybind11/numpy.h",
"include/pybind11/operators.h",
@@ -41,9 +51,14 @@ detail_headers = {
"include/pybind11/detail/descr.h",
"include/pybind11/detail/init.h",
"include/pybind11/detail/internals.h",
+ "include/pybind11/detail/type_caster_base.h",
"include/pybind11/detail/typeid.h",
}
+stl_headers = {
+ "include/pybind11/stl/filesystem.h",
+}
+
cmake_files = {
"share/cmake/pybind11/FindPythonLibsNew.cmake",
"share/cmake/pybind11/pybind11Common.cmake",
@@ -54,19 +69,21 @@ cmake_files = {
"share/cmake/pybind11/pybind11Tools.cmake",
}
+pkgconfig_files = {
+ "share/pkgconfig/pybind11.pc",
+}
+
py_files = {
"__init__.py",
"__main__.py",
"_version.py",
- "_version.pyi",
"commands.py",
"py.typed",
"setup_helpers.py",
- "setup_helpers.pyi",
}
-headers = main_headers | detail_headers
-src_files = headers | cmake_files
+headers = main_headers | detail_headers | stl_headers
+src_files = headers | cmake_files | pkgconfig_files
all_files = src_files | py_files
@@ -75,9 +92,11 @@ sdist_files = {
"pybind11/include",
"pybind11/include/pybind11",
"pybind11/include/pybind11/detail",
+ "pybind11/include/pybind11/stl",
"pybind11/share",
"pybind11/share/cmake",
"pybind11/share/cmake/pybind11",
+ "pybind11/share/pkgconfig",
"pyproject.toml",
"setup.cfg",
"setup.py",
@@ -97,105 +116,106 @@ local_sdist_files = {
}
+def read_tz_file(tar: tarfile.TarFile, name: str) -> bytes:
+ start = tar.getnames()[0] + "/"
+ inner_file = tar.extractfile(tar.getmember(f"{start}{name}"))
+ assert inner_file
+ with contextlib.closing(inner_file) as f:
+ return f.read()
+
+
+def normalize_line_endings(value: bytes) -> bytes:
+ return value.replace(os.linesep.encode("utf-8"), b"\n")
+
+
def test_build_sdist(monkeypatch, tmpdir):
monkeypatch.chdir(MAIN_DIR)
- out = subprocess.check_output(
- [
- sys.executable,
- "setup.py",
- "sdist",
- "--formats=tar",
- "--dist-dir",
- str(tmpdir),
- ]
+ subprocess.run(
+ [sys.executable, "-m", "build", "--sdist", f"--outdir={tmpdir}"], check=True
)
- if hasattr(out, "decode"):
- out = out.decode()
- (sdist,) = tmpdir.visit("*.tar")
+ (sdist,) = tmpdir.visit("*.tar.gz")
- with tarfile.open(str(sdist)) as tar:
+ with tarfile.open(str(sdist), "r:gz") as tar:
start = tar.getnames()[0] + "/"
version = start[9:-1]
- simpler = set(n.split("/", 1)[-1] for n in tar.getnames()[1:])
+ simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]}
- with contextlib.closing(
- tar.extractfile(tar.getmember(start + "setup.py"))
- ) as f:
- setup_py = f.read()
+ setup_py = read_tz_file(tar, "setup.py")
+ pyproject_toml = read_tz_file(tar, "pyproject.toml")
+ pkgconfig = read_tz_file(tar, "pybind11/share/pkgconfig/pybind11.pc")
+ cmake_cfg = read_tz_file(
+ tar, "pybind11/share/cmake/pybind11/pybind11Config.cmake"
+ )
- with contextlib.closing(
- tar.extractfile(tar.getmember(start + "pyproject.toml"))
- ) as f:
- pyproject_toml = f.read()
+ assert (
+ 'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")'
+ in cmake_cfg.decode("utf-8")
+ )
- files = set("pybind11/{}".format(n) for n in all_files)
+ files = {f"pybind11/{n}" for n in all_files}
files |= sdist_files
- files |= set("pybind11{}".format(n) for n in local_sdist_files)
+ files |= {f"pybind11{n}" for n in local_sdist_files}
files.add("pybind11.egg-info/entry_points.txt")
files.add("pybind11.egg-info/requires.txt")
assert simpler == files
with open(os.path.join(MAIN_DIR, "tools", "setup_main.py.in"), "rb") as f:
contents = (
- string.Template(f.read().decode())
+ string.Template(f.read().decode("utf-8"))
.substitute(version=version, extra_cmd="")
- .encode()
+ .encode("utf-8")
)
- assert setup_py == contents
+ assert setup_py == contents
with open(os.path.join(MAIN_DIR, "tools", "pyproject.toml"), "rb") as f:
contents = f.read()
- assert pyproject_toml == contents
+ assert pyproject_toml == contents
+
+ simple_version = ".".join(version.split(".")[:3])
+ pkgconfig_expected = PKGCONFIG.format(VERSION=simple_version).encode("utf-8")
+ assert normalize_line_endings(pkgconfig) == pkgconfig_expected
def test_build_global_dist(monkeypatch, tmpdir):
monkeypatch.chdir(MAIN_DIR)
monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1")
-
- out = subprocess.check_output(
- [
- sys.executable,
- "setup.py",
- "sdist",
- "--formats=tar",
- "--dist-dir",
- str(tmpdir),
- ]
+ subprocess.run(
+ [sys.executable, "-m", "build", "--sdist", "--outdir", str(tmpdir)], check=True
)
- if hasattr(out, "decode"):
- out = out.decode()
- (sdist,) = tmpdir.visit("*.tar")
+ (sdist,) = tmpdir.visit("*.tar.gz")
- with tarfile.open(str(sdist)) as tar:
+ with tarfile.open(str(sdist), "r:gz") as tar:
start = tar.getnames()[0] + "/"
version = start[16:-1]
- simpler = set(n.split("/", 1)[-1] for n in tar.getnames()[1:])
+ simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]}
- with contextlib.closing(
- tar.extractfile(tar.getmember(start + "setup.py"))
- ) as f:
- setup_py = f.read()
+ setup_py = read_tz_file(tar, "setup.py")
+ pyproject_toml = read_tz_file(tar, "pyproject.toml")
+ pkgconfig = read_tz_file(tar, "pybind11/share/pkgconfig/pybind11.pc")
+ cmake_cfg = read_tz_file(
+ tar, "pybind11/share/cmake/pybind11/pybind11Config.cmake"
+ )
- with contextlib.closing(
- tar.extractfile(tar.getmember(start + "pyproject.toml"))
- ) as f:
- pyproject_toml = f.read()
+ assert (
+ 'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")'
+ in cmake_cfg.decode("utf-8")
+ )
- files = set("pybind11/{}".format(n) for n in all_files)
+ files = {f"pybind11/{n}" for n in all_files}
files |= sdist_files
- files |= set("pybind11_global{}".format(n) for n in local_sdist_files)
+ files |= {f"pybind11_global{n}" for n in local_sdist_files}
assert simpler == files
with open(os.path.join(MAIN_DIR, "tools", "setup_global.py.in"), "rb") as f:
contents = (
string.Template(f.read().decode())
.substitute(version=version, extra_cmd="")
- .encode()
+ .encode("utf-8")
)
assert setup_py == contents
@@ -203,17 +223,21 @@ def test_build_global_dist(monkeypatch, tmpdir):
contents = f.read()
assert pyproject_toml == contents
+ simple_version = ".".join(version.split(".")[:3])
+ pkgconfig_expected = PKGCONFIG.format(VERSION=simple_version).encode("utf-8")
+ assert normalize_line_endings(pkgconfig) == pkgconfig_expected
+
def tests_build_wheel(monkeypatch, tmpdir):
monkeypatch.chdir(MAIN_DIR)
- subprocess.check_output(
- [sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)]
+ subprocess.run(
+ [sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)], check=True
)
(wheel,) = tmpdir.visit("*.whl")
- files = set("pybind11/{}".format(n) for n in all_files)
+ files = {f"pybind11/{n}" for n in all_files}
files |= {
"dist-info/LICENSE",
"dist-info/METADATA",
@@ -226,10 +250,8 @@ def tests_build_wheel(monkeypatch, tmpdir):
with zipfile.ZipFile(str(wheel)) as z:
names = z.namelist()
- trimmed = set(n for n in names if "dist-info" not in n)
- trimmed |= set(
- "dist-info/{}".format(n.split("/", 1)[-1]) for n in names if "dist-info" in n
- )
+ trimmed = {n for n in names if "dist-info" not in n}
+ trimmed |= {f"dist-info/{n.split('/', 1)[-1]}" for n in names if "dist-info" in n}
assert files == trimmed
@@ -237,14 +259,14 @@ def tests_build_global_wheel(monkeypatch, tmpdir):
monkeypatch.chdir(MAIN_DIR)
monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1")
- subprocess.check_output(
- [sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)]
+ subprocess.run(
+ [sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)], check=True
)
(wheel,) = tmpdir.visit("*.whl")
- files = set("data/data/{}".format(n) for n in src_files)
- files |= set("data/headers/{}".format(n[8:]) for n in headers)
+ files = {f"data/data/{n}" for n in src_files}
+ files |= {f"data/headers/{n[8:]}" for n in headers}
files |= {
"dist-info/LICENSE",
"dist-info/METADATA",
@@ -257,6 +279,6 @@ def tests_build_global_wheel(monkeypatch, tmpdir):
names = z.namelist()
beginning = names[0].split("/", 1)[0].rsplit(".", 1)[0]
- trimmed = set(n[len(beginning) + 1 :] for n in names)
+ trimmed = {n[len(beginning) + 1 :] for n in names}
assert files == trimmed
diff --git a/3rdparty/pybind11/tests/extra_setuptools/test_setuphelper.py b/3rdparty/pybind11/tests/extra_setuptools/test_setuphelper.py
index 0d8bd0e4..d5d3093b 100644
--- a/3rdparty/pybind11/tests/extra_setuptools/test_setuphelper.py
+++ b/3rdparty/pybind11/tests/extra_setuptools/test_setuphelper.py
@@ -1,13 +1,13 @@
-# -*- coding: utf-8 -*-
import os
-import sys
import subprocess
+import sys
from textwrap import dedent
import pytest
DIR = os.path.abspath(os.path.dirname(__file__))
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
+WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
@pytest.mark.parametrize("parallel", [False, True])
@@ -18,7 +18,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
(tmpdir / "setup.py").write_text(
dedent(
- u"""\
+ f"""\
import sys
sys.path.append({MAIN_DIR!r})
@@ -51,13 +51,13 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
ext_modules=ext_modules,
)
"""
- ).format(MAIN_DIR=MAIN_DIR, std=std, parallel=parallel),
+ ),
encoding="ascii",
)
(tmpdir / "main.cpp").write_text(
dedent(
- u"""\
+ """\
#include <pybind11/pybind11.h>
int f(int x) {
@@ -71,13 +71,20 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
encoding="ascii",
)
- subprocess.check_call(
+ out = subprocess.check_output(
[sys.executable, "setup.py", "build_ext", "--inplace"],
- stdout=sys.stdout,
- stderr=sys.stderr,
)
+ if not WIN:
+ assert b"-g0" in out
+ out = subprocess.check_output(
+ [sys.executable, "setup.py", "build_ext", "--inplace", "--force"],
+ env=dict(os.environ, CFLAGS="-g"),
+ )
+ if not WIN:
+ assert b"-g0" not in out
# Debug helper printout, normally hidden
+ print(out)
for item in tmpdir.listdir():
print(item.basename)
@@ -88,7 +95,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
(tmpdir / "test.py").write_text(
dedent(
- u"""\
+ """\
import simple_setup
assert simple_setup.f(3) == 9
"""
@@ -99,3 +106,46 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
subprocess.check_call(
[sys.executable, "test.py"], stdout=sys.stdout, stderr=sys.stderr
)
+
+
+def test_intree_extensions(monkeypatch, tmpdir):
+ monkeypatch.syspath_prepend(MAIN_DIR)
+
+ from pybind11.setup_helpers import intree_extensions
+
+ monkeypatch.chdir(tmpdir)
+ root = tmpdir
+ root.ensure_dir()
+ subdir = root / "dir"
+ subdir.ensure_dir()
+ src = subdir / "ext.cpp"
+ src.ensure()
+ relpath = src.relto(tmpdir)
+ (ext,) = intree_extensions([relpath])
+ assert ext.name == "ext"
+ subdir.ensure("__init__.py")
+ (ext,) = intree_extensions([relpath])
+ assert ext.name == "dir.ext"
+
+
+def test_intree_extensions_package_dir(monkeypatch, tmpdir):
+ monkeypatch.syspath_prepend(MAIN_DIR)
+
+ from pybind11.setup_helpers import intree_extensions
+
+ monkeypatch.chdir(tmpdir)
+ root = tmpdir / "src"
+ root.ensure_dir()
+ subdir = root / "dir"
+ subdir.ensure_dir()
+ src = subdir / "ext.cpp"
+ src.ensure()
+ (ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"": "src"})
+ assert ext.name == "dir.ext"
+ (ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"foo": "src"})
+ assert ext.name == "foo.dir.ext"
+ subdir.ensure("__init__.py")
+ (ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"": "src"})
+ assert ext.name == "dir.ext"
+ (ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"foo": "src"})
+ assert ext.name == "foo.dir.ext"
diff --git a/3rdparty/pybind11/tests/local_bindings.h b/3rdparty/pybind11/tests/local_bindings.h
index 22537b13..01d27853 100644
--- a/3rdparty/pybind11/tests/local_bindings.h
+++ b/3rdparty/pybind11/tests/local_bindings.h
@@ -1,10 +1,13 @@
#pragma once
#include "pybind11_tests.h"
+#include <utility>
+
/// Simple class used to test py::local:
-template <int> class LocalBase {
+template <int>
+class LocalBase {
public:
- LocalBase(int i) : i(i) { }
+ explicit LocalBase(int i) : i(i) {}
int i = -1;
};
@@ -33,32 +36,57 @@ using NonLocalVec2 = std::vector<NonLocal2>;
using NonLocalMap = std::unordered_map<std::string, NonLocalType>;
using NonLocalMap2 = std::unordered_map<std::string, uint8_t>;
+// Exception that will be caught via the module local translator.
+class LocalException : public std::exception {
+public:
+ explicit LocalException(const char *m) : message{m} {}
+ const char *what() const noexcept override { return message.c_str(); }
+
+private:
+ std::string message = "";
+};
+
+// Exception that will be registered with register_local_exception_translator
+class LocalSimpleException : public std::exception {
+public:
+ explicit LocalSimpleException(const char *m) : message{m} {}
+ const char *what() const noexcept override { return message.c_str(); }
+
+private:
+ std::string message = "";
+};
+
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(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; });
+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) {}
+ explicit Pet(std::string name) : name_(std::move(name)) {}
std::string name_;
- const std::string &name() { return name_; }
+ const std::string &name() const { return name_; }
};
} // namespace pets
-struct MixGL { int i; MixGL(int i) : i{i} {} };
-struct MixGL2 { int i; MixGL2(int i) : i{i} {} };
+struct MixGL {
+ int i;
+ explicit MixGL(int i) : i{i} {}
+};
+struct MixGL2 {
+ int i;
+ explicit MixGL2(int i) : i{i} {}
+};
diff --git a/3rdparty/pybind11/tests/object.h b/3rdparty/pybind11/tests/object.h
index 9235f19c..564dd4a7 100644
--- a/3rdparty/pybind11/tests/object.h
+++ b/3rdparty/pybind11/tests/object.h
@@ -1,8 +1,9 @@
#if !defined(__OBJECT_H)
-#define __OBJECT_H
+# define __OBJECT_H
-#include <atomic>
-#include "constructor_stats.h"
+# include "constructor_stats.h"
+
+# include <atomic>
/// Reference counted object base class
class Object {
@@ -27,20 +28,23 @@ public:
*/
void decRef(bool dealloc = true) const {
--m_refCount;
- if (m_refCount == 0 && dealloc)
+ if (m_refCount == 0 && dealloc) {
delete this;
- else if (m_refCount < 0)
+ } 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 };
+ mutable std::atomic<int> m_refCount{0};
};
// Tag class used to track constructions of ref objects. When we track constructors, below, we
@@ -59,80 +63,105 @@ class ref_tag {};
*
* \ingroup libcore
*/
-template <typename T> class ref {
+template <typename T>
+class ref {
public:
/// Create a nullptr reference
- ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); }
+ 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");
+ explicit 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)
+ if (m_ptr) {
((Object *) m_ptr)->incRef();
+ }
- print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
+ print_copy_created(this, "with pointer", m_ptr);
+ track_copy_created((ref_tag *) this);
}
/// Move constructor
- ref(ref &&r) : m_ptr(r.m_ptr) {
+ ref(ref &&r) noexcept : m_ptr(r.m_ptr) {
r.m_ptr = nullptr;
- print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
+ print_move_created(this, "with pointer", m_ptr);
+ track_move_created((ref_tag *) this);
}
/// Destroy this reference
~ref() {
- if (m_ptr)
+ if (m_ptr) {
((Object *) m_ptr)->decRef();
+ }
- print_destroyed(this); track_destroyed((ref_tag*) this);
+ 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);
+ ref &operator=(ref &&r) noexcept {
+ print_move_assigned(this, "pointer", r.m_ptr);
+ track_move_assigned((ref_tag *) this);
- if (*this == r)
+ if (*this == r) {
return *this;
- if (m_ptr)
+ }
+ 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);
+ ref &operator=(const ref &r) {
+ if (this == &r) {
+ return *this;
+ }
+ print_copy_assigned(this, "pointer", r.m_ptr);
+ track_copy_assigned((ref_tag *) this);
- if (m_ptr == r.m_ptr)
+ if (m_ptr == r.m_ptr) {
return *this;
- if (m_ptr)
+ }
+ if (m_ptr) {
((Object *) m_ptr)->decRef();
+ }
m_ptr = r.m_ptr;
- if (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");
+ ref &operator=(T *ptr) {
+ print_values(this, "assigned pointer");
+ track_values((ref_tag *) this, "assigned pointer");
- if (m_ptr == ptr)
+ if (m_ptr == ptr) {
return *this;
- if (m_ptr)
+ }
+ if (m_ptr) {
((Object *) m_ptr)->decRef();
+ }
m_ptr = ptr;
- if (m_ptr)
+ if (m_ptr) {
((Object *) m_ptr)->incRef();
+ }
return *this;
}
@@ -143,31 +172,32 @@ public:
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; }
+ 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; }
+ bool operator!=(const T *ptr) const { return m_ptr != ptr; }
/// Access the object referenced by this reference
- T* operator->() { return m_ptr; }
+ T *operator->() { return m_ptr; }
/// Access the object referenced by this reference
- const T* operator->() const { return m_ptr; }
+ const T *operator->() const { return m_ptr; }
/// Return a C++ reference to the referenced object
- T& operator*() { return *m_ptr; }
+ T &operator*() { return *m_ptr; }
/// Return a const C++ reference to the referenced object
- const T& operator*() const { return *m_ptr; }
+ const T &operator*() const { return *m_ptr; }
/// Return a pointer to the referenced object
- operator T* () { return m_ptr; }
+ explicit operator T *() { return m_ptr; }
/// Return a const pointer to the referenced object
- T* get_ptr() { return m_ptr; }
+ T *get_ptr() { return m_ptr; }
/// Return a pointer to the referenced object
- const T* get_ptr() const { return m_ptr; }
+ const T *get_ptr() const { return m_ptr; }
+
private:
T *m_ptr;
};
diff --git a/3rdparty/pybind11/tests/pybind11_cross_module_tests.cpp b/3rdparty/pybind11/tests/pybind11_cross_module_tests.cpp
index f705e310..9379f3f2 100644
--- a/3rdparty/pybind11/tests/pybind11_cross_module_tests.cpp
+++ b/3rdparty/pybind11/tests/pybind11_cross_module_tests.cpp
@@ -7,10 +7,14 @@
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 "local_bindings.h"
+#include "pybind11_tests.h"
+#include "test_exceptions.h"
+
#include <numeric>
+#include <utility>
PYBIND11_MODULE(pybind11_cross_module_tests, m) {
m.doc() = "pybind11 cross-module test module";
@@ -25,17 +29,46 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
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(); });
+ py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException");
+ 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(); });
+ m.def("throw_local_error", []() { throw LocalException("just local"); });
+ m.def("throw_local_simple_error", []() { throw LocalSimpleException("external mod"); });
+ py::register_exception_translator([](std::exception_ptr p) {
+ try {
+ if (p) {
+ std::rethrow_exception(p);
+ }
+ } catch (const shared_exception &e) {
+ PyErr_SetString(PyExc_KeyError, e.what());
+ }
+ });
+
+ // translate the local exception into a key error but only in this module
+ py::register_local_exception_translator([](std::exception_ptr p) {
+ try {
+ if (p) {
+ std::rethrow_exception(p);
+ }
+ } catch (const LocalException &e) {
+ PyErr_SetString(PyExc_KeyError, e.what());
+ }
+ });
// test_local_bindings.py
// Local to both:
- bind_local<LocalType, 1>(m, "LocalType", py::module_local())
- .def("get2", [](LocalType &t) { return t.i + 2; })
- ;
+ 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; });
@@ -43,9 +76,7 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
// 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");
- });
+ 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:
@@ -55,27 +86,21 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
// 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");
- });
+ 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));
- });
+ 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_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));
});
@@ -83,25 +108,26 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
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(); });
+ m.def("local_cpp_types_addr",
+ []() { return (uintptr_t) &py::detail::get_local_internals().registered_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);
- });
+ 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);
+ class Dog : public pets::Pet {
+ public:
+ explicit Dog(std::string name) : Pet(std::move(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>());
+ 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>());
@@ -118,6 +144,6 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
// 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_arg", [](const 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
index 439cd401..aa309559 100644
--- a/3rdparty/pybind11/tests/pybind11_tests.cpp
+++ b/3rdparty/pybind11/tests/pybind11_tests.cpp
@@ -8,6 +8,7 @@
*/
#include "pybind11_tests.h"
+
#include "constructor_stats.h"
#include <functional>
@@ -31,9 +32,7 @@ std::list<std::function<void(py::module_ &)>> &initializers() {
return inits;
}
-test_initializer::test_initializer(Initializer init) {
- initializers().emplace_back(init);
-}
+test_initializer::test_initializer(Initializer init) { initializers().emplace_back(init); }
test_initializer::test_initializer(const char *submodule_name, Initializer init) {
initializers().emplace_back([=](py::module_ &parent) {
@@ -51,26 +50,52 @@ void bind_ConstructorStats(py::module_ &m) {
.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)
+ .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)
+ // 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();
- })
- ;
+ });
+}
+
+const char *cpp_std() {
+ return
+#if defined(PYBIND11_CPP20)
+ "C++20";
+#elif defined(PYBIND11_CPP17)
+ "C++17";
+#elif defined(PYBIND11_CPP14)
+ "C++14";
+#else
+ "C++11";
+#endif
}
PYBIND11_MODULE(pybind11_tests, m) {
m.doc() = "pybind11 test module";
+ // Intentionally kept minimal to not create a maintenance chore
+ // ("just enough" to be conclusive).
+#if defined(_MSC_FULL_VER)
+ m.attr("compiler_info") = "MSVC " PYBIND11_TOSTRING(_MSC_FULL_VER);
+#elif defined(__VERSION__)
+ m.attr("compiler_info") = __VERSION__;
+#else
+ m.attr("compiler_info") = py::none();
+#endif
+ m.attr("cpp_std") = cpp_std();
+ m.attr("PYBIND11_INTERNALS_ID") = PYBIND11_INTERNALS_ID;
+
bind_ConstructorStats(m);
-#if !defined(NDEBUG)
- m.attr("debug_enabled") = true;
+#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
+ m.attr("detailed_error_messages_enabled") = true;
#else
- m.attr("debug_enabled") = false;
+ m.attr("detailed_error_messages_enabled") = false;
#endif
py::class_<UserType>(m, "UserType", "A `py::class_` type for testing")
@@ -79,13 +104,14 @@ PYBIND11_MODULE(pybind11_tests, m) {
.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()); });
+ .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()); });
+ .def("__repr__", [](const IncType &u) { return "IncType({})"_s.format(u.value()); });
- for (const auto &initializer : initializers())
+ for (const auto &initializer : initializers()) {
initializer(m);
+ }
}
diff --git a/3rdparty/pybind11/tests/pybind11_tests.h b/3rdparty/pybind11/tests/pybind11_tests.h
index 4ff56c07..a7c00c2f 100644
--- a/3rdparty/pybind11/tests/pybind11_tests.h
+++ b/3rdparty/pybind11/tests/pybind11_tests.h
@@ -1,10 +1,7 @@
#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
+#include <pybind11/eval.h>
+#include <pybind11/pybind11.h>
namespace py = pybind11;
using namespace pybind11::literals;
@@ -13,24 +10,23 @@ class test_initializer {
using Initializer = void (*)(py::module_ &);
public:
- test_initializer(Initializer init);
+ explicit 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)
-
+#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 { };
+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) { }
+ explicit UserType(int i) : i(i) {}
int value() const { return i; }
void set(int set) { i = set; }
@@ -44,7 +40,7 @@ class IncType : public UserType {
public:
using UserType::UserType;
IncType() = default;
- IncType(const IncType &other) : IncType(other.value() + 1) { }
+ IncType(const IncType &other) : IncType(other.value() + 1) {}
IncType(IncType &&) = delete;
IncType &operator=(const IncType &) = delete;
IncType &operator=(IncType &&) = delete;
@@ -56,16 +52,34 @@ union IntFloat {
float f;
};
-/// 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).
+/// 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 {};
PYBIND11_NAMESPACE_BEGIN(pybind11)
PYBIND11_NAMESPACE_BEGIN(detail)
-template<> class type_caster<RValueCaster> {
+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(); }
+ PYBIND11_TYPE_CASTER(RValueCaster, const_name("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();
+ }
};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(pybind11)
+
+template <typename F>
+void ignoreOldStyleInitWarnings(F &&body) {
+ py::exec(R"(
+ message = "pybind11-bound class '.+' is using an old-style placement-new '(?:__init__|__setstate__)' which has been deprecated"
+
+ import warnings
+ with warnings.catch_warnings():
+ warnings.filterwarnings("ignore", message=message, category=FutureWarning)
+ body()
+ )",
+ py::dict(py::arg("body") = py::cpp_function(body)));
+}
diff --git a/3rdparty/pybind11/tests/pytest.ini b/3rdparty/pybind11/tests/pytest.ini
index c47cbe9c..792ba361 100644
--- a/3rdparty/pybind11/tests/pytest.ini
+++ b/3rdparty/pybind11/tests/pytest.ini
@@ -1,17 +1,20 @@
[pytest]
-minversion = 3.1
+minversion = 3.10
norecursedirs = test_* extra_*
xfail_strict = True
addopts =
- # show summary of skipped tests
- -rs
+ # show summary of tests
+ -ra
# capture only Python print and C++ py::print, but not C output (low-level Python errors)
--capture=sys
- # enable all warnings
- -Wa
+ # Show local info when a failure occurs
+ --showlocals
+log_cli_level = info
filterwarnings =
# make warnings into errors but ignore certain third-party extension issues
error
+ # somehow, some DeprecationWarnings do not get turned into errors
+ always::DeprecationWarning
# importing scipy submodules on some version of Python
ignore::ImportWarning
# bogus numpy ABI warning (see numpy/#432)
diff --git a/3rdparty/pybind11/tests/requirements.txt b/3rdparty/pybind11/tests/requirements.txt
index 80ed6171..04aafa8c 100644
--- a/3rdparty/pybind11/tests/requirements.txt
+++ b/3rdparty/pybind11/tests/requirements.txt
@@ -1,8 +1,9 @@
---extra-index-url https://antocuni.github.io/pypy-wheels/manylinux2010/
-numpy==1.16.6; python_version<"3.6" and sys_platform!="win32"
-numpy==1.18.0; platform_python_implementation=="PyPy" and sys_platform=="darwin" and python_version>="3.6"
-numpy==1.19.3; (platform_python_implementation!="PyPy" or sys_platform=="linux") and python_version>="3.6" and python_version<"3.10"
-pytest==4.6.9; python_version<"3.5"
-pytest==5.4.3; python_version>="3.5"
-scipy==1.2.3; (platform_python_implementation!="PyPy" or sys_platform=="linux") and python_version<"3.6"
-scipy==1.5.2; (platform_python_implementation!="PyPy" or sys_platform=="linux") and python_version>="3.6" and python_version<"3.9"
+build==0.8.0
+numpy==1.21.5; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7"
+numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6"
+numpy==1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10"
+numpy==1.22.2; platform_python_implementation!="PyPy" and python_version>="3.10" and python_version<"3.11"
+pytest==7.0.0
+pytest-timeout
+scipy==1.5.4; platform_python_implementation!="PyPy" and python_version<"3.10"
+scipy==1.8.0; platform_python_implementation!="PyPy" and python_version=="3.10"
diff --git a/3rdparty/pybind11/tests/test_async.cpp b/3rdparty/pybind11/tests/test_async.cpp
index e6e01d72..a5d72246 100644
--- a/3rdparty/pybind11/tests/test_async.cpp
+++ b/3rdparty/pybind11/tests/test_async.cpp
@@ -11,12 +11,11 @@
TEST_SUBMODULE(async_module, m) {
struct DoesNotSupportAsync {};
- py::class_<DoesNotSupportAsync>(m, "DoesNotSupportAsync")
- .def(py::init<>());
+ 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 {
+ .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")();
diff --git a/3rdparty/pybind11/tests/test_async.py b/3rdparty/pybind11/tests/test_async.py
index df4489c4..b9ff9514 100644
--- a/3rdparty/pybind11/tests/test_async.py
+++ b/3rdparty/pybind11/tests/test_async.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
import pytest
asyncio = pytest.importorskip("asyncio")
diff --git a/3rdparty/pybind11/tests/test_buffers.cpp b/3rdparty/pybind11/tests/test_buffers.cpp
index 46eabf39..6b6e8cba 100644
--- a/3rdparty/pybind11/tests/test_buffers.cpp
+++ b/3rdparty/pybind11/tests/test_buffers.cpp
@@ -7,27 +7,31 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
-#include "constructor_stats.h"
#include <pybind11/stl.h>
+#include "constructor_stats.h"
+#include "pybind11_tests.h"
+
TEST_SUBMODULE(buffers, m) {
// test_from_python / test_to_python:
class Matrix {
public:
Matrix(py::ssize_t rows, py::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)];
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
+ 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");
+ print_copy_created(this,
+ std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
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) {
+ Matrix(Matrix &&s) noexcept : 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;
@@ -35,12 +39,17 @@ TEST_SUBMODULE(buffers, m) {
}
~Matrix() {
- print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " 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");
+ if (this == &s) {
+ return *this;
+ }
+ 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;
@@ -49,28 +58,34 @@ TEST_SUBMODULE(buffers, m) {
return *this;
}
- Matrix &operator=(Matrix &&s) {
- print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
+ Matrix &operator=(Matrix &&s) noexcept {
+ 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;
+ 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()(py::ssize_t i, py::ssize_t j) const {
- return m_data[(size_t) (i*m_cols + j)];
+ return m_data[(size_t) (i * m_cols + j)];
}
float &operator()(py::ssize_t i, py::ssize_t j) {
- return m_data[(size_t) (i*m_cols + j)];
+ return m_data[(size_t) (i * m_cols + j)];
}
float *data() { return m_data; }
py::ssize_t rows() const { return m_rows; }
py::ssize_t cols() const { return m_cols; }
+
private:
py::ssize_t m_rows;
py::ssize_t m_cols;
@@ -79,51 +94,51 @@ TEST_SUBMODULE(buffers, m) {
py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
.def(py::init<py::ssize_t, py::ssize_t>())
/// Construct from a buffer
- .def(py::init([](py::buffer const b) {
+ .def(py::init([](const py::buffer &b) {
py::buffer_info info = b.request();
- if (info.format != py::format_descriptor<float>::format() || info.ndim != 2)
+ 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]);
+ 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)
+ .def("rows", &Matrix::rows)
+ .def("cols", &Matrix::cols)
/// Bare bones interface
- .def("__getitem__", [](const Matrix &m, std::pair<py::ssize_t, py::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<py::ssize_t, py::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 {
+ .def("__getitem__",
+ [](const Matrix &m, std::pair<py::ssize_t, py::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<py::ssize_t, py::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) }
- );
- })
- ;
-
+ 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(py::ssize_t n) : Matrix(n, n) { }
+ explicit SquareMatrix(py::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<py::ssize_t>());
-
+ py::class_<SquareMatrix, Matrix>(m, "SquareMatrix").def(py::init<py::ssize_t>());
// test_pointer_to_member_fn
// Tests that passing a pointer to member to the base class works in
@@ -132,8 +147,8 @@ TEST_SUBMODULE(buffers, m) {
int32_t value = 0;
py::buffer_info get_buffer_info() {
- return py::buffer_info(&value, sizeof(value),
- py::format_descriptor<int32_t>::format(), 1);
+ return py::buffer_info(
+ &value, sizeof(value), py::format_descriptor<int32_t>::format(), 1);
}
};
py::class_<Buffer>(m, "Buffer", py::buffer_protocol())
@@ -141,7 +156,6 @@ TEST_SUBMODULE(buffers, m) {
.def_readwrite("value", &Buffer::value)
.def_buffer(&Buffer::get_buffer_info);
-
class ConstBuffer {
std::unique_ptr<int32_t> value;
@@ -150,18 +164,18 @@ TEST_SUBMODULE(buffers, m) {
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);
+ return py::buffer_info(
+ value.get(), sizeof(*value), py::format_descriptor<int32_t>::format(), 1);
}
- ConstBuffer() : value(new int32_t{0}) { };
+ 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 { };
+ struct DerivedBuffer : public Buffer {};
py::class_<DerivedBuffer>(m, "DerivedBuffer", py::buffer_protocol())
.def(py::init<>())
.def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value)
@@ -169,11 +183,9 @@ TEST_SUBMODULE(buffers, m) {
struct BufferReadOnly {
const uint8_t value = 0;
- BufferReadOnly(uint8_t value): value(value) {}
+ explicit BufferReadOnly(uint8_t value) : value(value) {}
- py::buffer_info get_buffer_info() {
- return py::buffer_info(&value, 1);
- }
+ 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>())
@@ -183,9 +195,7 @@ TEST_SUBMODULE(buffers, m) {
uint8_t value = 0;
bool readonly = false;
- py::buffer_info get_buffer_info() {
- return py::buffer_info(&value, 1, readonly);
- }
+ py::buffer_info get_buffer_info() { return py::buffer_info(&value, 1, readonly); }
};
py::class_<BufferReadOnlySelect>(m, "BufferReadOnlySelect", py::buffer_protocol())
.def(py::init<>())
@@ -204,11 +214,11 @@ TEST_SUBMODULE(buffers, m) {
.def_readonly("strides", &py::buffer_info::strides)
.def_readonly("readonly", &py::buffer_info::readonly)
.def("__repr__", [](py::handle self) {
- return py::str("itemsize={0.itemsize!r}, size={0.size!r}, format={0.format!r}, ndim={0.ndim!r}, shape={0.shape!r}, strides={0.strides!r}, readonly={0.readonly!r}").format(self);
- })
- ;
+ return py::str("itemsize={0.itemsize!r}, size={0.size!r}, format={0.format!r}, "
+ "ndim={0.ndim!r}, shape={0.shape!r}, strides={0.strides!r}, "
+ "readonly={0.readonly!r}")
+ .format(self);
+ });
- m.def("get_buffer_info", [](py::buffer buffer) {
- return buffer.request();
- });
+ m.def("get_buffer_info", [](const py::buffer &buffer) { return buffer.request(); });
}
diff --git a/3rdparty/pybind11/tests/test_buffers.py b/3rdparty/pybind11/tests/test_buffers.py
index f0f37084..8354b68c 100644
--- a/3rdparty/pybind11/tests/test_buffers.py
+++ b/3rdparty/pybind11/tests/test_buffers.py
@@ -1,14 +1,12 @@
-# -*- coding: utf-8 -*-
+import ctypes
import io
import struct
-import ctypes
import pytest
-import env # noqa: F401
-
-from pybind11_tests import buffers as m
+import env
from pybind11_tests import ConstructorStats
+from pybind11_tests import buffers as m
np = pytest.importorskip("numpy")
@@ -37,6 +35,10 @@ def test_from_python():
# https://foss.heptapod.net/pypy/pypy/-/issues/2444
+# TODO: fix on recent PyPy
+@pytest.mark.xfail(
+ env.PYPY, reason="PyPy 7.3.7 doesn't clear this anymore", strict=False
+)
def test_to_python():
mat = m.Matrix(5, 4)
assert memoryview(mat).shape == (5, 4)
@@ -90,14 +92,16 @@ def test_pointer_to_member_fn():
def test_readonly_buffer():
buf = m.BufferReadOnly(0x64)
view = memoryview(buf)
- assert view[0] == b"d" if env.PY2 else 0x64
+ assert view[0] == 0x64
assert view.readonly
+ with pytest.raises(TypeError):
+ view[0] = 0
def test_selective_readonly_buffer():
buf = m.BufferReadOnlySelect()
- memoryview(buf)[0] = b"d" if env.PY2 else 0x64
+ memoryview(buf)[0] = 0x64
assert buf.value == 0x64
io.BytesIO(b"A").readinto(buf)
@@ -105,7 +109,7 @@ def test_selective_readonly_buffer():
buf.readonly = True
with pytest.raises(TypeError):
- memoryview(buf)[0] = b"\0" if env.PY2 else 0
+ memoryview(buf)[0] = 0
with pytest.raises(TypeError):
io.BytesIO(b"1").readinto(buf)
@@ -140,9 +144,6 @@ def test_ctypes_array_2d():
assert not info.readonly
-@pytest.mark.skipif(
- "env.PYPY and env.PY2", reason="PyPy2 bytes buffer not reported as readonly"
-)
def test_ctypes_from_buffer():
test_pystr = b"0123456789"
for pyarray in (test_pystr, bytearray(test_pystr)):
diff --git a/3rdparty/pybind11/tests/test_builtin_casters.cpp b/3rdparty/pybind11/tests/test_builtin_casters.cpp
index acc9f8fb..6ff63edf 100644
--- a/3rdparty/pybind11/tests/test_builtin_casters.cpp
+++ b/3rdparty/pybind11/tests/test_builtin_casters.cpp
@@ -7,40 +7,117 @@
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
+#include "pybind11_tests.h"
+
+struct ConstRefCasted {
+ int tag;
+};
+
+PYBIND11_NAMESPACE_BEGIN(pybind11)
+PYBIND11_NAMESPACE_BEGIN(detail)
+template <>
+class type_caster<ConstRefCasted> {
+public:
+ static constexpr auto name = const_name<ConstRefCasted>();
+
+ // Input is unimportant, a new value will always be constructed based on the
+ // cast operator.
+ bool load(handle, bool) { return true; }
+
+ explicit operator ConstRefCasted &&() {
+ value = {1};
+ // NOLINTNEXTLINE(performance-move-const-arg)
+ return std::move(value);
+ }
+ explicit operator ConstRefCasted &() {
+ value = {2};
+ return value;
+ }
+ explicit operator ConstRefCasted *() {
+ value = {3};
+ return &value;
+ }
+
+ explicit operator const ConstRefCasted &() {
+ value = {4};
+ return value;
+ }
+ explicit operator const ConstRefCasted *() {
+ value = {5};
+ return &value;
+ }
+
+ // custom cast_op to explicitly propagate types to the conversion operators.
+ template <typename T_>
+ using cast_op_type =
+ /// const
+ conditional_t<
+ std::is_same<remove_reference_t<T_>, const ConstRefCasted *>::value,
+ const ConstRefCasted *,
+ conditional_t<
+ std::is_same<T_, const ConstRefCasted &>::value,
+ const ConstRefCasted &,
+ /// non-const
+ conditional_t<std::is_same<remove_reference_t<T_>, ConstRefCasted *>::value,
+ ConstRefCasted *,
+ conditional_t<std::is_same<T_, ConstRefCasted &>::value,
+ ConstRefCasted &,
+ /* else */ ConstRefCasted &&>>>>;
+
+private:
+ ConstRefCasted value = {0};
+};
+PYBIND11_NAMESPACE_END(detail)
+PYBIND11_NAMESPACE_END(pybind11)
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;
+ // 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(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
+ if (PYBIND11_SILENCE_MSVC_C4127(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_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("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 didn't appear to trigger
+ // UnicodeDecodeError
+ m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); });
+ if (PYBIND11_SILENCE_MSVC_C4127(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; });
@@ -58,12 +135,17 @@ TEST_SUBMODULE(builtin_casters, m) {
// test_bytes_to_string
m.def("strlen", [](char *s) { return strlen(s); });
- m.def("string_length", [](std::string s) { return s.length(); });
+ m.def("string_length", [](const 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("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'; });
@@ -75,21 +157,72 @@ TEST_SUBMODULE(builtin_casters, m) {
// 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_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_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"); });
+
+ // The inner lambdas here are to also test implicit conversion
+ using namespace std::literals;
+ m.def("string_view_bytes",
+ []() { return [](py::bytes b) { return b; }("abc \x80\x80 def"sv); });
+ m.def("string_view_str",
+ []() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); });
+ m.def("string_view_from_bytes",
+ [](const py::bytes &b) { return [](std::string_view s) { return s; }(b); });
+ m.def("string_view_memoryview", []() {
+ static constexpr auto val = "Have some \360\237\216\202"sv;
+ return py::memoryview::from_memory(val);
+ });
+
+# 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
+ m.def("string_view8_str", []() { return py::str{std::u8string_view{u8"abc ‽ def"}}; });
+# endif
+
+ struct TypeWithBothOperatorStringAndStringView {
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ operator std::string() const { return "success"; }
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ operator std::string_view() const { return "failure"; }
+ };
+ m.def("bytes_from_type_with_both_operator_string_and_string_view",
+ []() { return py::bytes(TypeWithBothOperatorStringAndStringView()); });
+ m.def("str_from_type_with_both_operator_string_and_string_view",
+ []() { return py::str(TypeWithBothOperatorStringAndStringView()); });
#endif
// test_integer_casting
@@ -98,71 +231,121 @@ TEST_SUBMODULE(builtin_casters, m) {
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_int_convert
+ m.def("int_passthrough", [](int arg) { return arg; });
+ m.def(
+ "int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert());
+
// 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(
+ "pair_passthrough",
+ [](const 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;
+ 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("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{}))); });
+ return std::make_pair(
+ RValueCaster{},
+ std::make_tuple(RValueCaster{}, std::make_pair(RValueCaster{}, RValueCaster{})));
+ });
m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; });
- static std::pair<int, std::string> int_string_pair{2, "items"};
- m.def("int_string_pair", []() { return &int_string_pair; });
+ m.def(
+ "int_string_pair",
+ []() {
+ // Using no-destructor idiom to side-step warnings from overzealous compilers.
+ static auto *int_string_pair = new std::pair<int, std::string>{2, "items"};
+ return int_string_pair;
+ },
+ py::return_value_policy::reference);
// 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; });
- m.def("return_none_pair", []() -> std::pair<int,int> * { 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; });
+ m.def("return_none_pair", []() -> std::pair<int, int> * { 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_cstring", [](const py::none &) { return true; });
m.def("defer_none_custom", [](UserType *) { return false; });
- m.def("defer_none_custom", [](py::none) { return true; });
+ m.def("defer_none_custom", [](const py::none &) { return true; });
m.def("nodefer_none_void", [](void *) { return true; });
- m.def("nodefer_none_void", [](py::none) { return false; });
+ m.def("nodefer_none_void", [](const 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{}; });
+ // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
+
// test_bool_caster
m.def("bool_passthrough", [](bool arg) { return arg; });
- m.def("bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg().noconvert());
+ m.def(
+ "bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert());
+
+ // TODO: This should be disabled and fixed in future Intel compilers
+#if !defined(__INTEL_COMPILER)
+ // Test "bool_passthrough_noconvert" again, but using () instead of {} to construct py::arg
+ // When compiled with the Intel compiler, this results in segmentation faults when importing
+ // the module. Tested with icc (ICC) 2021.1 Beta 20200827, this should be tested again when
+ // a newer version of icc is available.
+ m.def(
+ "bool_passthrough_noconvert2", [](bool arg) { return arg; }, py::arg().noconvert());
+#endif
// 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(); });
+ m.def("refwrap_usertype_const",
+ [](std::reference_wrapper<const UserType> p) { return p.get().value(); });
+
+ m.def("refwrap_lvalue", []() -> std::reference_wrapper<UserType> {
+ static UserType x(1);
+ return std::ref(x);
+ });
+ m.def("refwrap_lvalue_const", []() -> std::reference_wrapper<const UserType> {
+ static UserType x(1);
+ return std::cref(x);
+ });
+
// 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_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_list",
+ [](bool copy) {
+ static IncType x1(1), x2(2);
+ py::list l;
+ for (const 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) {
+ m.def("refwrap_call_iiw", [](IncType &w, const py::function &f) {
py::list l;
l.append(f(std::ref(w)));
l.append(f(std::cref(w)));
@@ -176,12 +359,13 @@ TEST_SUBMODULE(builtin_casters, m) {
// 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()); });
+ 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;});
+ 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 {
@@ -189,4 +373,15 @@ TEST_SUBMODULE(builtin_casters, m) {
py::object o = py::cast(v);
return py::cast<void *>(o) == v;
});
+
+ // Tests const/non-const propagation in cast_op.
+ m.def("takes", [](ConstRefCasted x) { return x.tag; });
+ m.def("takes_move", [](ConstRefCasted &&x) { return x.tag; });
+ m.def("takes_ptr", [](ConstRefCasted *x) { return x->tag; });
+ m.def("takes_ref", [](ConstRefCasted &x) { return x.tag; });
+ m.def("takes_ref_wrap", [](std::reference_wrapper<ConstRefCasted> x) { return x.get().tag; });
+ m.def("takes_const_ptr", [](const ConstRefCasted *x) { return x->tag; });
+ m.def("takes_const_ref", [](const ConstRefCasted &x) { return x.tag; });
+ m.def("takes_const_ref_wrap",
+ [](std::reference_wrapper<const ConstRefCasted> x) { return x.get().tag; });
}
diff --git a/3rdparty/pybind11/tests/test_builtin_casters.py b/3rdparty/pybind11/tests/test_builtin_casters.py
index bd7996b6..d38ae680 100644
--- a/3rdparty/pybind11/tests/test_builtin_casters.py
+++ b/3rdparty/pybind11/tests/test_builtin_casters.py
@@ -1,10 +1,10 @@
-# -*- coding: utf-8 -*-
-import pytest
+import sys
-import env # noqa: F401
+import pytest
+import env
+from pybind11_tests import IncType, UserType
from pybind11_tests import builtin_casters as m
-from pybind11_tests import UserType, IncType
def test_simple_string():
@@ -13,12 +13,12 @@ def test_simple_string():
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"
+ assert m.good_utf8_string() == "Say utf8‽ 🎂 𝐀"
+ assert m.good_utf16_string() == "b‽🎂𝐀z"
+ assert m.good_utf32_string() == "a𝐀🎂‽z"
+ assert m.good_wchar_string() == "a⸘𝐀z"
if hasattr(m, "has_u8string"):
- assert m.good_utf8_u8string() == u"Say utf8‽ 🎂 𝐀"
+ assert m.good_utf8_u8string() == "Say utf8‽ 🎂 𝐀"
with pytest.raises(UnicodeDecodeError):
m.bad_utf8_string()
@@ -26,7 +26,7 @@ def test_unicode_conversion():
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)
+ # These are provided only if they actually fail (they don't when 32-bit)
if hasattr(m, "bad_utf32_string"):
with pytest.raises(UnicodeDecodeError):
m.bad_utf32_string()
@@ -38,10 +38,10 @@ def test_unicode_conversion():
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"♥"
+ assert m.u8_eacute() == "é"
+ assert m.u16_ibang() == "‽"
+ assert m.u32_mathbfA() == "𝐀"
+ assert m.wchar_heart() == "♥"
if hasattr(m, "has_u8string"):
assert m.u8_char8_Z() == "Z"
@@ -50,72 +50,72 @@ 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)
+ return f"Character code point not in range({r:#x})"
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("a") == 0x61 # simple ASCII
+ assert m.ord_char_lv("b") == 0x62
assert (
- m.ord_char(u"é") == 0xE9
+ m.ord_char("é") == 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 m.ord_char("Ā") == 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 m.ord_char("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
+ assert m.ord_char16("a") == 0x61
+ assert m.ord_char16("é") == 0xE9
+ assert m.ord_char16_lv("ê") == 0xEA
+ assert m.ord_char16("Ā") == 0x100
+ assert m.ord_char16("‽") == 0x203D
+ assert m.ord_char16("♥") == 0x2665
+ assert m.ord_char16_lv("♡") == 0x2661
with pytest.raises(ValueError) as excinfo:
- assert m.ord_char16(u"🎂") == 0x1F382 # requires surrogate pair
+ assert m.ord_char16("🎂") == 0x1F382 # requires surrogate pair
assert str(excinfo.value) == toobig_message(0x10000)
with pytest.raises(ValueError) as excinfo:
- assert m.ord_char16(u"aa")
+ assert m.ord_char16("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
+ assert m.ord_char32("a") == 0x61
+ assert m.ord_char32("é") == 0xE9
+ assert m.ord_char32("Ā") == 0x100
+ assert m.ord_char32("‽") == 0x203D
+ assert m.ord_char32("♥") == 0x2665
+ assert m.ord_char32("🎂") == 0x1F382
with pytest.raises(ValueError) as excinfo:
- assert m.ord_char32(u"aa")
+ assert m.ord_char32("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
+ assert m.ord_wchar("a") == 0x61
+ assert m.ord_wchar("é") == 0xE9
+ assert m.ord_wchar("Ā") == 0x100
+ assert m.ord_wchar("‽") == 0x203D
+ assert m.ord_wchar("♥") == 0x2665
if m.wchar_size == 2:
with pytest.raises(ValueError) as excinfo:
- assert m.ord_wchar(u"🎂") == 0x1F382 # requires surrogate pair
+ assert m.ord_wchar("🎂") == 0x1F382 # requires surrogate pair
assert str(excinfo.value) == toobig_message(0x10000)
else:
- assert m.ord_wchar(u"🎂") == 0x1F382
+ assert m.ord_wchar("🎂") == 0x1F382
with pytest.raises(ValueError) as excinfo:
- assert m.ord_wchar(u"aa")
+ assert m.ord_wchar("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("a") == 0x61 # simple ASCII
+ assert m.ord_char8_lv("b") == 0x62
assert (
- m.ord_char8(u"é") == 0xE9
+ m.ord_char8("é") == 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 m.ord_char8("Ā") == 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 m.ord_char8("ab")
assert str(excinfo.value) == toolong_message
@@ -124,18 +124,22 @@ def test_bytes_to_string():
one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
# Issue #816
- def to_bytes(s):
- b = s if env.PY2 else s.encode("utf8")
- assert isinstance(b, bytes)
- return b
-
- assert m.strlen(to_bytes("hi")) == 2
- assert m.string_length(to_bytes("world")) == 5
- assert m.string_length(to_bytes("a\x00b")) == 3
- assert m.strlen(to_bytes("a\x00b")) == 1 # C-string limitation
+ assert m.strlen(b"hi") == 2
+ assert m.string_length(b"world") == 5
+ assert m.string_length("a\x00b".encode()) == 3
+ assert m.strlen("a\x00b".encode()) == 1 # C-string limitation
# passing in a utf8 encoded string should work
- assert m.string_length(u"💩".encode("utf8")) == 4
+ assert m.string_length("💩".encode()) == 4
+
+
+def test_bytearray_to_string():
+ """Tests the ability to pass bytearray to C++ string-accepting functions"""
+ assert m.string_length(bytearray(b"Hi")) == 2
+ assert m.strlen(bytearray(b"bytearray")) == 9
+ assert m.string_length(bytearray()) == 0
+ assert m.string_length(bytearray("🦜", "utf-8", "strict")) == 4
+ assert m.string_length(bytearray(b"\x80")) == 1
@pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")
@@ -143,26 +147,26 @@ 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(u"Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82]
- assert m.string_view32_chars(u"Hi 🎂") == [72, 105, 32, 127874]
+ 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(u"Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
+ assert m.string_view8_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
- assert m.string_view_return() == u"utf8 secret 🎂"
- assert m.string_view16_return() == u"utf16 secret 🎂"
- assert m.string_view32_return() == u"utf32 secret 🎂"
+ 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() == u"utf8 secret 🎂"
+ assert m.string_view8_return() == "utf8 secret 🎂"
with capture:
m.string_view_print("Hi")
m.string_view_print("utf8 🎂")
- m.string_view16_print(u"utf16 🎂")
- m.string_view32_print(u"utf32 🎂")
+ m.string_view16_print("utf16 🎂")
+ m.string_view32_print("utf32 🎂")
assert (
capture
- == u"""
+ == """
Hi 2
utf8 🎂 9
utf16 🎂 8
@@ -172,10 +176,10 @@ def test_string_view(capture):
if hasattr(m, "has_u8string"):
with capture:
m.string_view8_print("Hi")
- m.string_view8_print(u"utf8 🎂")
+ m.string_view8_print("utf8 🎂")
assert (
capture
- == u"""
+ == """
Hi 2
utf8 🎂 9
"""
@@ -184,11 +188,11 @@ def test_string_view(capture):
with capture:
m.string_view_print("Hi, ascii")
m.string_view_print("Hi, utf8 🎂")
- m.string_view16_print(u"Hi, utf16 🎂")
- m.string_view32_print(u"Hi, utf32 🎂")
+ m.string_view16_print("Hi, utf16 🎂")
+ m.string_view32_print("Hi, utf32 🎂")
assert (
capture
- == u"""
+ == """
Hi, ascii 9
Hi, utf8 🎂 13
Hi, utf16 🎂 12
@@ -198,15 +202,25 @@ def test_string_view(capture):
if hasattr(m, "has_u8string"):
with capture:
m.string_view8_print("Hi, ascii")
- m.string_view8_print(u"Hi, utf8 🎂")
+ m.string_view8_print("Hi, utf8 🎂")
assert (
capture
- == u"""
+ == """
Hi, ascii 9
Hi, utf8 🎂 13
"""
)
+ assert m.string_view_bytes() == b"abc \x80\x80 def"
+ assert m.string_view_str() == "abc ‽ def"
+ assert m.string_view_from_bytes("abc ‽ def".encode()) == "abc ‽ def"
+ if hasattr(m, "has_u8string"):
+ assert m.string_view8_str() == "abc ‽ def"
+ assert m.string_view_memoryview() == "Have some 🎂".encode()
+
+ assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success"
+ assert m.str_from_type_with_both_operator_string_and_string_view() == "success"
+
def test_integer_casting():
"""Issue #929 - out-of-range integer values shouldn't be accepted"""
@@ -214,20 +228,8 @@ def test_integer_casting():
assert m.i64_str(-1) == "-1"
assert m.i32_str(2000000000) == "2000000000"
assert m.u32_str(2000000000) == "2000000000"
- if env.PY2:
- 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)) # noqa: F821 undefined name 'long'
- == "-999999999999"
- )
- assert (
- m.u64_str(long(999999999999)) # noqa: F821 undefined name 'long'
- == "999999999999"
- )
- else:
- assert m.i64_str(-999999999999) == "-999999999999"
- assert m.u64_str(999999999999) == "999999999999"
+ assert m.i64_str(-999999999999) == "-999999999999"
+ assert m.u64_str(999999999999) == "999999999999"
with pytest.raises(TypeError) as excinfo:
m.u32_str(-1)
@@ -242,13 +244,100 @@ def test_integer_casting():
m.i32_str(3000000000)
assert "incompatible function arguments" in str(excinfo.value)
- if env.PY2:
- 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_int_convert():
+ class Int:
+ def __int__(self):
+ return 42
+
+ class NotInt:
+ pass
+
+ class Float:
+ def __float__(self):
+ return 41.99999
+
+ class Index:
+ def __index__(self):
+ return 42
+
+ class IntAndIndex:
+ def __int__(self):
+ return 42
+
+ def __index__(self):
+ return 0
+
+ class RaisingTypeErrorOnIndex:
+ def __index__(self):
+ raise TypeError
+
+ def __int__(self):
+ return 42
+
+ class RaisingValueErrorOnIndex:
+ def __index__(self):
+ raise ValueError
+
+ def __int__(self):
+ return 42
+
+ convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
+
+ def requires_conversion(v):
+ pytest.raises(TypeError, noconvert, v)
+
+ def cant_convert(v):
+ pytest.raises(TypeError, convert, v)
+
+ assert convert(7) == 7
+ assert noconvert(7) == 7
+ cant_convert(3.14159)
+ # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
+ # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
+ if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
+ with env.deprecated_call():
+ assert convert(Int()) == 42
+ else:
+ assert convert(Int()) == 42
+ requires_conversion(Int())
+ cant_convert(NotInt())
+ cant_convert(Float())
+
+ # Before Python 3.8, `PyLong_AsLong` does not pick up on `obj.__index__`,
+ # but pybind11 "backports" this behavior.
+ assert convert(Index()) == 42
+ assert noconvert(Index()) == 42
+ assert convert(IntAndIndex()) == 0 # Fishy; `int(DoubleThought)` == 42
+ assert noconvert(IntAndIndex()) == 0
+ assert convert(RaisingTypeErrorOnIndex()) == 42
+ requires_conversion(RaisingTypeErrorOnIndex())
+ assert convert(RaisingValueErrorOnIndex()) == 42
+ requires_conversion(RaisingValueErrorOnIndex())
+
+
+def test_numpy_int_convert():
+ np = pytest.importorskip("numpy")
+
+ convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
+
+ def require_implicit(v):
+ pytest.raises(TypeError, noconvert, v)
+
+ # `np.intc` is an alias that corresponds to a C++ `int`
+ assert convert(np.intc(42)) == 42
+ assert noconvert(np.intc(42)) == 42
+
+ # The implicit conversion from np.float32 is undesirable but currently accepted.
+ # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
+ # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
+ # https://github.com/pybind/pybind11/issues/3408
+ if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
+ with env.deprecated_call():
+ assert convert(np.float32(3.14159)) == 3
+ else:
+ assert convert(np.float32(3.14159)) == 3
+ require_implicit(np.float32(3.14159))
def test_tuple(doc):
@@ -315,6 +404,7 @@ 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
+ assert m.refwrap_usertype_const(UserType(42)) == 42
with pytest.raises(TypeError) as excinfo:
m.refwrap_builtin(None)
@@ -324,6 +414,9 @@ def test_reference_wrapper():
m.refwrap_usertype(None)
assert "incompatible function arguments" in str(excinfo.value)
+ assert m.refwrap_lvalue().value == 1
+ assert m.refwrap_lvalue_const().value == 1
+
a1 = m.refwrap_list(copy=True)
a2 = m.refwrap_list(copy=True)
assert [x.value for x in a1] == [2, 3]
@@ -366,7 +459,7 @@ def test_bool_caster():
require_implicit(None)
assert convert(None) is False
- class A(object):
+ class A:
def __init__(self, x):
self.x = x
@@ -376,7 +469,7 @@ def test_bool_caster():
def __bool__(self):
return self.x
- class B(object):
+ class B:
pass
# Arbitrary objects are not accepted
@@ -406,18 +499,28 @@ def test_numpy_bool():
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)
+ assert isinstance(m.longlong_cast(), int)
def test_void_caster_2():
assert m.test_void_caster()
+
+
+def test_const_ref_caster():
+ """Verifies that const-ref is propagated through type_caster cast_op.
+ The returned ConstRefCasted type is a minimal type that is constructed to
+ reference the casting mode used.
+ """
+ x = False
+ assert m.takes(x) == 1
+ assert m.takes_move(x) == 1
+
+ assert m.takes_ptr(x) == 3
+ assert m.takes_ref(x) == 2
+ assert m.takes_ref_wrap(x) == 2
+
+ assert m.takes_const_ptr(x) == 5
+ assert m.takes_const_ref(x) == 4
+ assert m.takes_const_ref_wrap(x) == 4
diff --git a/3rdparty/pybind11/tests/test_call_policies.cpp b/3rdparty/pybind11/tests/test_call_policies.cpp
index 26c83f81..d177008c 100644
--- a/3rdparty/pybind11/tests/test_call_policies.cpp
+++ b/3rdparty/pybind11/tests/test_call_policies.cpp
@@ -40,17 +40,17 @@ TEST_SUBMODULE(call_policies, m) {
Child(Child &&) = default;
~Child() { py::print("Releasing child."); }
};
- py::class_<Child>(m, "Child")
- .def(py::init<>());
+ py::class_<Child>(m, "Child").def(py::init<>());
class Parent {
public:
Parent() { py::print("Allocating parent."); }
- Parent(const Parent& parent) = default;
+ Parent(const Parent &parent) = default;
~Parent() { py::print("Releasing parent."); }
- void addChild(Child *) { }
+ void addChild(Child *) {}
Child *returnChild() { return new Child(); }
Child *returnNullChild() { return nullptr; }
+ static Child *staticFunction(Parent *) { return new Child(); }
};
py::class_<Parent>(m, "Parent")
.def(py::init<>())
@@ -60,7 +60,13 @@ TEST_SUBMODULE(call_policies, m) {
.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>());
+ .def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>())
+ .def_static("staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>());
+
+ m.def(
+ "free_function", [](Parent *, Child *) {}, py::keep_alive<1, 2>());
+ m.def(
+ "invalid_arg_index", [] {}, py::keep_alive<0, 1>());
#if !defined(PYPY_VERSION)
// test_alive_gc
@@ -68,29 +74,37 @@ TEST_SUBMODULE(call_policies, m) {
public:
using Parent::Parent;
};
- py::class_<ParentGC, Parent>(m, "ParentGC", py::dynamic_attr())
- .def(py::init<>());
+ 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>());
+ 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())
+ if (auto *tstate = py::detail::get_thread_state_unchecked()) {
is_gil_held = (tstate == PyGILState_GetThisThreadState());
+ }
return is_gil_held ? "GIL held" : "GIL released";
};
diff --git a/3rdparty/pybind11/tests/test_call_policies.py b/3rdparty/pybind11/tests/test_call_policies.py
index e0413d14..61605641 100644
--- a/3rdparty/pybind11/tests/test_call_policies.py
+++ b/3rdparty/pybind11/tests/test_call_policies.py
@@ -1,10 +1,8 @@
-# -*- coding: utf-8 -*-
import pytest
import env # noqa: F401
-
-from pybind11_tests import call_policies as m
from pybind11_tests import ConstructorStats
+from pybind11_tests import call_policies as m
@pytest.mark.xfail("env.PYPY", reason="sometimes comes out 1 off on PyPy", strict=False)
@@ -46,6 +44,19 @@ def test_keep_alive_argument(capture):
"""
)
+ p = m.Parent()
+ c = m.Child()
+ assert ConstructorStats.detail_reg_inst() == n_inst + 2
+ m.free_function(p, c)
+ del c
+ assert ConstructorStats.detail_reg_inst() == n_inst + 2
+ del p
+ assert ConstructorStats.detail_reg_inst() == n_inst
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.invalid_arg_index()
+ assert str(excinfo.value) == "Could not activate keep_alive!"
+
def test_keep_alive_return_value(capture):
n_inst = ConstructorStats.detail_reg_inst()
@@ -85,6 +96,23 @@ def test_keep_alive_return_value(capture):
"""
)
+ p = m.Parent()
+ assert ConstructorStats.detail_reg_inst() == n_inst + 1
+ with capture:
+ m.Parent.staticFunction(p)
+ 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://foss.heptapod.net/pypy/pypy/-/issues/2447
@pytest.mark.xfail("env.PYPY", reason="_PyObject_GetDictPtr is unimplemented")
diff --git a/3rdparty/pybind11/tests/test_callbacks.cpp b/3rdparty/pybind11/tests/test_callbacks.cpp
index 683dfb3e..92b8053d 100644
--- a/3rdparty/pybind11/tests/test_callbacks.cpp
+++ b/3rdparty/pybind11/tests/test_callbacks.cpp
@@ -7,72 +7,79 @@
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>
+#include "constructor_stats.h"
+#include "pybind11_tests.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_callback1", [](const py::object &func) { return func(); });
+ m.def("test_callback2", [](const 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"));
+ 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) {
+ m.def("test_tuple_unpacking", [](const 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);
+ m.def("test_dict_unpacking", [](const py::function &f) {
+ auto d1 = py::dict("key"_a = "value", "a"_a = 1);
auto d2 = py::dict();
- auto d3 = py::dict("b"_a=2);
+ 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_keyword_args", [](const py::function &f) { return f("x"_a = 10, "y"_a = 20); });
- m.def("test_unpacking_and_keywords1", [](py::function f) {
+ m.def("test_unpacking_and_keywords1", [](const py::function &f) {
auto args = py::make_tuple(2);
- auto kwargs = py::dict("d"_a=4);
- return f(1, *args, "c"_a=3, **kwargs);
+ 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_and_keywords2", [](const 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_error1", [](const 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_unpacking_error2", [](const 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_error1",
+ [](const 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);
+ m.def("test_arg_conversion_error2", [](const py::function &f) {
+ f(234, "expected_name"_a = UnregisteredType(), "kw"_a = 567);
});
// test_lambda_closure_cleanup
@@ -80,49 +87,99 @@ TEST_SUBMODULE(callbacks, m) {
Payload() { print_default_created(this); }
~Payload() { print_destroyed(this); }
Payload(const Payload &) { print_copy_created(this); }
- Payload(Payload &&) { print_move_created(this); }
+ Payload(Payload &&) noexcept { 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)> {
+ m.def("test_lambda_closure_cleanup", []() -> std::function<void()> {
Payload p;
+ // In this situation, `Func` in the implementation of
+ // `cpp_function::initialize` is NOT trivially destructible.
return [p]() {
/* p should be cleaned up when the returned function is garbage collected */
(void) p;
};
});
+ class CppCallable {
+ public:
+ CppCallable() { track_default_created(this); }
+ ~CppCallable() { track_destroyed(this); }
+ CppCallable(const CppCallable &) { track_copy_created(this); }
+ CppCallable(CppCallable &&) noexcept { track_move_created(this); }
+ void operator()() {}
+ };
+
+ m.def("test_cpp_callable_cleanup", []() {
+ // Related issue: https://github.com/pybind/pybind11/issues/3228
+ // Related PR: https://github.com/pybind/pybind11/pull/3229
+ py::list alive_counts;
+ ConstructorStats &stat = ConstructorStats::get<CppCallable>();
+ alive_counts.append(stat.alive());
+ {
+ CppCallable cpp_callable;
+ alive_counts.append(stat.alive());
+ {
+ // In this situation, `Func` in the implementation of
+ // `cpp_function::initialize` IS trivially destructible,
+ // only `capture` is not.
+ py::cpp_function py_func(cpp_callable);
+ py::detail::silence_unused_warnings(py_func);
+ alive_counts.append(stat.alive());
+ }
+ alive_counts.append(stat.alive());
+ {
+ py::cpp_function py_func(std::move(cpp_callable));
+ py::detail::silence_unused_warnings(py_func);
+ alive_counts.append(stat.alive());
+ }
+ alive_counts.append(stat.alive());
+ }
+ alive_counts.append(stat.alive());
+ return alive_counts;
+ });
+
// 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_function_overloaded", [](int i, int j) { return i + j; });
+ m.def("dummy_function_overloaded", &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(
+ "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>();
+ const 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) {
+ }
+ 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!";
}
+ return "argument does NOT match dummy_function. This should never happen!";
});
class AbstractBase {
public:
- virtual ~AbstractBase() = default;
+ // [workaround(intel)] = default does not work here
+ // Defaulting this destructor results in linking errors with the Intel compiler
+ // (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
+ virtual ~AbstractBase() {} // NOLINT(modernize-use-equals-default)
virtual unsigned int func() = 0;
};
- m.def("func_accepting_func_accepting_base", [](std::function<double(AbstractBase&)>) { });
+ m.def("func_accepting_func_accepting_base",
+ [](const std::function<double(AbstractBase &)> &) {});
struct MovableObject {
bool valid = true;
@@ -130,8 +187,8 @@ TEST_SUBMODULE(callbacks, m) {
MovableObject() = default;
MovableObject(const MovableObject &) = default;
MovableObject &operator=(const MovableObject &) = default;
- MovableObject(MovableObject &&o) : valid(o.valid) { o.valid = false; }
- MovableObject &operator=(MovableObject &&o) {
+ MovableObject(MovableObject &&o) noexcept : valid(o.valid) { o.valid = false; }
+ MovableObject &operator=(MovableObject &&o) noexcept {
valid = o.valid;
o.valid = false;
return *this;
@@ -140,9 +197,9 @@ TEST_SUBMODULE(callbacks, m) {
py::class_<MovableObject>(m, "MovableObject");
// test_movable_object
- m.def("callback_with_movable", [](std::function<void(MovableObject &)> f) {
+ m.def("callback_with_movable", [](const std::function<void(MovableObject &)> &f) {
auto x = MovableObject();
- f(x); // lvalue reference shouldn't move out object
+ f(x); // lvalue reference shouldn't move out object
return x.valid; // must still return `true`
});
@@ -152,9 +209,16 @@ TEST_SUBMODULE(callbacks, m) {
.def(py::init<>())
.def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; });
+ // This checks that builtin functions can be passed as callbacks
+ // rather than throwing RuntimeError due to trying to extract as capsule
+ m.def("test_sum_builtin",
+ [](const std::function<double(py::iterable)> &sum_builtin, const py::iterable &i) {
+ return sum_builtin(i);
+ });
+
// test async Python callbacks
using callback_f = std::function<void(int)>;
- m.def("test_async_callback", [](callback_f f, py::list work) {
+ m.def("test_async_callback", [](const callback_f &f, const 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] {
@@ -166,7 +230,14 @@ TEST_SUBMODULE(callbacks, m) {
};
// spawn worker threads
- for (auto i : work)
+ for (auto i : work) {
start_f(py::cast<int>(i));
+ }
+ });
+
+ m.def("callback_num_times", [](const py::function &f, std::size_t num) {
+ for (std::size_t i = 0; i < num; i++) {
+ f();
+ }
});
}
diff --git a/3rdparty/pybind11/tests/test_callbacks.py b/3rdparty/pybind11/tests/test_callbacks.py
index 039b877c..0b1047bb 100644
--- a/3rdparty/pybind11/tests/test_callbacks.py
+++ b/3rdparty/pybind11/tests/test_callbacks.py
@@ -1,7 +1,10 @@
-# -*- coding: utf-8 -*-
+import time
+from threading import Thread
+
import pytest
+
+import env # noqa: F401
from pybind11_tests import callbacks as m
-from threading import Thread
def test_callbacks():
@@ -14,7 +17,7 @@ def test_callbacks():
return "func2", a, b, c, d
def func3(a):
- return "func3({})".format(a)
+ return f"func3({a})"
assert m.test_callback1(func1) == "func1"
assert m.test_callback2(func2) == ("func2", "Hello", "x", True, 5)
@@ -75,13 +78,18 @@ def test_keyword_args_and_generalized_unpacking():
def test_lambda_closure_cleanup():
- m.test_cleanup()
+ m.test_lambda_closure_cleanup()
cstats = m.payload_cstats()
assert cstats.alive() == 0
assert cstats.copy_constructions == 1
assert cstats.move_constructions >= 1
+def test_cpp_callable_cleanup():
+ alive_counts = m.test_cpp_callable_cleanup()
+ assert alive_counts == [0, 1, 2, 1, 2, 1, 0]
+
+
def test_cpp_function_roundtrip():
"""Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer"""
@@ -92,6 +100,10 @@ def test_cpp_function_roundtrip():
m.test_dummy_function(m.roundtrip(m.dummy_function))
== "matches dummy_function: eval(1) = 2"
)
+ assert (
+ m.test_dummy_function(m.dummy_function_overloaded)
+ == "matches dummy_function: eval(1) = 2"
+ )
assert m.roundtrip(None, expect_none=True) is None
assert (
m.test_dummy_function(lambda x: x + 2)
@@ -119,6 +131,16 @@ def test_movable_object():
assert m.callback_with_movable(lambda _: None) is True
+@pytest.mark.skipif(
+ "env.PYPY",
+ reason="PyPy segfaults on here. See discussion on #1413.",
+)
+def test_python_builtins():
+ """Test if python builtins like sum() can be used as callbacks"""
+ assert m.test_sum_builtin(sum, [1, 2, 3]) == 6
+ assert m.test_sum_builtin(sum, []) == 0
+
+
def test_async_callbacks():
# serves as state for async callback
class Item:
@@ -139,10 +161,35 @@ def test_async_callbacks():
from time import sleep
sleep(0.5)
- assert sum(res) == sum([x + 3 for x in work])
+ 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()
+
+
+def test_callback_num_times():
+ # Super-simple micro-benchmarking related to PR #2919.
+ # Example runtimes (Intel Xeon 2.2GHz, fully optimized):
+ # num_millions 1, repeats 2: 0.1 secs
+ # num_millions 20, repeats 10: 11.5 secs
+ one_million = 1000000
+ num_millions = 1 # Try 20 for actual micro-benchmarking.
+ repeats = 2 # Try 10.
+ rates = []
+ for rep in range(repeats):
+ t0 = time.time()
+ m.callback_num_times(lambda: None, num_millions * one_million)
+ td = time.time() - t0
+ rate = num_millions / td if td else 0
+ rates.append(rate)
+ if not rep:
+ print()
+ print(
+ f"callback_num_times: {num_millions:d} million / {td:.3f} seconds = {rate:.3f} million / second"
+ )
+ if len(rates) > 1:
+ print("Min Mean Max")
+ print(f"{min(rates):6.3f} {sum(rates) / len(rates):6.3f} {max(rates):6.3f}")
diff --git a/3rdparty/pybind11/tests/test_chrono.cpp b/3rdparty/pybind11/tests/test_chrono.cpp
index 65370508..8be0ffd1 100644
--- a/3rdparty/pybind11/tests/test_chrono.cpp
+++ b/3rdparty/pybind11/tests/test_chrono.cpp
@@ -8,21 +8,20 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
#include <pybind11/chrono.h>
+
+#include "pybind11_tests.h"
+
#include <chrono>
struct different_resolutions {
- using time_point_h = std::chrono::time_point<
- std::chrono::system_clock, std::chrono::hours>;
- using time_point_m = std::chrono::time_point<
- std::chrono::system_clock, std::chrono::minutes>;
- using time_point_s = std::chrono::time_point<
- std::chrono::system_clock, std::chrono::seconds>;
- using time_point_ms = std::chrono::time_point<
- std::chrono::system_clock, std::chrono::milliseconds>;
- using time_point_us = std::chrono::time_point<
- std::chrono::system_clock, std::chrono::microseconds>;
+ using time_point_h = std::chrono::time_point<std::chrono::system_clock, std::chrono::hours>;
+ using time_point_m = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
+ using time_point_s = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
+ using time_point_ms
+ = std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>;
+ using time_point_us
+ = std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>;
time_point_h timestamp_h;
time_point_m timestamp_m;
time_point_s timestamp_s;
@@ -65,12 +64,11 @@ TEST_SUBMODULE(chrono, m) {
// 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_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;
- });
+ m.def("test_nano_timepoint",
+ [](timestamp start, timespan delta) -> timestamp { return start + delta; });
// Test different resolutions
py::class_<different_resolutions>(m, "different_resolutions")
@@ -79,6 +77,5 @@ TEST_SUBMODULE(chrono, m) {
.def_readwrite("timestamp_m", &different_resolutions::timestamp_m)
.def_readwrite("timestamp_s", &different_resolutions::timestamp_s)
.def_readwrite("timestamp_ms", &different_resolutions::timestamp_ms)
- .def_readwrite("timestamp_us", &different_resolutions::timestamp_us)
- ;
+ .def_readwrite("timestamp_us", &different_resolutions::timestamp_us);
}
diff --git a/3rdparty/pybind11/tests/test_chrono.py b/3rdparty/pybind11/tests/test_chrono.py
index e9e24e08..7f47b37a 100644
--- a/3rdparty/pybind11/tests/test_chrono.py
+++ b/3rdparty/pybind11/tests/test_chrono.py
@@ -1,9 +1,9 @@
-# -*- coding: utf-8 -*-
-from pybind11_tests import chrono as m
import datetime
+
import pytest
import env # noqa: F401
+from pybind11_tests import chrono as m
def test_chrono_system_clock():
@@ -39,9 +39,7 @@ def test_chrono_system_clock_roundtrip():
# 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
+ assert diff == datetime.timedelta(0)
def test_chrono_system_clock_roundtrip_date():
@@ -64,9 +62,7 @@ def test_chrono_system_clock_roundtrip_date():
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
+ assert date1 == date2
# There should be no time information
assert time2.hour == 0
@@ -104,7 +100,7 @@ SKIP_TZ_ENV_ON_WIN = pytest.mark.skipif(
)
def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch):
if tz is not None:
- monkeypatch.setenv("TZ", "/usr/share/zoneinfo/{}".format(tz))
+ monkeypatch.setenv("TZ", f"/usr/share/zoneinfo/{tz}")
# Roundtrip the time
datetime2 = m.test_chrono2(time1)
@@ -117,10 +113,7 @@ def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch):
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
+ assert time1 == time2
# There should be no date information (i.e. date = python base date)
assert date2.year == 1970
@@ -140,9 +133,13 @@ def test_chrono_duration_roundtrip():
cpp_diff = m.test_chrono3(diff)
- assert cpp_diff.days == diff.days
- assert cpp_diff.seconds == diff.seconds
- assert cpp_diff.microseconds == diff.microseconds
+ assert cpp_diff == diff
+
+ # Negative timedelta roundtrip
+ diff = datetime.timedelta(microseconds=-1)
+ cpp_diff = m.test_chrono3(diff)
+
+ assert cpp_diff == diff
def test_chrono_duration_subtraction_equivalence():
@@ -153,9 +150,7 @@ def test_chrono_duration_subtraction_equivalence():
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
+ assert cpp_diff == diff
def test_chrono_duration_subtraction_equivalence_date():
@@ -166,9 +161,7 @@ def test_chrono_duration_subtraction_equivalence_date():
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
+ assert cpp_diff == diff
def test_chrono_steady_clock():
@@ -183,9 +176,7 @@ def test_chrono_steady_clock_roundtrip():
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
+ assert time1 == time2
def test_floating_point_duration():
diff --git a/3rdparty/pybind11/tests/test_class.cpp b/3rdparty/pybind11/tests/test_class.cpp
index 890fab73..c8b8071d 100644
--- a/3rdparty/pybind11/tests/test_class.cpp
+++ b/3rdparty/pybind11/tests/test_class.cpp
@@ -7,18 +7,29 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
+#if defined(__INTEL_COMPILER) && __cplusplus >= 201703L
+// Intel compiler requires a separate header file to support aligned new operators
+// and does not set the __cpp_aligned_new feature macro.
+// This header needs to be included before pybind11.
+# include <aligned_new>
+#endif
+
+#include <pybind11/stl.h>
+
#include "constructor_stats.h"
#include "local_bindings.h"
-#include <pybind11/stl.h>
+#include "pybind11_tests.h"
+
+#include <utility>
#if defined(_MSC_VER)
-# pragma warning(disable: 4324) // warning C4324: structure was padded due to alignment specifier
+# 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)} {}
+ explicit NoBraceInitialization(std::vector<int> v) : vec{std::move(v)} {}
template <typename T>
NoBraceInitialization(std::initializer_list<T> l) : vec(l) {}
@@ -38,10 +49,26 @@ TEST_SUBMODULE(class_, m) {
}
~NoConstructor() { print_destroyed(this); }
};
+ struct NoConstructorNew {
+ NoConstructorNew() = default;
+ NoConstructorNew(const NoConstructorNew &) = default;
+ NoConstructorNew(NoConstructorNew &&) = default;
+ static NoConstructorNew *new_instance() {
+ auto *ptr = new NoConstructorNew();
+ print_created(ptr, "via new_instance");
+ return ptr;
+ }
+ ~NoConstructorNew() { print_destroyed(this); }
+ };
py::class_<NoConstructor>(m, "NoConstructor")
.def_static("new_instance", &NoConstructor::new_instance, "Return an instance");
+ py::class_<NoConstructorNew>(m, "NoConstructorNew")
+ .def(py::init([](const NoConstructorNew &self) { return self; })) // Need a NOOP __init__
+ .def_static("__new__",
+ [](const py::object &) { return NoConstructorNew::new_instance(); });
+
// test_inheritance
class Pet {
public:
@@ -49,6 +76,7 @@ TEST_SUBMODULE(class_, m) {
: 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;
@@ -56,18 +84,18 @@ TEST_SUBMODULE(class_, m) {
class Dog : public Pet {
public:
- Dog(const std::string &name) : Pet(name, "dog") {}
+ explicit 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") {}
+ explicit Rabbit(const std::string &name) : Pet(name, "parrot") {}
};
class Hamster : public Pet {
public:
- Hamster(const std::string &name) : Pet(name, "rodent") {}
+ explicit Hamster(const std::string &name) : Pet(name, "rodent") {}
};
class Chimera : public Pet {
@@ -75,27 +103,24 @@ TEST_SUBMODULE(class_, m) {
};
py::class_<Pet> pet_class(m, "Pet");
- pet_class
- .def(py::init<std::string, std::string>())
+ 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>());
+ 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>());
+ 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>());
+ 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("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
@@ -105,33 +130,35 @@ TEST_SUBMODULE(class_, m) {
BaseClass(BaseClass &&) = default;
virtual ~BaseClass() = default;
};
- struct DerivedClass1 : BaseClass { };
- struct DerivedClass2 : 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();
+ 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; });
+ 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])
- );
+ m.def("check_instances", [](const 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]));
});
struct Invalid {};
@@ -142,30 +169,24 @@ TEST_SUBMODULE(class_, m) {
// See https://github.com/pybind/pybind11/issues/2486
// if (category == 2)
// return py::type::of<int>();
- if (category == 1)
+ if (category == 1) {
return py::type::of<DerivedClass1>();
- else
- return py::type::of<Invalid>();
+ }
+ return py::type::of<Invalid>();
});
- m.def("get_type_of", [](py::object ob) {
- return py::type::of(ob);
- });
+ m.def("get_type_of", [](py::object ob) { return py::type::of(std::move(ob)); });
- m.def("get_type_classic", [](py::handle h) {
- return h.get_type();
- });
+ m.def("get_type_classic", [](py::handle h) { return h.get_type(); });
- m.def("as_type", [](py::object ob) {
- return py::type(ob);
- });
+ m.def("as_type", [](const py::object &ob) { return py::type(ob); });
// test_mismatched_holder
- struct MismatchBase1 { };
- struct MismatchDerived1 : MismatchBase1 { };
+ struct MismatchBase1 {};
+ struct MismatchDerived1 : MismatchBase1 {};
- struct MismatchBase2 { };
- struct MismatchDerived2 : MismatchBase2 { };
+ struct MismatchBase2 {};
+ struct MismatchDerived2 : MismatchBase2 {};
m.def("mismatched_holder_1", []() {
auto mod = py::module_::import("__main__");
@@ -175,16 +196,14 @@ TEST_SUBMODULE(class_, m) {
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");
+ 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());
- }
+ static std::unique_ptr<MyBase> make() { return std::unique_ptr<MyBase>(new MyBase()); }
};
struct MyDerived : MyBase {
@@ -193,8 +212,7 @@ TEST_SUBMODULE(class_, m) {
}
};
- py::class_<MyBase>(m, "MyBase")
- .def_static("make", &MyBase::make);
+ py::class_<MyBase>(m, "MyBase").def_static("make", &MyBase::make);
py::class_<MyDerived, MyBase>(m, "MyDerived")
.def_static("make", &MyDerived::make)
@@ -204,15 +222,14 @@ TEST_SUBMODULE(class_, m) {
struct ConvertibleFromUserType {
int i;
- ConvertibleFromUserType(UserType u) : i(u.value()) { }
+ explicit ConvertibleFromUserType(UserType u) : i(u.value()) {}
};
- py::class_<ConvertibleFromUserType>(m, "AcceptsUserType")
- .def(py::init<UserType>());
+ 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) {
+ m.def("implicitly_convert_variable", [](const 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.
@@ -230,48 +247,91 @@ TEST_SUBMODULE(class_, m) {
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()));
+ auto *def = new PyMethodDef{"f", f, METH_VARARGS, nullptr};
+ py::capsule def_capsule(def,
+ [](void *ptr) { delete reinterpret_cast<PyMethodDef *>(ptr); });
+ return py::reinterpret_steal<py::object>(
+ PyCFunction_NewEx(def, def_capsule.ptr(), 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); }
+ 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); }
+ 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); }
+ 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;
AliasedHasOpNewDelSize() = default;
- AliasedHasOpNewDelSize(const AliasedHasOpNewDelSize&) = delete;
+ AliasedHasOpNewDelSize(const AliasedHasOpNewDelSize &) = delete;
};
struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize {
PyAliasedHasOpNewDelSize() = default;
- PyAliasedHasOpNewDelSize(int) { }
+ explicit 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); }
+ 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");
+ 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));
@@ -294,13 +354,7 @@ TEST_SUBMODULE(class_, m) {
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
+ py::class_<ProtectedA>(m, "ProtectedA").def(py::init<>()).def("foo", &PublicistA::foo);
class ProtectedB {
public:
@@ -322,16 +376,16 @@ TEST_SUBMODULE(class_, m) {
class PublicistB : public ProtectedB {
public:
+ // [workaround(intel)] = default does not work here
+ // Removing or defaulting this destructor results in linking errors with the Intel compiler
+ // (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
+ ~PublicistB() override{}; // NOLINT(modernize-use-equals-default)
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 {
@@ -371,8 +425,8 @@ TEST_SUBMODULE(class_, m) {
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);
+ .def(
+ "fa", [](Nested &, int, NestBase &, Nested &) {}, "a"_a, "b"_a, "c"_a);
base.def("g", [](NestBase &, Nested &) {});
base.def("h", []() { return NestBase(); });
@@ -382,21 +436,21 @@ TEST_SUBMODULE(class_, m) {
// generate a useful error message
struct NotRegistered {};
- struct StringWrapper { std::string str; };
+ struct StringWrapper {
+ std::string str;
+ };
m.def("test_error_after_conversions", [](int) {});
m.def("test_error_after_conversions",
- [](StringWrapper) -> NotRegistered { return {}; });
+ [](const 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
+#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
// test_final
struct IsFinal final {};
@@ -409,9 +463,7 @@ TEST_SUBMODULE(class_, m) {
// test_exception_rvalue_abort
struct PyPrintDestructor {
PyPrintDestructor() = default;
- ~PyPrintDestructor() {
- py::print("Print from destructor");
- }
+ ~PyPrintDestructor() { py::print("Print from destructor"); }
void throw_something() { throw std::runtime_error("error"); }
};
py::class_<PyPrintDestructor>(m, "PyPrintDestructor")
@@ -422,12 +474,10 @@ TEST_SUBMODULE(class_, m) {
struct SamePointer {};
static SamePointer samePointer;
py::class_<SamePointer, std::unique_ptr<SamePointer, py::nodelete>>(m, "SamePointer")
- .def(py::init([]() { return &samePointer; }))
- .def("__del__", [](SamePointer&) { py::print("__del__ called"); });
+ .def(py::init([]() { return &samePointer; }));
struct Empty {};
- py::class_<Empty>(m, "Empty")
- .def(py::init<>());
+ py::class_<Empty>(m, "Empty").def(py::init<>());
// test_base_and_derived_nested_scope
struct BaseWithNested {
@@ -450,30 +500,34 @@ TEST_SUBMODULE(class_, m) {
struct OtherDuplicate {};
struct DuplicateNested {};
struct OtherDuplicateNested {};
- m.def("register_duplicate_class_name", [](py::module_ m) {
+
+ m.def("register_duplicate_class_name", [](const py::module_ &m) {
py::class_<Duplicate>(m, "Duplicate");
py::class_<OtherDuplicate>(m, "Duplicate");
});
- m.def("register_duplicate_class_type", [](py::module_ m) {
+ m.def("register_duplicate_class_type", [](const py::module_ &m) {
py::class_<OtherDuplicate>(m, "OtherDuplicate");
py::class_<OtherDuplicate>(m, "YetAnotherDuplicate");
});
- m.def("register_duplicate_nested_class_name", [](py::object gt) {
+ m.def("register_duplicate_nested_class_name", [](const py::object &gt) {
py::class_<DuplicateNested>(gt, "DuplicateNested");
py::class_<OtherDuplicateNested>(gt, "DuplicateNested");
});
- m.def("register_duplicate_nested_class_type", [](py::object gt) {
+ m.def("register_duplicate_nested_class_type", [](const py::object &gt) {
py::class_<OtherDuplicateNested>(gt, "OtherDuplicateNested");
py::class_<OtherDuplicateNested>(gt, "YetAnotherDuplicateNested");
});
}
-template <int N> class BreaksBase { public:
+template <int N>
+class BreaksBase {
+public:
virtual ~BreaksBase() = default;
BreaksBase() = default;
- BreaksBase(const BreaksBase&) = delete;
+ BreaksBase(const BreaksBase &) = delete;
};
-template <int N> class BreaksTramp : public BreaksBase<N> {};
+template <int N>
+class BreaksTramp : public BreaksBase<N> {};
// These should all compile just fine:
using DoesntBreak1 = py::class_<BreaksBase<1>, std::unique_ptr<BreaksBase<1>>, BreaksTramp<1>>;
using DoesntBreak2 = py::class_<BreaksBase<2>, BreaksTramp<2>, std::unique_ptr<BreaksBase<2>>>;
@@ -483,43 +537,83 @@ using DoesntBreak5 = py::class_<BreaksBase<5>>;
using DoesntBreak6 = py::class_<BreaksBase<6>, std::shared_ptr<BreaksBase<6>>, BreaksTramp<6>>;
using DoesntBreak7 = py::class_<BreaksBase<7>, BreaksTramp<7>, std::shared_ptr<BreaksBase<7>>>;
using DoesntBreak8 = py::class_<BreaksBase<8>, std::shared_ptr<BreaksBase<8>>>;
-#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, \
+#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);
+#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);
+#define CHECK_BROKEN(N) \
+ static_assert(std::is_same<typename Breaks##N::type, BreaksBase<-(N)>>::value, \
+ "Breaks1 has wrong type!");
+
+#ifdef PYBIND11_NEVER_DEFINED_EVER
+// 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);
+#endif
diff --git a/3rdparty/pybind11/tests/test_class.py b/3rdparty/pybind11/tests/test_class.py
index bdcced96..ff9196f0 100644
--- a/3rdparty/pybind11/tests/test_class.py
+++ b/3rdparty/pybind11/tests/test_class.py
@@ -1,14 +1,11 @@
-# -*- coding: utf-8 -*-
import pytest
import env # noqa: F401
-
+from pybind11_tests import ConstructorStats, UserType
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)
@@ -26,6 +23,14 @@ def test_instance(msg):
assert cstats.alive() == 0
+def test_instance_new(msg):
+ instance = m.NoConstructorNew() # .__new__(m.NoConstructor.__class__)
+ cstats = ConstructorStats.get(m.NoConstructorNew)
+ assert cstats.alive() == 1
+ del instance
+ assert cstats.alive() == 0
+
+
def test_type():
assert m.check_type(1) == m.DerivedClass1
with pytest.raises(RuntimeError) as execinfo:
@@ -96,8 +101,8 @@ def test_docstrings(doc):
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"""
+ """Tests that a properly qualified name is set in __qualname__ and that
+ generated docstrings properly use it and the module name"""
assert m.NestBase.__qualname__ == "NestBase"
assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
@@ -123,13 +128,13 @@ def test_qualname(doc):
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_"
@@ -321,7 +326,7 @@ def test_bind_protected_functions():
def test_brace_initialization():
- """ Tests that simple POD classes can be constructed using C++11 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"
diff --git a/3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt
index 0c0578ad..8bfaa386 100644
--- a/3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt
+++ b/3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt
@@ -25,7 +25,7 @@ function(pybind11_add_build_test name)
endif()
if(NOT ARG_INSTALL)
- list(APPEND build_options "-DPYBIND11_PROJECT_DIR=${pybind11_SOURCE_DIR}")
+ list(APPEND build_options "-Dpybind11_SOURCE_DIR=${pybind11_SOURCE_DIR}")
else()
list(APPEND build_options "-DCMAKE_PREFIX_PATH=${pybind11_BINARY_DIR}/mock_install")
endif()
@@ -55,6 +55,8 @@ function(pybind11_add_build_test name)
add_dependencies(test_cmake_build test_build_${name})
endfunction()
+possibly_uninitialized(PYTHON_MODULE_EXTENSION Python_INTERPRETER_ID)
+
pybind11_add_build_test(subdirectory_function)
pybind11_add_build_test(subdirectory_target)
if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy")
@@ -77,3 +79,6 @@ if(PYBIND11_INSTALL)
endif()
add_dependencies(check test_cmake_build)
+
+add_subdirectory(subdirectory_target EXCLUDE_FROM_ALL)
+add_subdirectory(subdirectory_embed EXCLUDE_FROM_ALL)
diff --git a/3rdparty/pybind11/tests/test_cmake_build/embed.cpp b/3rdparty/pybind11/tests/test_cmake_build/embed.cpp
index a3abc8a8..30bc4f1e 100644
--- a/3rdparty/pybind11/tests/test_cmake_build/embed.cpp
+++ b/3rdparty/pybind11/tests/test_cmake_build/embed.cpp
@@ -6,15 +6,17 @@ PYBIND11_EMBEDDED_MODULE(test_cmake_build, m) {
}
int main(int argc, char *argv[]) {
- if (argc != 2)
+ if (argc != 2) {
throw std::runtime_error("Expected test.py file as the first argument");
- auto test_py_file = argv[1];
+ }
+ 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)
+ 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
index 64ae5c4b..f7d69399 100644
--- a/3rdparty/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt
+++ b/3rdparty/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt
@@ -22,5 +22,7 @@ set_target_properties(test_installed_embed PROPERTIES OUTPUT_NAME test_cmake_bui
# This may be needed to resolve header conflicts, e.g. between Python release and debug headers.
set_target_properties(test_installed_embed PROPERTIES NO_SYSTEM_FROM_IMPORTED ON)
-add_custom_target(check_installed_embed $<TARGET_FILE:test_installed_embed>
- ${PROJECT_SOURCE_DIR}/../test.py)
+add_custom_target(
+ check_installed_embed
+ $<TARGET_FILE:test_installed_embed> ${PROJECT_SOURCE_DIR}/../test.py
+ DEPENDS test_installed_embed)
diff --git a/3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt
index 1a502863..d7ca4db5 100644
--- a/3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt
+++ b/3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt
@@ -35,4 +35,5 @@ add_custom_target(
PYTHONPATH=$<TARGET_FILE_DIR:test_installed_function>
${_Python_EXECUTABLE}
${PROJECT_SOURCE_DIR}/../test.py
- ${PROJECT_NAME})
+ ${PROJECT_NAME}
+ DEPENDS test_installed_function)
diff --git a/3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt
index b38eb774..bc5e101f 100644
--- a/3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt
+++ b/3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt
@@ -42,4 +42,5 @@ add_custom_target(
PYTHONPATH=$<TARGET_FILE_DIR:test_installed_target>
${_Python_EXECUTABLE}
${PROJECT_SOURCE_DIR}/../test.py
- ${PROJECT_NAME})
+ ${PROJECT_NAME}
+ DEPENDS test_installed_target)
diff --git a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt
index c7df0cf7..58cdd7cf 100644
--- a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt
+++ b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt
@@ -16,15 +16,17 @@ set(PYBIND11_INSTALL
CACHE BOOL "")
set(PYBIND11_EXPORT_NAME test_export)
-add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11)
+add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
# Test basic target functionality
add_executable(test_subdirectory_embed ../embed.cpp)
target_link_libraries(test_subdirectory_embed PRIVATE pybind11::embed)
set_target_properties(test_subdirectory_embed PROPERTIES OUTPUT_NAME test_cmake_build)
-add_custom_target(check_subdirectory_embed $<TARGET_FILE:test_subdirectory_embed>
- ${PROJECT_SOURCE_DIR}/../test.py)
+add_custom_target(
+ check_subdirectory_embed
+ $<TARGET_FILE:test_subdirectory_embed> "${PROJECT_SOURCE_DIR}/../test.py"
+ DEPENDS test_subdirectory_embed)
# Test custom export group -- PYBIND11_EXPORT_NAME
add_library(test_embed_lib ../embed.cpp)
diff --git a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt
index 624c600f..01557c43 100644
--- a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt
+++ b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt
@@ -11,7 +11,7 @@ endif()
project(test_subdirectory_function CXX)
-add_subdirectory("${PYBIND11_PROJECT_DIR}" pybind11)
+add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
pybind11_add_module(test_subdirectory_function ../main.cpp)
set_target_properties(test_subdirectory_function PROPERTIES OUTPUT_NAME test_cmake_build)
@@ -31,4 +31,5 @@ add_custom_target(
PYTHONPATH=$<TARGET_FILE_DIR:test_subdirectory_function>
${_Python_EXECUTABLE}
${PROJECT_SOURCE_DIR}/../test.py
- ${PROJECT_NAME})
+ ${PROJECT_NAME}
+ DEPENDS test_subdirectory_function)
diff --git a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt
index 2471941f..ba82fdee 100644
--- a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt
+++ b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt
@@ -11,7 +11,7 @@ endif()
project(test_subdirectory_target CXX)
-add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11)
+add_subdirectory("${pybind11_SOURCE_DIR}" pybind11)
add_library(test_subdirectory_target MODULE ../main.cpp)
set_target_properties(test_subdirectory_target PROPERTIES OUTPUT_NAME test_cmake_build)
@@ -37,4 +37,5 @@ add_custom_target(
PYTHONPATH=$<TARGET_FILE_DIR:test_subdirectory_target>
${_Python_EXECUTABLE}
${PROJECT_SOURCE_DIR}/../test.py
- ${PROJECT_NAME})
+ ${PROJECT_NAME}
+ DEPENDS test_subdirectory_target)
diff --git a/3rdparty/pybind11/tests/test_cmake_build/test.py b/3rdparty/pybind11/tests/test_cmake_build/test.py
index 87ed5135..807fd43b 100644
--- a/3rdparty/pybind11/tests/test_cmake_build/test.py
+++ b/3rdparty/pybind11/tests/test_cmake_build/test.py
@@ -1,6 +1,8 @@
-# -*- coding: utf-8 -*-
import sys
+
import test_cmake_build
+assert isinstance(__file__, str) # Test this is properly set
+
assert test_cmake_build.add(1, 2) == 3
-print("{} imports, runs, and adds: 1 + 2 = 3".format(sys.argv[1]))
+print(f"{sys.argv[1]} imports, runs, and adds: 1 + 2 = 3")
diff --git a/3rdparty/pybind11/tests/test_const_name.cpp b/3rdparty/pybind11/tests/test_const_name.cpp
new file mode 100644
index 00000000..2ad01e68
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_const_name.cpp
@@ -0,0 +1,55 @@
+// Copyright (c) 2021 The Pybind Development Team.
+// 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"
+
+// IUT = Implementation Under Test
+#define CONST_NAME_TESTS(TEST_FUNC, IUT) \
+ std::string TEST_FUNC(int selector) { \
+ switch (selector) { \
+ case 0: \
+ return IUT("").text; \
+ case 1: \
+ return IUT("A").text; \
+ case 2: \
+ return IUT("Bd").text; \
+ case 3: \
+ return IUT("Cef").text; \
+ case 4: \
+ return IUT<int>().text; /*NOLINT(bugprone-macro-parentheses)*/ \
+ case 5: \
+ return IUT<std::string>().text; /*NOLINT(bugprone-macro-parentheses)*/ \
+ case 6: \
+ return IUT<true>("T1", "T2").text; /*NOLINT(bugprone-macro-parentheses)*/ \
+ case 7: \
+ return IUT<false>("U1", "U2").text; /*NOLINT(bugprone-macro-parentheses)*/ \
+ case 8: \
+ /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
+ return IUT<true>(IUT("D1"), IUT("D2")).text; \
+ case 9: \
+ /*NOLINTNEXTLINE(bugprone-macro-parentheses)*/ \
+ return IUT<false>(IUT("E1"), IUT("E2")).text; \
+ case 10: \
+ return IUT("KeepAtEnd").text; \
+ default: \
+ break; \
+ } \
+ throw std::runtime_error("Invalid selector value."); \
+ }
+
+CONST_NAME_TESTS(const_name_tests, py::detail::const_name)
+
+#ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
+CONST_NAME_TESTS(underscore_tests, py::detail::_)
+#endif
+
+TEST_SUBMODULE(const_name, m) {
+ m.def("const_name_tests", const_name_tests);
+
+#if defined(PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY)
+ m.def("underscore_tests", underscore_tests);
+#else
+ m.attr("underscore_tests") = "PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY not defined.";
+#endif
+}
diff --git a/3rdparty/pybind11/tests/test_const_name.py b/3rdparty/pybind11/tests/test_const_name.py
new file mode 100644
index 00000000..10b0caee
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_const_name.py
@@ -0,0 +1,29 @@
+import pytest
+
+from pybind11_tests import const_name as m
+
+
+@pytest.mark.parametrize("func", (m.const_name_tests, m.underscore_tests))
+@pytest.mark.parametrize(
+ "selector, expected",
+ enumerate(
+ (
+ "",
+ "A",
+ "Bd",
+ "Cef",
+ "%",
+ "%",
+ "T1",
+ "U2",
+ "D1",
+ "E2",
+ "KeepAtEnd",
+ )
+ ),
+)
+def test_const_name(func, selector, expected):
+ if isinstance(func, str):
+ pytest.skip(func)
+ text = func(selector)
+ assert text == expected
diff --git a/3rdparty/pybind11/tests/test_constants_and_functions.cpp b/3rdparty/pybind11/tests/test_constants_and_functions.cpp
index f6077955..1918a429 100644
--- a/3rdparty/pybind11/tests/test_constants_and_functions.cpp
+++ b/3rdparty/pybind11/tests/test_constants_and_functions.cpp
@@ -1,5 +1,6 @@
/*
- tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw byte strings
+ tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw
+ byte strings
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
@@ -11,20 +12,14 @@
enum MyEnum { EFirstEntry = 1, ESecondEntry };
-std::string test_function1() {
- return "test_function()";
-}
+std::string test_function1() { return "test_function()"; }
-std::string test_function2(MyEnum k) {
- return "test_function(enum=" + std::to_string(k) + ")";
-}
+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) + ")";
-}
+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() { 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)"; }
@@ -33,50 +28,60 @@ py::bytes return_bytes() {
return std::string(data, 4);
}
-std::string print_bytes(py::bytes bytes) {
+std::string print_bytes(const 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])) + " ";
+ for (char c : value) {
+ ret += std::to_string(static_cast<int>(c)) + ' ';
}
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.
+// 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"
+// [workaround(intel)] Unable to use noexcept instead of noexcept(true)
+// Make the f1 test basically the same as the f2 test in C++17 mode for the Intel compiler as
+// it fails to compile with a plain noexcept (tested with icc (ICC) 2021.1 Beta 20200827).
+#if defined(__INTEL_COMPILER) && defined(PYBIND11_CPP17)
+int f1(int x) noexcept(true) { return x + 1; }
+#else
+int f1(int x) noexcept { return x + 1; }
+#endif
+int f2(int x) noexcept(true) { return x + 2; }
+int f3(int x) noexcept(false) { return x + 3; }
+#if defined(__GNUG__) && !defined(__INTEL_COMPILER)
+# 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
+// NOLINTNEXTLINE(modernize-use-noexcept)
+int f4(int x) throw() { return x + 4; } // Deprecated equivalent to noexcept(true)
+#if defined(__GNUG__) && !defined(__INTEL_COMPILER)
+# 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"
+ 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__) && !defined(__INTEL_COMPILER)
+# 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
+ // NOLINTNEXTLINE(modernize-use-noexcept)
+ int m7(int x) throw() { return x - 7; }
+ // NOLINTNEXTLINE(modernize-use-noexcept)
+ int m8(int x) const throw() { return x - 8; }
+#if defined(__GNUG__) && !defined(__INTEL_COMPILER)
+# pragma GCC diagnostic pop
#endif
};
} // namespace test_exc_sp
-
TEST_SUBMODULE(constants_and_functions, m) {
// test_constants
m.attr("some_constant") = py::int_(14);
@@ -118,10 +123,37 @@ TEST_SUBMODULE(constants_and_functions, m) {
.def("m5", &C::m5)
.def("m6", &C::m6)
.def("m7", &C::m7)
- .def("m8", &C::m8)
- ;
+ .def("m8", &C::m8);
m.def("f1", f1);
m.def("f2", f2);
+#if defined(__INTEL_COMPILER)
+# pragma warning push
+# pragma warning disable 878 // incompatible exception specifications
+#endif
m.def("f3", f3);
+#if defined(__INTEL_COMPILER)
+# pragma warning pop
+#endif
m.def("f4", f4);
+
+ // test_function_record_leaks
+ m.def("register_large_capture_with_invalid_arguments", [](py::module_ m) {
+ // This should always be enough to trigger the alternative branch
+ // where `sizeof(capture) > sizeof(rec->data)`
+ uint64_t capture[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+#if defined(__GNUC__) && __GNUC__ == 4 // CentOS7
+ py::detail::silence_unused_warnings(capture);
+#endif
+ m.def(
+ "should_raise", [capture](int) { return capture[9] + 33; }, py::kw_only(), py::arg());
+ });
+ m.def("register_with_raising_repr", [](py::module_ m, const py::object &default_value) {
+ m.def(
+ "should_raise",
+ [](int, int, const py::object &) { return 42; },
+ "some docstring",
+ py::arg_v("x", 42),
+ py::arg_v("y", 42, "<the answer>"),
+ py::arg_v("z", default_value));
+ });
}
diff --git a/3rdparty/pybind11/tests/test_constants_and_functions.py b/3rdparty/pybind11/tests/test_constants_and_functions.py
index b980ccf1..5da0b84b 100644
--- a/3rdparty/pybind11/tests/test_constants_and_functions.py
+++ b/3rdparty/pybind11/tests/test_constants_and_functions.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
import pytest
m = pytest.importorskip("pybind11_tests.constants_and_functions")
@@ -40,3 +39,14 @@ def test_exception_specifiers():
assert m.f2(53) == 55
assert m.f3(86) == 89
assert m.f4(140) == 144
+
+
+def test_function_record_leaks():
+ class RaisingRepr:
+ def __repr__(self):
+ raise RuntimeError("Surprise!")
+
+ with pytest.raises(RuntimeError):
+ m.register_large_capture_with_invalid_arguments(m)
+ with pytest.raises(RuntimeError):
+ m.register_with_raising_repr(m, RaisingRepr())
diff --git a/3rdparty/pybind11/tests/test_copy_move.cpp b/3rdparty/pybind11/tests/test_copy_move.cpp
index 2704217a..28c24456 100644
--- a/3rdparty/pybind11/tests/test_copy_move.cpp
+++ b/3rdparty/pybind11/tests/test_copy_move.cpp
@@ -8,38 +8,48 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
-#include "constructor_stats.h"
#include <pybind11/stl.h>
+#include "constructor_stats.h"
+#include "pybind11_tests.h"
+
template <typename derived>
struct empty {
- static const derived& get_one() { return instance_; }
+ static const derived &get_one() { return instance_; }
static derived instance_;
};
struct lacking_copy_ctor : public empty<lacking_copy_ctor> {
lacking_copy_ctor() = default;
- lacking_copy_ctor(const lacking_copy_ctor& other) = delete;
+ lacking_copy_ctor(const lacking_copy_ctor &other) = delete;
};
-template <> lacking_copy_ctor empty<lacking_copy_ctor>::instance_ = {};
+template <>
+lacking_copy_ctor empty<lacking_copy_ctor>::instance_ = {};
struct lacking_move_ctor : public empty<lacking_move_ctor> {
lacking_move_ctor() = default;
- lacking_move_ctor(const lacking_move_ctor& other) = delete;
- lacking_move_ctor(lacking_move_ctor&& other) = delete;
+ 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_ = {};
+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; }
+ explicit MoveOnlyInt(int v) : value{v} { print_created(this, value); }
+ MoveOnlyInt(MoveOnlyInt &&m) noexcept {
+ print_move_created(this, m.value);
+ std::swap(value, m.value);
+ }
+ MoveOnlyInt &operator=(MoveOnlyInt &&m) noexcept {
+ 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); }
@@ -49,11 +59,26 @@ public:
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; }
+ explicit MoveOrCopyInt(int v) : value{v} { print_created(this, value); }
+ MoveOrCopyInt(MoveOrCopyInt &&m) noexcept {
+ print_move_created(this, m.value);
+ std::swap(value, m.value);
+ }
+ MoveOrCopyInt &operator=(MoveOrCopyInt &&m) noexcept {
+ print_move_assigned(this, m.value);
+ std::swap(value, m.value);
+ return *this;
+ }
+ MoveOrCopyInt(const MoveOrCopyInt &c) {
+ print_copy_created(this, c.value);
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
+ 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;
@@ -61,41 +86,71 @@ public:
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; }
+ explicit CopyOnlyInt(int v) : value{v} { print_created(this, value); }
+ CopyOnlyInt(const CopyOnlyInt &c) {
+ print_copy_created(this, c.value);
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
+ 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;
};
PYBIND11_NAMESPACE_BEGIN(pybind11)
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<MoveOnlyInt> {
+ PYBIND11_TYPE_CASTER(MoveOnlyInt, const_name("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<MoveOrCopyInt> {
+ PYBIND11_TYPE_CASTER(MoveOrCopyInt, const_name("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> {
+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 constexpr auto name = const_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();
+ 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>;
+ explicit operator CopyOnlyInt *() { return &value; }
+ explicit operator CopyOnlyInt &() { return value; }
+ template <typename T>
+ using cast_op_type = pybind11::detail::cast_op_type<T>;
};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(pybind11)
@@ -103,22 +158,21 @@ PYBIND11_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);
+ .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);
+ .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) {
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
+ m.def("move_and_copy_casts", [](const 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 */
- auto m1(py::cast<MoveOrCopyInt>(o)); /* moves */
- auto m2(py::cast<MoveOnlyInt>(o)); /* moves */
- auto m3(py::cast<CopyOnlyInt>(o)); /* copies */
+ r += py::cast<MoveOnlyInt>(o).value; /* moves */
+ r += py::cast<CopyOnlyInt>(o).value; /* copies */
+ auto m1(py::cast<MoveOrCopyInt>(o)); /* moves */
+ auto m2(py::cast<MoveOnlyInt>(o)); /* moves */
+ auto m3(py::cast<CopyOnlyInt>(o)); /* copies */
r += m1.value + m2.value + m3.value;
return r;
@@ -126,30 +180,40 @@ TEST_SUBMODULE(copy_move_policies, m) {
// test_move_and_copy_loads
m.def("move_only", [](MoveOnlyInt m) { return m.value; });
+ // Changing this breaks the existing test: needs careful review.
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; });
+ // Changing this breaks the existing test: needs careful review.
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
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_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_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;
+ 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;
+ 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;
+ 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);
@@ -159,18 +223,13 @@ TEST_SUBMODULE(copy_move_policies, m) {
#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;
- });
+ 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
@@ -181,39 +240,56 @@ TEST_SUBMODULE(copy_move_policies, m) {
// added later.
struct PrivateOpNew {
int value = 1;
+
private:
void *operator new(size_t bytes) {
void *ptr = std::malloc(bytes);
- if (ptr)
+ if (ptr) {
return ptr;
- else
- throw std::bad_alloc{};
+ }
+ throw std::bad_alloc{};
}
};
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);
+ 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} {}
+ explicit 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);
+ py::class_<MoveIssue1>(m, "MoveIssue1")
+ .def(py::init<int>())
+ .def_readwrite("value", &MoveIssue1::v);
struct MoveIssue2 {
int v;
- MoveIssue2(int v) : v{v} {}
+ explicit MoveIssue2(int v) : v{v} {}
MoveIssue2(MoveIssue2 &&) = default;
};
- py::class_<MoveIssue2>(m, "MoveIssue2").def(py::init<int>()).def_readwrite("value", &MoveIssue2::v);
+ py::class_<MoveIssue2>(m, "MoveIssue2")
+ .def(py::init<int>())
+ .def_readwrite("value", &MoveIssue2::v);
+
+ // #2742: Don't expect ownership of raw pointer to `new`ed object to be transferred with
+ // `py::return_value_policy::move`
+ m.def(
+ "get_moveissue1",
+ [](int i) { return std::unique_ptr<MoveIssue1>(new MoveIssue1(i)); },
+ py::return_value_policy::move);
+ m.def(
+ "get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
- 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);
+ // Make sure that cast from pytype rvalue to other pytype works
+ m.def("get_pytype_rvalue_castissue", [](double i) { return py::float_(i).cast<py::int_>(); });
}
diff --git a/3rdparty/pybind11/tests/test_copy_move.py b/3rdparty/pybind11/tests/test_copy_move.py
index 7e3cc168..9fef0893 100644
--- a/3rdparty/pybind11/tests/test_copy_move.py
+++ b/3rdparty/pybind11/tests/test_copy_move.py
@@ -1,5 +1,5 @@
-# -*- coding: utf-8 -*-
import pytest
+
from pybind11_tests import copy_move_policies as m
@@ -119,7 +119,14 @@ def test_private_op_new():
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
+ m2 = m.get_moveissue2(2)
+ assert m2.value == 2
+
+
+def test_pytype_rvalue_cast():
+ """Make sure that cast from pytype rvalue to other pytype works"""
+
+ value = m.get_pytype_rvalue_castissue(1.0)
+ assert value == 1
diff --git a/3rdparty/pybind11/tests/test_custom_type_casters.cpp b/3rdparty/pybind11/tests/test_custom_type_casters.cpp
index d565add2..b4af02a4 100644
--- a/3rdparty/pybind11/tests/test_custom_type_casters.cpp
+++ b/3rdparty/pybind11/tests/test_custom_type_casters.cpp
@@ -7,23 +7,37 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
#include "constructor_stats.h"
-
+#include "pybind11_tests.h"
// 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> {
+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 {
+namespace detail {
+template <>
+struct type_caster<ArgInspector1> {
public:
+ // Classic
+#ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
PYBIND11_TYPE_CASTER(ArgInspector1, _("ArgInspector1"));
+#else
+ PYBIND11_TYPE_CASTER(ArgInspector1, const_name("ArgInspector1"));
+#endif
bool load(handle src, bool convert) {
- value.arg = "loading ArgInspector1 argument " +
- std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. "
- "Argument value = " + (std::string) str(src);
+ value.arg = "loading ArgInspector1 argument " + std::string(convert ? "WITH" : "WITHOUT")
+ + " conversion allowed. "
+ "Argument value = "
+ + (std::string) str(src);
return true;
}
@@ -31,14 +45,16 @@ public:
return str(src.arg).release();
}
};
-template <> struct type_caster<ArgInspector2> {
+template <>
+struct type_caster<ArgInspector2> {
public:
- PYBIND11_TYPE_CASTER(ArgInspector2, _("ArgInspector2"));
+ PYBIND11_TYPE_CASTER(ArgInspector2, const_name("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);
+ value.arg = "loading ArgInspector2 argument " + std::string(convert ? "WITH" : "WITHOUT")
+ + " conversion allowed. "
+ "Argument value = "
+ + (std::string) str(src);
return true;
}
@@ -46,20 +62,19 @@ public:
return str(src.arg).release();
}
};
-template <> struct type_caster<ArgAlwaysConverts> {
+template <>
+struct type_caster<ArgAlwaysConverts> {
public:
- PYBIND11_TYPE_CASTER(ArgAlwaysConverts, _("ArgAlwaysConverts"));
+ PYBIND11_TYPE_CASTER(ArgAlwaysConverts, const_name("ArgAlwaysConverts"));
- bool load(handle, bool convert) {
- return convert;
- }
+ bool load(handle, bool convert) { return convert; }
static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) {
return py::none().release();
}
};
} // namespace detail
-} // namespace pybind11
+} // namespace PYBIND11_NAMESPACE
// test_custom_caster_destruction
class DestructionTester {
@@ -67,13 +82,21 @@ 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; }
+ DestructionTester(DestructionTester &&) noexcept { print_move_created(this); }
+ DestructionTester &operator=(const DestructionTester &) {
+ print_copy_assigned(this);
+ return *this;
+ }
+ DestructionTester &operator=(DestructionTester &&) noexcept {
+ print_move_assigned(this);
+ return *this;
+ }
};
-namespace pybind11 { namespace detail {
-template <> struct type_caster<DestructionTester> {
- PYBIND11_TYPE_CASTER(DestructionTester, _("DestructionTester"));
+namespace PYBIND11_NAMESPACE {
+namespace detail {
+template <>
+struct type_caster<DestructionTester> {
+ PYBIND11_TYPE_CASTER(DestructionTester, const_name("DestructionTester"));
bool load(handle, bool) { return true; }
static handle cast(const DestructionTester &, return_value_policy, handle) {
@@ -81,7 +104,35 @@ template <> struct type_caster<DestructionTester> {
}
};
} // namespace detail
-} // namespace pybind11
+} // namespace PYBIND11_NAMESPACE
+
+// Define type caster outside of `pybind11::detail` and then alias it.
+namespace other_lib {
+struct MyType {};
+// Corrupt `py` shorthand alias for surrounding context.
+namespace py {}
+// Corrupt unqualified relative `pybind11` namespace.
+namespace PYBIND11_NAMESPACE {}
+// Correct alias.
+namespace py_ = ::pybind11;
+// Define caster. This is effectively no-op, we only ensure it compiles and we
+// don't have any symbol collision when using macro mixin.
+struct my_caster {
+ PYBIND11_TYPE_CASTER(MyType, py_::detail::const_name("MyType"));
+ bool load(py_::handle, bool) { return true; }
+
+ static py_::handle cast(const MyType &, py_::return_value_policy, py_::handle) {
+ return py_::bool_(true).release();
+ }
+};
+} // namespace other_lib
+// Effectively "alias" it into correct namespace (via inheritance).
+namespace PYBIND11_NAMESPACE {
+namespace detail {
+template <>
+struct type_caster<other_lib::MyType> : public other_lib::my_caster {};
+} // namespace detail
+} // namespace PYBIND11_NAMESPACE
TEST_SUBMODULE(custom_type_casters, m) {
// test_custom_type_casters
@@ -94,34 +145,65 @@ TEST_SUBMODULE(custom_type_casters, m) {
class ArgInspector {
public:
ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; }
- std::string g(ArgInspector1 a, const ArgInspector1 &b, int c, ArgInspector2 *d, ArgAlwaysConverts) {
+ std::string g(const 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; }
};
+ // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
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());
+ .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",
+ [](const ArgInspector2 &a, const 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; }, "f"_a);
+ m.def(
+ "floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert());
+ m.def(
+ "ints_preferred", [](int i) { return i / 2; }, "i"_a);
+ m.def(
+ "ints_only", [](int i) { return i / 2; }, "i"_a.noconvert());
// 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);
+ 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);
+
+ m.def("other_lib_type", [](other_lib::MyType x) { return x; });
}
diff --git a/3rdparty/pybind11/tests/test_custom_type_casters.py b/3rdparty/pybind11/tests/test_custom_type_casters.py
index bb74d54e..adfa6cf8 100644
--- a/3rdparty/pybind11/tests/test_custom_type_casters.py
+++ b/3rdparty/pybind11/tests/test_custom_type_casters.py
@@ -1,5 +1,5 @@
-# -*- coding: utf-8 -*-
import pytest
+
from pybind11_tests import custom_type_casters as m
@@ -18,7 +18,7 @@ def test_noconvert_args(msg):
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))
@@ -27,7 +27,7 @@ def test_noconvert_args(msg):
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"))
@@ -75,7 +75,7 @@ def test_noconvert_args(msg):
1. (i: int) -> int
Invoked with: 4.0
- """ # noqa: E501 line too long
+ """
)
assert m.ints_only(4) == 2
@@ -114,3 +114,7 @@ def test_custom_caster_destruction():
# Make sure we still only have the original object (from ..._no_destroy()) alive:
assert cstats.alive() == 1
+
+
+def test_custom_caster_other_lib():
+ assert m.other_lib_type(True)
diff --git a/3rdparty/pybind11/tests/test_custom_type_setup.cpp b/3rdparty/pybind11/tests/test_custom_type_setup.cpp
new file mode 100644
index 00000000..42fae05d
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_custom_type_setup.cpp
@@ -0,0 +1,41 @@
+/*
+ tests/test_custom_type_setup.cpp -- Tests `pybind11::custom_type_setup`
+
+ Copyright (c) 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 "pybind11_tests.h"
+
+namespace py = pybind11;
+
+namespace {
+
+struct OwnsPythonObjects {
+ py::object value = py::none();
+};
+} // namespace
+
+TEST_SUBMODULE(custom_type_setup, m) {
+ py::class_<OwnsPythonObjects> cls(
+ m, "OwnsPythonObjects", py::custom_type_setup([](PyHeapTypeObject *heap_type) {
+ auto *type = &heap_type->ht_type;
+ type->tp_flags |= Py_TPFLAGS_HAVE_GC;
+ type->tp_traverse = [](PyObject *self_base, visitproc visit, void *arg) {
+ auto &self = py::cast<OwnsPythonObjects &>(py::handle(self_base));
+ Py_VISIT(self.value.ptr());
+ return 0;
+ };
+ type->tp_clear = [](PyObject *self_base) {
+ auto &self = py::cast<OwnsPythonObjects &>(py::handle(self_base));
+ self.value = py::none();
+ return 0;
+ };
+ }));
+ cls.def(py::init<>());
+ cls.def_readwrite("value", &OwnsPythonObjects::value);
+}
diff --git a/3rdparty/pybind11/tests/test_custom_type_setup.py b/3rdparty/pybind11/tests/test_custom_type_setup.py
new file mode 100644
index 00000000..19b44c9d
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_custom_type_setup.py
@@ -0,0 +1,48 @@
+import gc
+import weakref
+
+import pytest
+
+import env # noqa: F401
+from pybind11_tests import custom_type_setup as m
+
+
+@pytest.fixture
+def gc_tester():
+ """Tests that an object is garbage collected.
+
+ Assumes that any unreferenced objects are fully collected after calling
+ `gc.collect()`. That is true on CPython, but does not appear to reliably
+ hold on PyPy.
+ """
+
+ weak_refs = []
+
+ def add_ref(obj):
+ # PyPy does not support `gc.is_tracked`.
+ if hasattr(gc, "is_tracked"):
+ assert gc.is_tracked(obj)
+ weak_refs.append(weakref.ref(obj))
+
+ yield add_ref
+
+ gc.collect()
+ for ref in weak_refs:
+ assert ref() is None
+
+
+# PyPy does not seem to reliably garbage collect.
+@pytest.mark.skipif("env.PYPY")
+def test_self_cycle(gc_tester):
+ obj = m.OwnsPythonObjects()
+ obj.value = obj
+ gc_tester(obj)
+
+
+# PyPy does not seem to reliably garbage collect.
+@pytest.mark.skipif("env.PYPY")
+def test_indirect_cycle(gc_tester):
+ obj = m.OwnsPythonObjects()
+ obj_list = [obj]
+ obj.value = obj_list
+ gc_tester(obj)
diff --git a/3rdparty/pybind11/tests/test_docstring_options.cpp b/3rdparty/pybind11/tests/test_docstring_options.cpp
index 8c8f79fd..4d44f4e2 100644
--- a/3rdparty/pybind11/tests/test_docstring_options.cpp
+++ b/3rdparty/pybind11/tests/test_docstring_options.cpp
@@ -15,35 +15,60 @@ TEST_SUBMODULE(docstring_options, m) {
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");
+ 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");
+ 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");
+ 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_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");
+ m.def(
+ "test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring");
+
+ {
+ py::options options;
+ options.disable_user_defined_docstrings();
+ options.disable_function_signatures();
+
+ m.def("test_function8", []() {});
+ }
{
py::options options;
@@ -55,7 +80,9 @@ TEST_SUBMODULE(docstring_options, m) {
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")
- ;
+ .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
index 87d80d2d..fcd16b89 100644
--- a/3rdparty/pybind11/tests/test_docstring_options.py
+++ b/3rdparty/pybind11/tests/test_docstring_options.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
from pybind11_tests import docstring_options as m
@@ -34,6 +33,9 @@ def test_docstring_options():
assert m.test_function7.__doc__.startswith("test_function7(a: int, b: int) -> None")
assert m.test_function7.__doc__.endswith("A custom docstring\n")
+ # when all options are disabled, no docstring (instead of an empty one) should be generated
+ assert m.test_function8.__doc__ is None
+
# 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
index 2cc2243d..591dacc6 100644
--- a/3rdparty/pybind11/tests/test_eigen.cpp
+++ b/3rdparty/pybind11/tests/test_eigen.cpp
@@ -7,26 +7,29 @@
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>
+#include "constructor_stats.h"
+#include "pybind11_tests.h"
+
#if defined(_MSC_VER)
-# pragma warning(disable: 4996) // C4996: std::unary_negation is deprecated
+# 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;
+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
@@ -54,16 +57,18 @@ void reset_refs() {
}
// 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); };
-
+double get_elem(const 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) {
+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; // NOLINT(clang-analyzer-core.uninitialized.Assign)
+ for (int c = 0; c < m.cols(); c++) {
+ for (int r = 0; r < m.rows(); r++) {
+ ret(r, c) += 10 * r + 100 * c; // NOLINT(clang-analyzer-core.uninitialized.Assign)
+ }
+ }
return ret;
}
@@ -90,27 +95,35 @@ TEST_SUBMODULE(eigen, m) {
// 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_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; });
+ m.def("double_mat_cm", [](const Eigen::MatrixXf &x) -> Eigen::MatrixXf { return 2.0f * x; });
+ m.def("double_mat_rm", [](const 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(); });
+ m.def("cholesky1",
+ [](const 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", [](const 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: 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
@@ -121,7 +134,8 @@ TEST_SUBMODULE(eigen, m) {
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; });
+ 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()); });
@@ -133,49 +147,72 @@ TEST_SUBMODULE(eigen, m) {
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);
+ 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);
+ 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(),
+ 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);
+ },
+ 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,
+ 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);
+ },
+ 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); });
+ 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);
- });
+ 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); }
+ // NOLINTNEXTLINE(readability-const-return-type)
static const Eigen::MatrixXd createConst() { return Eigen::MatrixXd::Ones(10, 10); }
Eigen::MatrixXd &get() { return mat; }
Eigen::MatrixXd *getPtr() { return &mat; }
@@ -183,12 +220,24 @@ TEST_SUBMODULE(eigen, m) {
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))); }
+ 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")
@@ -199,9 +248,9 @@ TEST_SUBMODULE(eigen, m) {
.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("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)
@@ -212,52 +261,55 @@ TEST_SUBMODULE(eigen, m) {
.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)
- ;
+ .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;
+ 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>();
- });
+ 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>();
- });
+ 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;
+ 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); });
+ // Our Eigen does a hack which respects constness through the numpy writeable flag.
+ // Therefore, the const return actually affects this type despite being an rvalue.
+ // NOLINTNEXTLINE(readability-const-return-type)
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>) {});
+ m.def("fixed_mutator_r", [](const Eigen::Ref<FixedMatrixR> &) {});
+ m.def("fixed_mutator_c", [](const Eigen::Ref<FixedMatrixC> &) {});
+ m.def("fixed_mutator_a", [](const 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); }); //NOLINT(clang-analyzer-core.uninitialized.UndefReturn)
- m.def("sparse_c", [mat]() -> SparseMatrixC { return Eigen::SparseView<Eigen::MatrixXf>(mat); });
+ m.def("sparse_r", [mat]() -> SparseMatrixR {
+ // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
+ 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
@@ -271,41 +323,62 @@ TEST_SUBMODULE(eigen, m) {
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); });
+ m.def("cpp_ref_any",
+ [](py::handle m) { return m.cast<py::EigenDRef<Eigen::MatrixXd>>()(1, 0); });
+ // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
// 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());
+ m.def(
+ "get_elem_nocopy",
+ [](const 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
+ 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, test_zero_length
+ // Issue #738: 1×N or N×1 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());
+ // Similarly, 0×N or N×0 matrices were not accepted--again, these should be allowed since
+ // they contain no data. This particularly affects numpy ≥ 1.23, which sets the strides to
+ // 0 if any dimension size is 0.
+ 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; });
+ // 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", [](const Eigen::VectorXd &) { return true; });
+ m.def("iss1105_row", [](const 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"));
+ 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")
@@ -317,7 +390,7 @@ TEST_SUBMODULE(eigen, m) {
// 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) {
+ m.def("get_elem_direct", [](const Eigen::Ref<const Eigen::VectorXd> &v) {
py::module_::import("numpy").attr("ones")(10);
return v(5);
});
diff --git a/3rdparty/pybind11/tests/test_eigen.py b/3rdparty/pybind11/tests/test_eigen.py
index a131dc15..9c6485de 100644
--- a/3rdparty/pybind11/tests/test_eigen.py
+++ b/3rdparty/pybind11/tests/test_eigen.py
@@ -1,5 +1,5 @@
-# -*- coding: utf-8 -*-
import pytest
+
from pybind11_tests import ConstructorStats
np = pytest.importorskip("numpy")
@@ -200,7 +200,7 @@ def test_negative_stride_from_python(msg):
double_threer(): incompatible function arguments. The following argument types are supported:
1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None
- Invoked with: """ # noqa: E501 line too long
+ Invoked with: """
+ repr(np.array([5.0, 4.0, 3.0], dtype="float32"))
)
@@ -212,7 +212,7 @@ def test_negative_stride_from_python(msg):
double_threec(): incompatible function arguments. The following argument types are supported:
1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None
- Invoked with: """ # noqa: E501 line too long
+ Invoked with: """
+ repr(np.array([7.0, 4.0, 1.0], dtype="float32"))
)
@@ -221,9 +221,7 @@ 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.diagonal_n(ref, i) == ref.diagonal(i)), f"m.diagonal_n({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:])
@@ -236,7 +234,7 @@ def test_eigen_ref_to_python():
mymat = chol(np.array([[1.0, 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)
+ ), f"cholesky{i}"
def assign_both(a1, a2, r, c, v):
@@ -253,14 +251,14 @@ def array_copy_but_one(a, r, c, v):
def test_eigen_return_references():
"""Tests various ways of returning references and non-referencing copies"""
- master = np.ones((10, 10))
+ primary = 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)
+ assign_both(a_get1, primary, 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)
+ assign_both(a_get1, primary, 2, 3, 6)
a_view1 = a.view()
assert not a_view1.flags.owndata and not a_view1.flags.writeable
@@ -273,25 +271,25 @@ def test_eigen_return_references():
a_copy1 = a.copy_get()
assert a_copy1.flags.owndata and a_copy1.flags.writeable
- np.testing.assert_array_equal(a_copy1, master)
+ np.testing.assert_array_equal(a_copy1, primary)
a_copy1[7, 7] = -44 # Shouldn't affect anything else
- c1want = array_copy_but_one(master, 7, 7, -44)
+ c1want = array_copy_but_one(primary, 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)
+ np.testing.assert_array_equal(a_copy2, primary)
a_copy2[4, 4] = -22 # Shouldn't affect anything else
- c2want = array_copy_but_one(master, 4, 4, -22)
+ c2want = array_copy_but_one(primary, 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)
+ assign_both(a_ref1, primary, 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)
+ assign_both(a_ref3, primary, 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):
@@ -299,23 +297,23 @@ def test_eigen_return_references():
a_copy3 = a.copy_ref()
assert a_copy3.flags.owndata and a_copy3.flags.writeable
- np.testing.assert_array_equal(a_copy3, master)
+ np.testing.assert_array_equal(a_copy3, primary)
a_copy3[8, 1] = 11
- c3want = array_copy_but_one(master, 8, 1, 11)
+ c3want = array_copy_but_one(primary, 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)
+ np.testing.assert_array_equal(a_copy4, primary)
a_copy4[8, 4] = 88
- c4want = array_copy_but_one(master, 8, 4, 88)
+ c4want = array_copy_but_one(primary, 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
+ primary[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
+ primary[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):
@@ -323,18 +321,18 @@ def test_eigen_return_references():
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])
+ np.testing.assert_array_equal(a_copy5, primary[2:4, 2:5])
a_copy5[1, 1] = 777
- c5want = array_copy_but_one(master[2:4, 2:5], 1, 1, 777)
+ c5want = array_copy_but_one(primary[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
+ primary[0, 0] = 50
+ primary[0, 9] = 50
+ primary[9, 0] = 50
+ primary[9, 9] = 999
a_corn2 = a.corners_const()
assert not a_corn2.flags.owndata and not a_corn2.flags.writeable
with pytest.raises(ValueError):
@@ -342,22 +340,22 @@ def test_eigen_return_references():
# 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_get1, primary)
+ np.testing.assert_array_equal(a_get2, primary)
+ np.testing.assert_array_equal(a_view1, primary)
+ np.testing.assert_array_equal(a_view2, primary)
+ np.testing.assert_array_equal(a_ref1, primary)
+ np.testing.assert_array_equal(a_ref2, primary)
+ np.testing.assert_array_equal(a_ref3, primary)
+ np.testing.assert_array_equal(a_ref4, primary)
+ np.testing.assert_array_equal(a_block1, primary[3:5, 3:5])
+ np.testing.assert_array_equal(a_block2, primary[2:5, 2:4])
+ np.testing.assert_array_equal(a_block3, primary[6:10, 7:10])
np.testing.assert_array_equal(
- a_corn1, master[0 :: master.shape[0] - 1, 0 :: master.shape[1] - 1]
+ a_corn1, primary[0 :: primary.shape[0] - 1, 0 :: primary.shape[1] - 1]
)
np.testing.assert_array_equal(
- a_corn2, master[0 :: master.shape[0] - 1, 0 :: master.shape[1] - 1]
+ a_corn2, primary[0 :: primary.shape[0] - 1, 0 :: primary.shape[1] - 1]
)
np.testing.assert_array_equal(a_copy1, c1want)
@@ -723,13 +721,13 @@ def test_sparse_signature(doc):
doc(m.sparse_copy_r)
== """
sparse_copy_r(arg0: scipy.sparse.csr_matrix[numpy.float32]) -> scipy.sparse.csr_matrix[numpy.float32]
- """ # noqa: E501 line too long
+ """
)
assert (
doc(m.sparse_copy_c)
== """
sparse_copy_c(arg0: scipy.sparse.csc_matrix[numpy.float32]) -> scipy.sparse.csc_matrix[numpy.float32]
- """ # noqa: E501 line too long
+ """
)
@@ -746,6 +744,13 @@ def test_issue738():
)
+@pytest.mark.parametrize("func", [m.iss738_f1, m.iss738_f2])
+@pytest.mark.parametrize("sizes", [(0, 2), (2, 0)])
+def test_zero_length(func, sizes):
+ """Ignore strides on a length-0 dimension (even if they would be incompatible length > 1)"""
+ assert np.all(func(np.zeros(sizes)) == np.zeros(sizes))
+
+
def test_issue1105():
"""Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen
compile-time row vectors or column vector"""
diff --git a/3rdparty/pybind11/tests/test_embed/CMakeLists.txt b/3rdparty/pybind11/tests/test_embed/CMakeLists.txt
index fabcb24e..09a36939 100644
--- a/3rdparty/pybind11/tests/test_embed/CMakeLists.txt
+++ b/3rdparty/pybind11/tests/test_embed/CMakeLists.txt
@@ -1,10 +1,13 @@
+possibly_uninitialized(PYTHON_MODULE_EXTENSION Python_INTERPRETER_ID)
+
if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy")
+ message(STATUS "Skipping embed test on 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 2.13.2)
+find_package(Catch 2.13.9)
if(CATCH_FOUND)
message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}")
@@ -22,12 +25,13 @@ pybind11_enable_warnings(test_embed)
target_link_libraries(test_embed PRIVATE pybind11::embed Catch2::Catch2 Threads::Threads)
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
- file(COPY test_interpreter.py DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
+ file(COPY test_interpreter.py test_trampoline.py DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
endif()
add_custom_target(
cpptest
COMMAND "$<TARGET_FILE:test_embed>"
+ DEPENDS test_embed
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
pybind11_add_module(external_module THIN_LTO external_module.cpp)
diff --git a/3rdparty/pybind11/tests/test_embed/catch.cpp b/3rdparty/pybind11/tests/test_embed/catch.cpp
index dd137385..a03a8b37 100644
--- a/3rdparty/pybind11/tests/test_embed/catch.cpp
+++ b/3rdparty/pybind11/tests/test_embed/catch.cpp
@@ -4,9 +4,14 @@
#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)
+// 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
+
+// Catch uses _ internally, which breaks gettext style defines
+#ifdef _
+# undef _
#endif
#define CATCH_CONFIG_RUNNER
@@ -15,7 +20,25 @@
namespace py = pybind11;
int main(int argc, char *argv[]) {
+ // Setup for TEST_CASE in test_interpreter.cpp, tagging on a large random number:
+ std::string updated_pythonpath("pybind11_test_embed_PYTHONPATH_2099743835476552");
+ const char *preexisting_pythonpath = getenv("PYTHONPATH");
+ if (preexisting_pythonpath != nullptr) {
+#if defined(_WIN32)
+ updated_pythonpath += ';';
+#else
+ updated_pythonpath += ':';
+#endif
+ updated_pythonpath += preexisting_pythonpath;
+ }
+#if defined(_WIN32)
+ _putenv_s("PYTHONPATH", updated_pythonpath.c_str());
+#else
+ setenv("PYTHONPATH", updated_pythonpath.c_str(), /*replace=*/1);
+#endif
+
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
index e9a6058b..5c482fe0 100644
--- a/3rdparty/pybind11/tests/test_embed/external_module.cpp
+++ b/3rdparty/pybind11/tests/test_embed/external_module.cpp
@@ -9,15 +9,12 @@ namespace py = pybind11;
PYBIND11_MODULE(external_module, m) {
class A {
public:
- A(int value) : v{value} {};
+ explicit A(int value) : v{value} {};
int v;
};
- py::class_<A>(m, "A")
- .def(py::init<int>())
- .def_readwrite("value", &A::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());
- });
+ 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
index 944334ce..6299293b 100644
--- a/3rdparty/pybind11/tests/test_embed/test_interpreter.cpp
+++ b/3rdparty/pybind11/tests/test_embed/test_interpreter.cpp
@@ -1,27 +1,29 @@
#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)
+// 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 <cstdlib>
#include <fstream>
#include <functional>
+#include <thread>
+#include <utility>
namespace py = pybind11;
using namespace py::literals;
class Widget {
public:
- Widget(std::string message) : message(message) { }
+ explicit Widget(std::string message) : message(std::move(message)) {}
virtual ~Widget() = default;
std::string the_message() const { return message; }
virtual int the_answer() const = 0;
+ virtual std::string argv0() const = 0;
private:
std::string message;
@@ -31,6 +33,23 @@ class PyWidget final : public Widget {
using Widget::Widget;
int the_answer() const override { PYBIND11_OVERRIDE_PURE(int, Widget, the_answer); }
+ std::string argv0() const override { PYBIND11_OVERRIDE_PURE(std::string, Widget, argv0); }
+};
+
+class test_override_cache_helper {
+
+public:
+ virtual int func() { return 0; }
+
+ test_override_cache_helper() = default;
+ virtual ~test_override_cache_helper() = default;
+ // Non-copyable
+ test_override_cache_helper &operator=(test_override_cache_helper const &Right) = delete;
+ test_override_cache_helper(test_override_cache_helper const &Copy) = delete;
+};
+
+class test_override_cache_helper_trampoline : public test_override_cache_helper {
+ int func() override { PYBIND11_OVERRIDE(int, test_override_cache_helper, func); }
};
PYBIND11_EMBEDDED_MODULE(widget_module, m) {
@@ -41,24 +60,39 @@ PYBIND11_EMBEDDED_MODULE(widget_module, m) {
m.def("add", [](int i, int j) { return i + j; });
}
-PYBIND11_EMBEDDED_MODULE(throw_exception, ) {
- throw std::runtime_error("C++ Error");
+PYBIND11_EMBEDDED_MODULE(trampoline_module, m) {
+ py::class_<test_override_cache_helper,
+ test_override_cache_helper_trampoline,
+ std::shared_ptr<test_override_cache_helper>>(m, "test_override_cache_helper")
+ .def(py::init_alias<>())
+ .def("func", &test_override_cache_helper::func);
}
+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("PYTHONPATH is used to update sys.path") {
+ // The setup for this TEST_CASE is in catch.cpp!
+ auto sys_path = py::str(py::module_::import("sys").attr("path")).cast<std::string>();
+ REQUIRE_THAT(sys_path,
+ Catch::Matchers::Contains("pybind11_test_embed_PYTHONPATH_2099743835476552"));
+}
+
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__"));
+ 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);
+ )",
+ py::globals(),
+ locals);
REQUIRE(locals["message"].cast<std::string>() == "Hello, World! - 5");
auto py_widget = module_.attr("DerivedWidget")("The question");
@@ -69,12 +103,51 @@ TEST_CASE("Pass classes and data between modules defined in C++ and Python") {
REQUIRE(cpp_widget.the_answer() == 42);
}
+TEST_CASE("Override cache") {
+ auto module_ = py::module_::import("test_trampoline");
+ REQUIRE(py::hasattr(module_, "func"));
+ REQUIRE(py::hasattr(module_, "func2"));
+
+ auto locals = py::dict(**module_.attr("__dict__"));
+
+ int i = 0;
+ for (; i < 1500; ++i) {
+ std::shared_ptr<test_override_cache_helper> p_obj;
+ std::shared_ptr<test_override_cache_helper> p_obj2;
+
+ py::object loc_inst = locals["func"]();
+ p_obj = py::cast<std::shared_ptr<test_override_cache_helper>>(loc_inst);
+
+ int ret = p_obj->func();
+
+ REQUIRE(ret == 42);
+
+ loc_inst = locals["func2"]();
+
+ p_obj2 = py::cast<std::shared_ptr<test_override_cache_helper>>(loc_inst);
+
+ p_obj2->func();
+ }
+}
+
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_exception"), "ImportError: C++ Error");
REQUIRE_THROWS_WITH(py::module_::import("throw_error_already_set"),
- Catch::Contains("ImportError: KeyError"));
+ Catch::Contains("ImportError: initialization failed"));
+
+ auto locals = py::dict("is_keyerror"_a = false, "message"_a = "not set");
+ py::exec(R"(
+ try:
+ import throw_error_already_set
+ except ImportError as e:
+ is_keyerror = type(e.__cause__) == KeyError
+ message = str(e.__cause__)
+ )",
+ py::globals(),
+ locals);
+ REQUIRE(locals["is_keyerror"].cast<bool>() == true);
+ REQUIRE(locals["message"].cast<std::string>() == "'missing'");
}
TEST_CASE("There can be only one interpreter") {
@@ -102,7 +175,7 @@ bool has_pybind11_internals_builtin() {
bool has_pybind11_internals_static() {
auto **&ipp = py::detail::get_internals_pp();
- return ipp && *ipp;
+ return (ipp != nullptr) && (*ipp != nullptr);
}
TEST_CASE("Restart the interpreter") {
@@ -110,11 +183,12 @@ TEST_CASE("Restart the interpreter") {
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);
+ 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>());
+ 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();
@@ -129,16 +203,19 @@ TEST_CASE("Restart the interpreter") {
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>());
+ 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; });
+ 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);
@@ -171,8 +248,8 @@ TEST_CASE("Subinterpreter") {
REQUIRE(has_pybind11_internals_static());
/// Create and switch to a subinterpreter.
- auto main_tstate = PyThreadState_Get();
- auto sub_tstate = Py_NewInterpreter();
+ 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
@@ -212,7 +289,7 @@ TEST_CASE("Threads") {
REQUIRE_FALSE(has_pybind11_internals_static());
constexpr auto num_threads = 10;
- auto locals = py::dict("count"_a=0);
+ auto locals = py::dict("count"_a = 0);
{
py::gil_scoped_release gil_release{};
@@ -238,7 +315,11 @@ TEST_CASE("Threads") {
struct scope_exit {
std::function<void()> f_;
explicit scope_exit(std::function<void()> f) noexcept : f_(std::move(f)) {}
- ~scope_exit() { if (f_) f_(); }
+ ~scope_exit() {
+ if (f_) {
+ f_();
+ }
+ }
};
TEST_CASE("Reload module from file") {
@@ -249,9 +330,8 @@ TEST_CASE("Reload module from file") {
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;
- });
+ 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";
@@ -262,9 +342,7 @@ TEST_CASE("Reload module from file") {
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());
- });
+ 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());
@@ -282,3 +360,43 @@ TEST_CASE("Reload module from file") {
result = module_.attr("test")().cast<int>();
REQUIRE(result == 2);
}
+
+TEST_CASE("sys.argv gets initialized properly") {
+ py::finalize_interpreter();
+ {
+ py::scoped_interpreter default_scope;
+ auto module = py::module::import("test_interpreter");
+ auto py_widget = module.attr("DerivedWidget")("The question");
+ const auto &cpp_widget = py_widget.cast<const Widget &>();
+ REQUIRE(cpp_widget.argv0().empty());
+ }
+
+ {
+ char *argv[] = {strdup("a.out")};
+ py::scoped_interpreter argv_scope(true, 1, argv);
+ std::free(argv[0]);
+ auto module = py::module::import("test_interpreter");
+ auto py_widget = module.attr("DerivedWidget")("The question");
+ const auto &cpp_widget = py_widget.cast<const Widget &>();
+ REQUIRE(cpp_widget.argv0() == "a.out");
+ }
+ py::initialize_interpreter();
+}
+
+TEST_CASE("make_iterator can be called before then after finalizing an interpreter") {
+ // Reproduction of issue #2101 (https://github.com/pybind/pybind11/issues/2101)
+ py::finalize_interpreter();
+
+ std::vector<int> container;
+ {
+ pybind11::scoped_interpreter g;
+ auto iter = pybind11::make_iterator(container.begin(), container.end());
+ }
+
+ REQUIRE_NOTHROW([&]() {
+ pybind11::scoped_interpreter g;
+ auto iter = pybind11::make_iterator(container.begin(), container.end());
+ }());
+
+ py::initialize_interpreter();
+}
diff --git a/3rdparty/pybind11/tests/test_embed/test_interpreter.py b/3rdparty/pybind11/tests/test_embed/test_interpreter.py
index 6174ede4..f2794497 100644
--- a/3rdparty/pybind11/tests/test_embed/test_interpreter.py
+++ b/3rdparty/pybind11/tests/test_embed/test_interpreter.py
@@ -1,10 +1,14 @@
-# -*- coding: utf-8 -*-
+import sys
+
from widget_module import Widget
class DerivedWidget(Widget):
def __init__(self, message):
- super(DerivedWidget, self).__init__(message)
+ super().__init__(message)
def the_answer(self):
return 42
+
+ def argv0(self):
+ return sys.argv[0]
diff --git a/3rdparty/pybind11/tests/test_embed/test_trampoline.py b/3rdparty/pybind11/tests/test_embed/test_trampoline.py
new file mode 100644
index 00000000..8e14e8ef
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_embed/test_trampoline.py
@@ -0,0 +1,16 @@
+import trampoline_module
+
+
+def func():
+ class Test(trampoline_module.test_override_cache_helper):
+ def func(self):
+ return 42
+
+ return Test()
+
+
+def func2():
+ class Test(trampoline_module.test_override_cache_helper):
+ pass
+
+ return Test()
diff --git a/3rdparty/pybind11/tests/test_enum.cpp b/3rdparty/pybind11/tests/test_enum.cpp
index 31530892..2597b275 100644
--- a/3rdparty/pybind11/tests/test_enum.cpp
+++ b/3rdparty/pybind11/tests/test_enum.cpp
@@ -11,11 +11,7 @@
TEST_SUBMODULE(enums, m) {
// test_unscoped_enum
- enum UnscopedEnum {
- EOne = 1,
- ETwo,
- EThree
- };
+ 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")
@@ -23,10 +19,7 @@ TEST_SUBMODULE(enums, m) {
.export_values();
// test_scoped_enum
- enum class ScopedEnum {
- Two = 2,
- Three
- };
+ enum class ScopedEnum { Two = 2, Three };
py::enum_<ScopedEnum>(m, "ScopedEnum", py::arithmetic())
.value("Two", ScopedEnum::Two)
.value("Three", ScopedEnum::Three);
@@ -36,11 +29,7 @@ TEST_SUBMODULE(enums, m) {
});
// test_binary_operators
- enum Flags {
- Read = 4,
- Write = 2,
- Execute = 1
- };
+ enum Flags { Read = 4, Write = 2, Execute = 1 };
py::enum_<Flags>(m, "Flags", py::arithmetic())
.value("Read", Flags::Read)
.value("Write", Flags::Write)
@@ -50,14 +39,9 @@ TEST_SUBMODULE(enums, m) {
// test_implicit_conversion
class ClassWithUnscopedEnum {
public:
- enum EMode {
- EFirstMode = 1,
- ESecondMode
- };
-
- static EMode test_function(EMode mode) {
- return mode;
- }
+ 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);
@@ -67,21 +51,83 @@ TEST_SUBMODULE(enums, m) {
.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) { });
+ 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
- };
+ 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::ONE) // NOTE: all value function calls are called with the
+ // same first parameter value
.value("ONE", SimpleEnum::TWO)
.value("ONE", SimpleEnum::THREE)
.export_values();
});
+
+ // test_enum_scalar
+ enum UnscopedUCharEnum : unsigned char {};
+ enum class ScopedShortEnum : short {};
+ enum class ScopedLongEnum : long {};
+ enum UnscopedUInt64Enum : std::uint64_t {};
+ static_assert(
+ py::detail::all_of<
+ std::is_same<py::enum_<UnscopedUCharEnum>::Scalar, unsigned char>,
+ std::is_same<py::enum_<ScopedShortEnum>::Scalar, short>,
+ std::is_same<py::enum_<ScopedLongEnum>::Scalar, long>,
+ std::is_same<py::enum_<UnscopedUInt64Enum>::Scalar, std::uint64_t>>::value,
+ "Error during the deduction of enum's scalar type with normal integer underlying");
+
+ // test_enum_scalar_with_char_underlying
+ enum class ScopedCharEnum : char { Zero, Positive };
+ enum class ScopedWCharEnum : wchar_t { Zero, Positive };
+ enum class ScopedChar32Enum : char32_t { Zero, Positive };
+ enum class ScopedChar16Enum : char16_t { Zero, Positive };
+
+ // test the scalar of char type enums according to chapter 'Character types'
+ // from https://en.cppreference.com/w/cpp/language/types
+ static_assert(
+ py::detail::any_of<
+ std::is_same<py::enum_<ScopedCharEnum>::Scalar, signed char>, // e.g. gcc on x86
+ std::is_same<py::enum_<ScopedCharEnum>::Scalar, unsigned char> // e.g. arm linux
+ >::value,
+ "char should be cast to either signed char or unsigned char");
+ static_assert(sizeof(py::enum_<ScopedWCharEnum>::Scalar) == 2
+ || sizeof(py::enum_<ScopedWCharEnum>::Scalar) == 4,
+ "wchar_t should be either 16 bits (Windows) or 32 (everywhere else)");
+ static_assert(
+ py::detail::all_of<
+ std::is_same<py::enum_<ScopedChar32Enum>::Scalar, std::uint_least32_t>,
+ std::is_same<py::enum_<ScopedChar16Enum>::Scalar, std::uint_least16_t>>::value,
+ "char32_t, char16_t (and char8_t)'s size, signedness, and alignment is determined");
+#if defined(PYBIND11_HAS_U8STRING)
+ enum class ScopedChar8Enum : char8_t { Zero, Positive };
+ static_assert(std::is_same<py::enum_<ScopedChar8Enum>::Scalar, unsigned char>::value);
+#endif
+
+ // test_char_underlying_enum
+ py::enum_<ScopedCharEnum>(m, "ScopedCharEnum")
+ .value("Zero", ScopedCharEnum::Zero)
+ .value("Positive", ScopedCharEnum::Positive);
+ py::enum_<ScopedWCharEnum>(m, "ScopedWCharEnum")
+ .value("Zero", ScopedWCharEnum::Zero)
+ .value("Positive", ScopedWCharEnum::Positive);
+ py::enum_<ScopedChar32Enum>(m, "ScopedChar32Enum")
+ .value("Zero", ScopedChar32Enum::Zero)
+ .value("Positive", ScopedChar32Enum::Positive);
+ py::enum_<ScopedChar16Enum>(m, "ScopedChar16Enum")
+ .value("Zero", ScopedChar16Enum::Zero)
+ .value("Positive", ScopedChar16Enum::Positive);
+
+ // test_bool_underlying_enum
+ enum class ScopedBoolEnum : bool { FALSE, TRUE };
+
+ // bool is unsigned (std::is_signed returns false) and 1-byte long, so represented with u8
+ static_assert(std::is_same<py::enum_<ScopedBoolEnum>::Scalar, std::uint8_t>::value, "");
+
+ py::enum_<ScopedBoolEnum>(m, "ScopedBoolEnum")
+ .value("FALSE", ScopedBoolEnum::FALSE)
+ .value("TRUE", ScopedBoolEnum::TRUE);
}
diff --git a/3rdparty/pybind11/tests/test_enum.py b/3rdparty/pybind11/tests/test_enum.py
index f6b24fc2..f14a7239 100644
--- a/3rdparty/pybind11/tests/test_enum.py
+++ b/3rdparty/pybind11/tests/test_enum.py
@@ -1,5 +1,5 @@
-# -*- coding: utf-8 -*-
import pytest
+
from pybind11_tests import enums as m
@@ -13,15 +13,24 @@ def test_unscoped_enum():
# name property
assert m.UnscopedEnum.EOne.name == "EOne"
+ assert m.UnscopedEnum.EOne.value == 1
assert m.UnscopedEnum.ETwo.name == "ETwo"
- assert m.EOne.name == "EOne"
- # name readonly
+ assert m.UnscopedEnum.ETwo.value == 2
+ assert m.EOne is m.UnscopedEnum.EOne
+ # name, value readonly
with pytest.raises(AttributeError):
m.UnscopedEnum.EOne.name = ""
- # name returns a copy
- foo = m.UnscopedEnum.EOne.name
- foo = "bar"
+ with pytest.raises(AttributeError):
+ m.UnscopedEnum.EOne.value = 10
+ # name, value returns a copy
+ # TODO: Neither the name nor value tests actually check against aliasing.
+ # Use a mutable type that has reference semantics.
+ nonaliased_name = m.UnscopedEnum.EOne.name
+ nonaliased_name = "bar" # noqa: F841
assert m.UnscopedEnum.EOne.name == "EOne"
+ nonaliased_value = m.UnscopedEnum.EOne.value
+ nonaliased_value = 10 # noqa: F841
+ assert m.UnscopedEnum.EOne.value == 1
# __members__ property
assert m.UnscopedEnum.__members__ == {
@@ -33,8 +42,8 @@ def test_unscoped_enum():
with pytest.raises(AttributeError):
m.UnscopedEnum.__members__ = {}
# __members__ returns a copy
- foo = m.UnscopedEnum.__members__
- foo["bar"] = "baz"
+ nonaliased_members = m.UnscopedEnum.__members__
+ nonaliased_members["bar"] = "baz"
assert m.UnscopedEnum.__members__ == {
"EOne": m.UnscopedEnum.EOne,
"ETwo": m.UnscopedEnum.ETwo,
@@ -73,16 +82,16 @@ Members:
assert not (y == "2")
with pytest.raises(TypeError):
- y < object()
+ y < object() # noqa: B015
with pytest.raises(TypeError):
- y <= object()
+ y <= object() # noqa: B015
with pytest.raises(TypeError):
- y > object()
+ y > object() # noqa: B015
with pytest.raises(TypeError):
- y >= object()
+ y >= object() # noqa: B015
with pytest.raises(TypeError):
y | object()
@@ -134,13 +143,13 @@ def test_scoped_enum():
assert not (z == object())
# Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions)
with pytest.raises(TypeError):
- z > 3
+ z > 3 # noqa: B015
with pytest.raises(TypeError):
- z < 3
+ z < 3 # noqa: B015
with pytest.raises(TypeError):
- z >= 3
+ z >= 3 # noqa: B015
with pytest.raises(TypeError):
- z <= 3
+ z <= 3 # noqa: B015
# order
assert m.ScopedEnum.Two < m.ScopedEnum.Three
@@ -208,10 +217,16 @@ def test_binary_operators():
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_int(m.ScopedCharEnum.Positive)
+ m.test_enum_to_int(m.ScopedBoolEnum.TRUE)
m.test_enum_to_uint(m.Flags.Read)
m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode)
+ m.test_enum_to_uint(m.ScopedCharEnum.Positive)
+ m.test_enum_to_uint(m.ScopedBoolEnum.TRUE)
m.test_enum_to_long_long(m.Flags.Read)
m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode)
+ m.test_enum_to_long_long(m.ScopedCharEnum.Positive)
+ m.test_enum_to_long_long(m.ScopedBoolEnum.TRUE)
def test_duplicate_enum_name():
@@ -220,6 +235,28 @@ def test_duplicate_enum_name():
assert str(excinfo.value) == 'SimpleEnum: element "ONE" already exists!'
+def test_char_underlying_enum(): # Issue #1331/PR #1334:
+ assert type(m.ScopedCharEnum.Positive.__int__()) is int
+ assert int(m.ScopedChar16Enum.Zero) == 0
+ assert hash(m.ScopedChar32Enum.Positive) == 1
+ assert type(m.ScopedCharEnum.Positive.__getstate__()) is int
+ assert m.ScopedWCharEnum(1) == m.ScopedWCharEnum.Positive
+ with pytest.raises(TypeError):
+ # Even if the underlying type is char, only an int can be used to construct the enum:
+ m.ScopedCharEnum("0")
+
+
+def test_bool_underlying_enum():
+ assert type(m.ScopedBoolEnum.TRUE.__int__()) is int
+ assert int(m.ScopedBoolEnum.FALSE) == 0
+ assert hash(m.ScopedBoolEnum.TRUE) == 1
+ assert type(m.ScopedBoolEnum.TRUE.__getstate__()) is int
+ assert m.ScopedBoolEnum(1) == m.ScopedBoolEnum.TRUE
+ # Enum could construct with a bool
+ # (bool is a strict subclass of int, and False will be converted to 0)
+ assert m.ScopedBoolEnum(False) == m.ScopedBoolEnum.FALSE
+
+
def test_docstring_signatures():
for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
for attr in enum_type.__dict__.values():
diff --git a/3rdparty/pybind11/tests/test_eval.cpp b/3rdparty/pybind11/tests/test_eval.cpp
index 5416c2ec..cd2903f0 100644
--- a/3rdparty/pybind11/tests/test_eval.cpp
+++ b/3rdparty/pybind11/tests/test_eval.cpp
@@ -7,10 +7,12 @@
BSD-style license that can be found in the LICENSE file.
*/
-
#include <pybind11/eval.h>
+
#include "pybind11_tests.h"
+#include <utility>
+
TEST_SUBMODULE(eval_, m) {
// test_evals
@@ -18,16 +20,13 @@ TEST_SUBMODULE(eval_, m) {
m.def("test_eval_statements", [global]() {
auto local = py::dict();
- local["call_test"] = py::cpp_function([&]() -> int {
- return 42;
- });
+ local["call_test"] = py::cpp_function([&]() -> int { return 42; });
// Regular string literal
- py::exec(
- "message = 'Hello World!'\n"
- "x = call_test()",
- global, local
- );
+ py::exec("message = 'Hello World!'\n"
+ "x = call_test()",
+ global,
+ local);
// Multi-line raw string literal
py::exec(R"(
@@ -35,8 +34,9 @@ TEST_SUBMODULE(eval_, m) {
print(message)
else:
raise RuntimeError
- )", global, local
- );
+ )",
+ global,
+ local);
auto x = local["x"].cast<int>();
return x == 42;
@@ -51,9 +51,7 @@ TEST_SUBMODULE(eval_, m) {
m.def("test_eval_single_statement", []() {
auto local = py::dict();
- local["call_test"] = py::cpp_function([&]() -> int {
- return 42;
- });
+ 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>();
@@ -64,10 +62,10 @@ TEST_SUBMODULE(eval_, m) {
auto local = py::dict();
local["y"] = py::int_(43);
- int val_out;
+ int val_out = 0;
local["call_test2"] = py::cpp_function([&](int value) { val_out = value; });
- auto result = py::eval_file(filename, global, local);
+ auto result = py::eval_file(std::move(filename), global, local);
return val_out == 43 && result.is_none();
});
@@ -91,9 +89,30 @@ TEST_SUBMODULE(eval_, m) {
// test_eval_empty_globals
m.def("eval_empty_globals", [](py::object global) {
- if (global.is_none())
+ if (global.is_none()) {
global = py::dict();
+ }
auto int_class = py::eval("isinstance(42, int)", global);
return global;
});
+
+ // test_eval_closure
+ m.def("test_eval_closure", []() {
+ py::dict global;
+ global["closure_value"] = 42;
+ py::dict local;
+ local["closure_value"] = 0;
+ py::exec(R"(
+ local_value = closure_value
+
+ def func_global():
+ return closure_value
+
+ def func_local():
+ return local_value
+ )",
+ global,
+ local);
+ return std::make_pair(global, local);
+ });
}
diff --git a/3rdparty/pybind11/tests/test_eval.py b/3rdparty/pybind11/tests/test_eval.py
index 1bb05af0..51b6b796 100644
--- a/3rdparty/pybind11/tests/test_eval.py
+++ b/3rdparty/pybind11/tests/test_eval.py
@@ -1,10 +1,8 @@
-# -*- coding: utf-8 -*-
import os
import pytest
import env # noqa: F401
-
from pybind11_tests import eval_ as m
@@ -19,7 +17,7 @@ def test_evals(capture):
assert m.test_eval_failure()
-@pytest.mark.xfail("env.PYPY and not env.PY2", raises=RuntimeError)
+@pytest.mark.xfail("env.PYPY", raises=RuntimeError)
def test_eval_file():
filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
assert m.test_eval_file(filename)
@@ -33,3 +31,20 @@ def test_eval_empty_globals():
g = {}
assert "__builtins__" in m.eval_empty_globals(g)
assert "__builtins__" in g
+
+
+def test_eval_closure():
+ global_, local = m.test_eval_closure()
+
+ assert global_["closure_value"] == 42
+ assert local["closure_value"] == 0
+
+ assert "local_value" not in global_
+ assert local["local_value"] == 0
+
+ assert "func_global" not in global_
+ assert local["func_global"]() == 42
+
+ assert "func_local" not in global_
+ with pytest.raises(NameError):
+ local["func_local"]()
diff --git a/3rdparty/pybind11/tests/test_eval_call.py b/3rdparty/pybind11/tests/test_eval_call.py
index 373b67ba..fd1da2a5 100644
--- a/3rdparty/pybind11/tests/test_eval_call.py
+++ b/3rdparty/pybind11/tests/test_eval_call.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# This file is called from 'test_eval.py'
if "call_test2" in locals():
diff --git a/3rdparty/pybind11/tests/test_exceptions.cpp b/3rdparty/pybind11/tests/test_exceptions.cpp
index e27c16df..3583f22a 100644
--- a/3rdparty/pybind11/tests/test_exceptions.cpp
+++ b/3rdparty/pybind11/tests/test_exceptions.cpp
@@ -6,14 +6,21 @@
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
+#include "test_exceptions.h"
+#include "local_bindings.h"
#include "pybind11_tests.h"
+#include <exception>
+#include <stdexcept>
+#include <utility>
+
// A type that should be raised as an exception in Python
class MyException : public std::exception {
public:
- explicit MyException(const char * m) : message{m} {}
- const char * what() const noexcept override {return message.c_str();}
+ explicit MyException(const char *m) : message{m} {}
+ const char *what() const noexcept override { return message.c_str(); }
+
private:
std::string message = "";
};
@@ -21,8 +28,9 @@ private:
// A type that should be translated to a standard Python exception
class MyException2 : public std::exception {
public:
- explicit MyException2(const char * m) : message{m} {}
- const char * what() const noexcept override {return message.c_str();}
+ explicit MyException2(const char *m) : message{m} {}
+ const char *what() const noexcept override { return message.c_str(); }
+
private:
std::string message = "";
};
@@ -30,13 +38,13 @@ private:
// 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();}
+ explicit MyException3(const char *m) : message{m} {}
+ virtual const char *what() const noexcept { return message.c_str(); }
// Rule of 5 BEGIN: to preempt compiler warnings.
- MyException3(const MyException3&) = default;
- MyException3(MyException3&&) = default;
- MyException3& operator=(const MyException3&) = default;
- MyException3& operator=(MyException3&&) = default;
+ MyException3(const MyException3 &) = default;
+ MyException3(MyException3 &&) = default;
+ MyException3 &operator=(const MyException3 &) = default;
+ MyException3 &operator=(MyException3 &&) = default;
virtual ~MyException3() = default;
// Rule of 5 END.
private:
@@ -47,13 +55,13 @@ private:
// and delegated to its exception translator
class MyException4 : public std::exception {
public:
- explicit MyException4(const char * m) : message{m} {}
- const char * what() const noexcept override {return message.c_str();}
+ explicit MyException4(const char *m) : message{m} {}
+ 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:
@@ -65,24 +73,31 @@ class MyException5_1 : public MyException5 {
using MyException5::MyException5;
};
+// Exception that will be caught via the module local translator.
+class MyException6 : public std::exception {
+public:
+ explicit MyException6(const char *m) : message{m} {}
+ const char *what() const noexcept override { return message.c_str(); }
+
+private:
+ std::string message = "";
+};
+
struct PythonCallInDestructor {
- PythonCallInDestructor(const py::dict &d) : d(d) {}
+ explicit PythonCallInDestructor(const py::dict &d) : d(d) {}
~PythonCallInDestructor() { d["good"] = true; }
py::dict d;
};
-
-
struct PythonAlreadySetInDestructor {
- PythonAlreadySetInDestructor(const py::str &s) : s(s) {}
+ explicit PythonAlreadySetInDestructor(const py::str &s) : s(s) {}
~PythonAlreadySetInDestructor() {
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) {
+ } catch (py::error_already_set &ex) {
ex.discard_as_unraisable(s);
}
}
@@ -90,17 +105,22 @@ struct PythonAlreadySetInDestructor {
py::str s;
};
+std::string error_already_set_what(const py::object &exc_type, const py::object &exc_value) {
+ PyErr_SetObject(exc_type.ptr(), exc_value.ptr());
+ return py::error_already_set().what();
+}
TEST_SUBMODULE(exceptions, m) {
- m.def("throw_std_exception", []() {
- throw std::runtime_error("This exception was intentionally thrown.");
- });
+ 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);
+ if (p) {
+ std::rethrow_exception(p);
+ }
} catch (const MyException &e) {
// Set MyException as the active python error
ex(e.what());
@@ -112,7 +132,9 @@ TEST_SUBMODULE(exceptions, m) {
// never by visible from Python
py::register_exception_translator([](std::exception_ptr p) {
try {
- if (p) std::rethrow_exception(p);
+ if (p) {
+ std::rethrow_exception(p);
+ }
} catch (const MyException2 &e) {
// Translate this exception to a standard RuntimeError
PyErr_SetString(PyExc_RuntimeError, e.what());
@@ -124,7 +146,9 @@ TEST_SUBMODULE(exceptions, m) {
// translator for MyException by throwing a new exception
py::register_exception_translator([](std::exception_ptr p) {
try {
- if (p) std::rethrow_exception(p);
+ if (p) {
+ std::rethrow_exception(p);
+ }
} catch (const MyException4 &e) {
throw MyException(e.what());
}
@@ -135,22 +159,42 @@ TEST_SUBMODULE(exceptions, m) {
// A slightly more complicated one that declares MyException5_1 as a subclass of MyException5
py::register_exception<MyException5_1>(m, "MyException5_1", ex5.ptr());
+ // py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException")
+
+ py::register_local_exception_translator([](std::exception_ptr p) {
+ try {
+ if (p) {
+ std::rethrow_exception(p);
+ }
+ } catch (const MyException6 &e) {
+ PyErr_SetString(PyExc_RuntimeError, e.what());
+ }
+ });
+
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("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",
+ []() { 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("throws6", []() { throw MyException6("MyException6 only handled in this module"); });
+ 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("throws_local_error", []() { throw LocalException("never caught"); });
+ m.def("throws_local_simple_error", []() { throw LocalSimpleException("this mod"); });
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;
+ } catch (py::error_already_set &ex) {
+ if (!ex.matches(PyExc_KeyError)) {
+ throw;
+ }
return true;
}
return false;
@@ -160,9 +204,10 @@ TEST_SUBMODULE(exceptions, m) {
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;
+ } catch (py::error_already_set &ex) {
+ if (!ex.matches(PyExc_Exception)) {
+ throw;
+ }
return true;
}
return false;
@@ -171,61 +216,132 @@ TEST_SUBMODULE(exceptions, m) {
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;
+ } 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)
+ 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")))
- {
+ } catch (const std::runtime_error &e) {
+ if ((err && e.what() != std::string("ValueError: foo"))
+ || (!err
+ && e.what()
+ != std::string("Internal error: pybind11::error_already_set called "
+ "while Python error indicator not set."))) {
PyErr_Clear();
throw std::runtime_error("error message mismatch");
}
}
PyErr_Clear();
- if (err)
+ if (err) {
PyErr_SetString(PyExc_ValueError, "foo");
+ }
throw py::error_already_set();
});
- m.def("python_call_in_destructor", [](py::dict d) {
+ m.def("python_call_in_destructor", [](const py::dict &d) {
+ bool retval = false;
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;
+ } catch (const py::error_already_set &) {
+ retval = true;
}
- return false;
+ return retval;
});
- m.def("python_alreadyset_in_destructor", [](py::str s) {
+ m.def("python_alreadyset_in_destructor", [](const py::str &s) {
PythonAlreadySetInDestructor alreadyset_in_destructor(s);
return true;
});
// 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;
+ m.def("try_catch",
+ [m](const py::object &exc_type, const py::function &f, const py::args &args) {
+ try {
+ f(*args);
+ } catch (py::error_already_set &ex) {
+ if (ex.matches(exc_type)) {
+ py::print(ex.what());
+ } else {
+ // Simply `throw;` also works and is better, but using `throw ex;`
+ // here to cover that situation (as observed in the wild).
+ throw ex; // Invokes the copy ctor.
+ }
+ }
+ });
+
+ // Test repr that cannot be displayed
+ m.def("simple_bool_passthrough", [](bool x) { return x; });
+
+ m.def("throw_should_be_translated_to_key_error", []() { throw shared_exception(); });
+
+ m.def("raise_from", []() {
+ PyErr_SetString(PyExc_ValueError, "inner");
+ py::raise_from(PyExc_ValueError, "outer");
+ throw py::error_already_set();
+ });
+
+ m.def("raise_from_already_set", []() {
+ try {
+ PyErr_SetString(PyExc_ValueError, "inner");
+ throw py::error_already_set();
+ } catch (py::error_already_set &e) {
+ py::raise_from(e, PyExc_ValueError, "outer");
+ throw py::error_already_set();
}
});
- // Test repr that cannot be displayed
- m.def("simple_bool_passthrough", [](bool x) {return x;});
+ m.def("throw_nested_exception", []() {
+ try {
+ throw std::runtime_error("Inner Exception");
+ } catch (const std::runtime_error &) {
+ std::throw_with_nested(std::runtime_error("Outer Exception"));
+ }
+ });
+
+ m.def("error_already_set_what", [](const py::object &exc_type, const py::object &exc_value) {
+ PyErr_SetObject(exc_type.ptr(), exc_value.ptr());
+ std::string what = py::error_already_set().what();
+ bool py_err_set_after_what = (PyErr_Occurred() != nullptr);
+ PyErr_Clear();
+ return py::make_tuple(std::move(what), py_err_set_after_what);
+ });
+
+ m.def("test_cross_module_interleaved_error_already_set", []() {
+ auto cm = py::module_::import("cross_module_interleaved_error_already_set");
+ auto interleaved_error_already_set
+ = reinterpret_cast<void (*)()>(PyLong_AsVoidPtr(cm.attr("funcaddr").ptr()));
+ interleaved_error_already_set();
+ });
+
+ m.def("test_error_already_set_double_restore", [](bool dry_run) {
+ PyErr_SetString(PyExc_ValueError, "Random error.");
+ py::error_already_set e;
+ e.restore();
+ PyErr_Clear();
+ if (!dry_run) {
+ e.restore();
+ }
+ });
+ // https://github.com/pybind/pybind11/issues/4075
+ m.def("test_pypy_oserror_normalization", []() {
+ try {
+ py::module_::import("io").attr("open")("this_filename_must_not_exist", "r");
+ } catch (const py::error_already_set &e) {
+ return py::str(e.what()); // str must be built before e goes out of scope.
+ }
+ return py::str("UNEXPECTED");
+ });
}
diff --git a/3rdparty/pybind11/tests/test_exceptions.h b/3rdparty/pybind11/tests/test_exceptions.h
new file mode 100644
index 00000000..03684b89
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_exceptions.h
@@ -0,0 +1,13 @@
+#pragma once
+#include "pybind11_tests.h"
+
+#include <stdexcept>
+
+// shared exceptions for cross_module_tests
+
+class PYBIND11_EXPORT_EXCEPTION shared_exception : public pybind11::builtin_exception {
+public:
+ using builtin_exception::builtin_exception;
+ explicit shared_exception() : shared_exception("") {}
+ void set_error() const override { PyErr_SetString(PyExc_RuntimeError, what()); }
+};
diff --git a/3rdparty/pybind11/tests/test_exceptions.py b/3rdparty/pybind11/tests/test_exceptions.py
index 95eac709..70b6ffea 100644
--- a/3rdparty/pybind11/tests/test_exceptions.py
+++ b/3rdparty/pybind11/tests/test_exceptions.py
@@ -1,10 +1,10 @@
-# -*- coding: utf-8 -*-
import sys
import pytest
-from pybind11_tests import exceptions as m
+import env
import pybind11_cross_module_tests as cm
+from pybind11_tests import exceptions as m
def test_std_exception(msg):
@@ -16,14 +16,31 @@ def test_std_exception(msg):
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"
+ assert (
+ msg(excinfo.value)
+ == "Internal error: pybind11::error_already_set called while Python error indicator not set."
+ )
with pytest.raises(ValueError) as excinfo:
m.throw_already_set(True)
assert msg(excinfo.value) == "foo"
-def test_cross_module_exceptions():
+def test_raise_from(msg):
+ with pytest.raises(ValueError) as excinfo:
+ m.raise_from()
+ assert msg(excinfo.value) == "outer"
+ assert msg(excinfo.value.__cause__) == "inner"
+
+
+def test_raise_from_already_set(msg):
+ with pytest.raises(ValueError) as excinfo:
+ m.raise_from_already_set()
+ assert msg(excinfo.value) == "outer"
+ assert msg(excinfo.value.__cause__) == "inner"
+
+
+def test_cross_module_exceptions(msg):
with pytest.raises(RuntimeError) as excinfo:
cm.raise_runtime_error()
assert str(excinfo.value) == "My runtime error"
@@ -43,6 +60,27 @@ def test_cross_module_exceptions():
with pytest.raises(StopIteration) as excinfo:
cm.throw_stop_iteration()
+ with pytest.raises(cm.LocalSimpleException) as excinfo:
+ cm.throw_local_simple_error()
+ assert msg(excinfo.value) == "external mod"
+
+ with pytest.raises(KeyError) as excinfo:
+ cm.throw_local_error()
+ # KeyError is a repr of the key, so it has an extra set of quotes
+ assert str(excinfo.value) == "'just local'"
+
+
+# TODO: FIXME
+@pytest.mark.xfail(
+ "env.PYPY and env.MACOS",
+ raises=RuntimeError,
+ reason="Expected failure with PyPy and libc++ (Issue #2847 & PR #2999)",
+)
+def test_cross_module_exception_translator():
+ with pytest.raises(KeyError):
+ # translator registered in cross_module_tests
+ m.throw_should_be_translated_to_key_error()
+
def test_python_call_in_catch():
d = {}
@@ -50,18 +88,32 @@ def test_python_call_in_catch():
assert d["good"] is True
+def ignore_pytest_unraisable_warning(f):
+ unraisable = "PytestUnraisableExceptionWarning"
+ if hasattr(pytest, unraisable): # Python >= 3.8 and pytest >= 6
+ dec = pytest.mark.filterwarnings(f"ignore::pytest.{unraisable}")
+ return dec(f)
+ else:
+ return f
+
+
+# TODO: find out why this fails on PyPy, https://foss.heptapod.net/pypy/pypy/-/issues/3583
+@pytest.mark.xfail(env.PYPY, reason="Failure on PyPy 3.8 (7.3.7)", strict=False)
+@ignore_pytest_unraisable_warning
def test_python_alreadyset_in_destructor(monkeypatch, capsys):
hooked = False
- triggered = [False] # mutable, so Python 2.7 closure can modify it
+ triggered = False
if hasattr(sys, "unraisablehook"): # Python 3.8+
hooked = True
- default_hook = sys.unraisablehook
+ # Don't take `sys.unraisablehook`, as that's overwritten by pytest
+ default_hook = sys.__unraisablehook__
def hook(unraisable_hook_args):
exc_type, exc_value, exc_tb, err_msg, obj = unraisable_hook_args
if obj == "already_set demo":
- triggered[0] = True
+ nonlocal triggered
+ triggered = True
default_hook(unraisable_hook_args)
return
@@ -70,11 +122,11 @@ def test_python_alreadyset_in_destructor(monkeypatch, capsys):
assert m.python_alreadyset_in_destructor("already_set demo") is True
if hooked:
- assert triggered[0] is True
+ assert triggered is True
_, captured_stderr = capsys.readouterr()
- # Error message is different in Python 2 and 3, check for words that appear in both
- assert "ignored" in captured_stderr and "already_set demo" in captured_stderr
+ assert captured_stderr.startswith("Exception ignored in: 'already_set demo'")
+ assert captured_stderr.rstrip().endswith("KeyError: 'bar'")
def test_exception_matches():
@@ -133,8 +185,8 @@ def test_custom(msg):
with pytest.raises(m.MyException5) as excinfo:
try:
m.throws5()
- except m.MyException5_1:
- raise RuntimeError("Exception error: caught child from parent")
+ except m.MyException5_1 as err:
+ raise RuntimeError("Exception error: caught child from parent") from err
assert msg(excinfo.value) == "this is a helper-defined translated exception"
@@ -188,11 +240,129 @@ def test_nested_throws(capture):
assert str(excinfo.value) == "this is a helper-defined translated exception"
+def test_throw_nested_exception():
+ with pytest.raises(RuntimeError) as excinfo:
+ m.throw_nested_exception()
+ assert str(excinfo.value) == "Outer Exception"
+ assert str(excinfo.value.__cause__) == "Inner Exception"
+
+
# This can often happen if you wrap a pybind11 class in a Python wrapper
def test_invalid_repr():
- class MyRepr(object):
+ class MyRepr:
def __repr__(self):
raise AttributeError("Example error")
with pytest.raises(TypeError):
m.simple_bool_passthrough(MyRepr())
+
+
+def test_local_translator(msg):
+ """Tests that a local translator works and that the local translator from
+ the cross module is not applied"""
+ with pytest.raises(RuntimeError) as excinfo:
+ m.throws6()
+ assert msg(excinfo.value) == "MyException6 only handled in this module"
+
+ with pytest.raises(RuntimeError) as excinfo:
+ m.throws_local_error()
+ assert not isinstance(excinfo.value, KeyError)
+ assert msg(excinfo.value) == "never caught"
+
+ with pytest.raises(Exception) as excinfo:
+ m.throws_local_simple_error()
+ assert not isinstance(excinfo.value, cm.LocalSimpleException)
+ assert msg(excinfo.value) == "this mod"
+
+
+class FlakyException(Exception):
+ def __init__(self, failure_point):
+ if failure_point == "failure_point_init":
+ raise ValueError("triggered_failure_point_init")
+ self.failure_point = failure_point
+
+ def __str__(self):
+ if self.failure_point == "failure_point_str":
+ raise ValueError("triggered_failure_point_str")
+ return "FlakyException.__str__"
+
+
+@pytest.mark.parametrize(
+ "exc_type, exc_value, expected_what",
+ (
+ (ValueError, "plain_str", "ValueError: plain_str"),
+ (ValueError, ("tuple_elem",), "ValueError: tuple_elem"),
+ (FlakyException, ("happy",), "FlakyException: FlakyException.__str__"),
+ ),
+)
+def test_error_already_set_what_with_happy_exceptions(
+ exc_type, exc_value, expected_what
+):
+ what, py_err_set_after_what = m.error_already_set_what(exc_type, exc_value)
+ assert not py_err_set_after_what
+ assert what == expected_what
+
+
+@pytest.mark.skipif("env.PYPY", reason="PyErr_NormalizeException Segmentation fault")
+def test_flaky_exception_failure_point_init():
+ with pytest.raises(RuntimeError) as excinfo:
+ m.error_already_set_what(FlakyException, ("failure_point_init",))
+ lines = str(excinfo.value).splitlines()
+ # PyErr_NormalizeException replaces the original FlakyException with ValueError:
+ assert lines[:3] == [
+ "pybind11::error_already_set: MISMATCH of original and normalized active exception types:"
+ " ORIGINAL FlakyException REPLACED BY ValueError: triggered_failure_point_init",
+ "",
+ "At:",
+ ]
+ # Checking the first two lines of the traceback as formatted in error_string():
+ assert "test_exceptions.py(" in lines[3]
+ assert lines[3].endswith("): __init__")
+ assert lines[4].endswith("): test_flaky_exception_failure_point_init")
+
+
+def test_flaky_exception_failure_point_str():
+ what, py_err_set_after_what = m.error_already_set_what(
+ FlakyException, ("failure_point_str",)
+ )
+ assert not py_err_set_after_what
+ lines = what.splitlines()
+ if env.PYPY and len(lines) == 3:
+ n = 3 # Traceback is missing.
+ else:
+ n = 5
+ assert (
+ lines[:n]
+ == [
+ "FlakyException: <MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>",
+ "",
+ "MESSAGE UNAVAILABLE DUE TO EXCEPTION: ValueError: triggered_failure_point_str",
+ "",
+ "At:",
+ ][:n]
+ )
+
+
+def test_cross_module_interleaved_error_already_set():
+ with pytest.raises(RuntimeError) as excinfo:
+ m.test_cross_module_interleaved_error_already_set()
+ assert str(excinfo.value) in (
+ "2nd error.", # Almost all platforms.
+ "RuntimeError: 2nd error.", # Some PyPy builds (seen under macOS).
+ )
+
+
+def test_error_already_set_double_restore():
+ m.test_error_already_set_double_restore(True) # dry_run
+ with pytest.raises(RuntimeError) as excinfo:
+ m.test_error_already_set_double_restore(False)
+ assert str(excinfo.value) == (
+ "Internal error: pybind11::detail::error_fetch_and_normalize::restore()"
+ " called a second time. ORIGINAL ERROR: ValueError: Random error."
+ )
+
+
+def test_pypy_oserror_normalization():
+ # https://github.com/pybind/pybind11/issues/4075
+ what = m.test_pypy_oserror_normalization()
+ assert "this_filename_must_not_exist" in what
diff --git a/3rdparty/pybind11/tests/test_factory_constructors.cpp b/3rdparty/pybind11/tests/test_factory_constructors.cpp
index f42d1f29..a387cd2e 100644
--- a/3rdparty/pybind11/tests/test_factory_constructors.cpp
+++ b/3rdparty/pybind11/tests/test_factory_constructors.cpp
@@ -8,35 +8,45 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
#include "constructor_stats.h"
+#include "pybind11_tests.h"
+
#include <cmath>
#include <new>
+#include <utility>
// 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); }
+ explicit TestFactory1(int v) : value(std::to_string(v)) { print_created(this, value); }
+ explicit TestFactory1(std::string v) : value(std::move(v)) { print_created(this, value); }
+
+public:
+ std::string 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); }
+ explicit TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); }
+ explicit 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; }
+ TestFactory2(TestFactory2 &&m) noexcept : value{std::move(m.value)} {
+ print_move_created(this);
+ }
+ TestFactory2 &operator=(TestFactory2 &&m) noexcept {
+ value = std::move(m.value);
+ print_move_assigned(this);
+ return *this;
+ }
std::string value;
~TestFactory2() { print_destroyed(this); }
};
@@ -45,11 +55,18 @@ 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); }
+ explicit 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; }
+ explicit TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); }
+ TestFactory3(TestFactory3 &&m) noexcept : value{std::move(m.value)} {
+ print_move_created(this);
+ }
+ TestFactory3 &operator=(TestFactory3 &&m) noexcept {
+ value = std::move(m.value);
+ print_move_assigned(this);
+ return *this;
+ }
std::string value;
virtual ~TestFactory3() { print_destroyed(this); }
};
@@ -57,13 +74,13 @@ public:
class TestFactory4 : public TestFactory3 {
public:
TestFactory4() : TestFactory3() { print_default_created(this); }
- TestFactory4(int v) : TestFactory3(v) { print_created(this, v); }
+ explicit TestFactory4(int v) : TestFactory3(v) { print_created(this, v); }
~TestFactory4() override { print_destroyed(this); }
};
// Another class for an invalid downcast test
class TestFactory5 : public TestFactory3 {
public:
- TestFactory5(int i) : TestFactory3(i) { print_created(this, i); }
+ explicit TestFactory5(int i) : TestFactory3(i) { print_created(this, i); }
~TestFactory5() override { print_destroyed(this); }
};
@@ -71,23 +88,45 @@ 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; }
+ explicit TestFactory6(int i) : value{i} { print_created(this, i); }
+ TestFactory6(TestFactory6 &&f) noexcept {
+ print_move_created(this);
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
+ value = f.value;
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
+ alias = f.alias;
+ }
+ TestFactory6(const TestFactory6 &f) {
+ print_copy_created(this);
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
+ value = f.value;
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
+ alias = f.alias;
+ }
virtual ~TestFactory6() { print_destroyed(this); }
virtual int get() { return value; }
- bool has_alias() { return alias; }
+ bool has_alias() const { 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); }
+ explicit PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) {
+ alias = true;
+ print_created(this, "move", value);
+ }
+ explicit PyTF6(int i) : TestFactory6(i) {
+ alias = true;
+ print_created(this, i);
+ }
+ PyTF6(PyTF6 &&f) noexcept : 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); }
+ explicit PyTF6(std::string s) : TestFactory6((int) s.size()) {
+ alias = true;
+ print_created(this, s);
+ }
~PyTF6() override { print_destroyed(this); }
int get() override { PYBIND11_OVERRIDE(int, TestFactory6, get, /*no args*/); }
};
@@ -96,56 +135,80 @@ 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; }
+ explicit TestFactory7(int i) : value{i} { print_created(this, i); }
+ TestFactory7(TestFactory7 &&f) noexcept {
+ print_move_created(this);
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
+ value = f.value;
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
+ alias = f.alias;
+ }
+ TestFactory7(const TestFactory7 &f) {
+ print_copy_created(this);
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
+ value = f.value;
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
+ alias = f.alias;
+ }
virtual ~TestFactory7() { print_destroyed(this); }
virtual int get() { return value; }
- bool has_alias() { return alias; }
+ bool has_alias() const { 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); }
+ explicit PyTF7(int i) : TestFactory7(i) {
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
+ alias = true;
+ print_created(this, i);
+ }
+ PyTF7(PyTF7 &&f) noexcept : TestFactory7(std::move(f)) { print_move_created(this); }
PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); }
~PyTF7() override { print_destroyed(this); }
int get() override { PYBIND11_OVERRIDE(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)); }
+ 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); }
+ static TestFactory1 *construct1_string(std::string a) {
+ return new TestFactory1(std::move(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)); }
+ 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); }
+ static TestFactory2 construct2(std::string a) { return TestFactory2(std::move(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)); }
+ 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<>()); \
+#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);
@@ -168,40 +231,50 @@ TEST_SUBMODULE(factory_constructors, m) {
.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)
- ;
+ .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([](unique_ptr_tag, std::string v) {
+ return TestFactoryHelper::construct2(std::move(v));
+ }))
.def(py::init([](move_tag) { return TestFactoryHelper::construct2(); }))
- .def_readwrite("value", &TestFactory2::value)
- ;
+ .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);};
+ 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")
+ py::class_<TestFactory3, std::shared_ptr<TestFactory3>> pyTestFactory3(m, "TestFactory3");
+ pyTestFactory3
.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
-
+ .def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); }));
+ ignoreOldStyleInitWarnings([&pyTestFactory3]() {
+ pyTestFactory3.def("__init__", [](TestFactory3 &self, std::string v) {
+ new (&self) TestFactory3(std::move(v));
+ }); // placement-new ctor
+ });
+ pyTestFactory3
// 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); }))
+ .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(py::init([](null_unique_ptr_tag) { return std::unique_ptr<TestFactory3>(); }))
.def(py::init([](null_shared_ptr_tag) { return std::shared_ptr<TestFactory3>(); }))
- .def_readwrite("value", &TestFactory3::value)
- ;
+ .def_readwrite("value", &TestFactory3::value);
// test_init_factory_casting
py::class_<TestFactory4, TestFactory3, std::shared_ptr<TestFactory4>>(m, "TestFactory4")
@@ -216,58 +289,60 @@ TEST_SUBMODULE(factory_constructors, m) {
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, std::string s) { return PyTF6(std::move(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(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)
- ;
+ .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([](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, const std::string &s) { return TestFactory7((int) s.size()); },
+ [](mixed_tag, const 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
+ [](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)
- ;
+ .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) { }
+ explicit 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));
@@ -283,50 +358,62 @@ TEST_SUBMODULE(factory_constructors, m) {
py::class_<NoPlacementNew>(m, "NoPlacementNew")
.def(py::init<int>())
.def(py::init([]() { return new NoPlacementNew(100); }))
- .def_readwrite("i", &NoPlacementNew::i)
- ;
-
+ .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)); }
+ explicit NoisyAlloc(int i) { py::print(py::str("NoisyAlloc(int {})").format(i)); }
+ explicit 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 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):
+ py::class_<NoisyAlloc> pyNoisyAlloc(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:
+ ignoreOldStyleInitWarnings([&pyNoisyAlloc]() {
+ pyNoisyAlloc.def("__init__", [](NoisyAlloc *a, int i) {
+ new (a) NoisyAlloc(i);
+ }); // Regular constructor, runs first, requires preallocation
+ });
+
+ pyNoisyAlloc.def(py::init([](double d) { return new NoisyAlloc(d); }));
+
+ // The two-argument version: first the factory pointer overload.
+ pyNoisyAlloc.def(py::init([](int i, int) { return new NoisyAlloc(i); }));
+ // Return-by-value:
+ pyNoisyAlloc.def(py::init([](double d, int) { return NoisyAlloc(d); }));
+ // Old-style placement new init; requires preallocation
+ ignoreOldStyleInitWarnings([&pyNoisyAlloc]() {
+ pyNoisyAlloc.def("__init__",
+ [](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); });
+ });
+ // Requires deallocation of previous overload preallocated value:
+ pyNoisyAlloc.def(py::init([](int i, double) { return new NoisyAlloc(i); }));
+ // Regular again: requires yet another preallocation
+ ignoreOldStyleInitWarnings([&pyNoisyAlloc]() {
+ pyNoisyAlloc.def(
+ "__init__", [](NoisyAlloc &a, int i, const 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 {};
diff --git a/3rdparty/pybind11/tests/test_factory_constructors.py b/3rdparty/pybind11/tests/test_factory_constructors.py
index ffcce6fd..120a587c 100644
--- a/3rdparty/pybind11/tests/test_factory_constructors.py
+++ b/3rdparty/pybind11/tests/test_factory_constructors.py
@@ -1,12 +1,10 @@
-# -*- coding: utf-8 -*-
-import pytest
import re
-import env # noqa: F401
+import pytest
+from pybind11_tests import ConstructorStats
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():
@@ -82,7 +80,7 @@ def test_init_factory_signature(msg):
4. m.factory_constructors.TestFactory1(arg0: handle, arg1: int, arg2: handle)
Invoked with: 'invalid', 'constructor', 'arguments'
- """ # noqa: E501 line too long
+ """
)
assert (
@@ -465,12 +463,10 @@ def test_reallocation_g(capture, msg):
)
-@pytest.mark.skipif("env.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."""
+ """Tests invocation of the pybind-registered base class with an invalid `self` argument."""
- class NotPybindDerived(object):
+ class NotPybindDerived:
pass
# Attempts to initialize with an invalid type passed as `self`:
@@ -486,7 +482,9 @@ def test_invalid_self():
# Same as above, but for a class with an alias:
class BrokenTF6(m.TestFactory6):
def __init__(self, bad):
- if bad == 1:
+ if bad == 0:
+ m.TestFactory6.__init__()
+ elif bad == 1:
a = m.TestFactory2(tag.pointer, 1)
m.TestFactory6.__init__(a, tag.base, 1)
elif bad == 2:
@@ -506,13 +504,13 @@ def test_invalid_self():
BrokenTF1(arg)
assert (
str(excinfo.value)
- == "__init__(self, ...) called with invalid `self` argument"
+ == "__init__(self, ...) called with invalid or missing `self` argument"
)
- for arg in (1, 2, 3, 4):
+ for arg in (0, 1, 2, 3, 4):
with pytest.raises(TypeError) as excinfo:
BrokenTF6(arg)
assert (
str(excinfo.value)
- == "__init__(self, ...) called with invalid `self` argument"
+ == "__init__(self, ...) called with invalid or missing `self` argument"
)
diff --git a/3rdparty/pybind11/tests/test_gil_scoped.cpp b/3rdparty/pybind11/tests/test_gil_scoped.cpp
index b6a45a5f..97efdc16 100644
--- a/3rdparty/pybind11/tests/test_gil_scoped.cpp
+++ b/3rdparty/pybind11/tests/test_gil_scoped.cpp
@@ -7,48 +7,41 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
#include <pybind11/functional.h>
+#include "pybind11_tests.h"
-class VirtClass {
+class VirtClass {
public:
virtual ~VirtClass() = default;
VirtClass() = default;
- VirtClass(const VirtClass&) = delete;
+ VirtClass(const VirtClass &) = delete;
virtual void virtual_func() {}
virtual void pure_virtual_func() = 0;
};
class PyVirtClass : public VirtClass {
- void virtual_func() override {
- PYBIND11_OVERRIDE(void, VirtClass, virtual_func,);
- }
+ void virtual_func() override { PYBIND11_OVERRIDE(void, VirtClass, virtual_func, ); }
void pure_virtual_func() override {
- PYBIND11_OVERRIDE_PURE(void, VirtClass, pure_virtual_func,);
+ PYBIND11_OVERRIDE_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();
- });
+ 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
index 0a1d6274..52374b0c 100644
--- a/3rdparty/pybind11/tests/test_gil_scoped.py
+++ b/3rdparty/pybind11/tests/test_gil_scoped.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
import multiprocessing
import threading
diff --git a/3rdparty/pybind11/tests/test_iostream.cpp b/3rdparty/pybind11/tests/test_iostream.cpp
index e9161505..421eaa2d 100644
--- a/3rdparty/pybind11/tests/test_iostream.cpp
+++ b/3rdparty/pybind11/tests/test_iostream.cpp
@@ -7,67 +7,120 @@
BSD-style license that can be found in the LICENSE file.
*/
-
#include <pybind11/iostream.h>
+
#include "pybind11_tests.h"
-#include <iostream>
+#include <atomic>
+#include <iostream>
+#include <mutex>
+#include <string>
+#include <thread>
-void noisy_function(std::string msg, bool flush) {
+void noisy_function(const std::string &msg, bool flush) {
std::cout << msg;
- if (flush)
+ if (flush) {
std::cout << std::flush;
+ }
}
-void noisy_funct_dual(std::string msg, std::string emsg) {
+void noisy_funct_dual(const std::string &msg, const std::string &emsg) {
std::cout << msg;
std::cerr << emsg;
}
+// object to manage C++ thread
+// simply repeatedly write to std::cerr until stopped
+// redirect is called at some point to test the safety of scoped_estream_redirect
+struct TestThread {
+ TestThread() : stop_{false} {
+ auto thread_f = [this] {
+ static std::mutex cout_mutex;
+ while (!stop_) {
+ {
+ // #HelpAppreciated: Work on iostream.h thread safety.
+ // Without this lock, the clang ThreadSanitizer (tsan) reliably reports a
+ // data race, and this test is predictably flakey on Windows.
+ // For more background see the discussion under
+ // https://github.com/pybind/pybind11/pull/2982 and
+ // https://github.com/pybind/pybind11/pull/2995.
+ const std::lock_guard<std::mutex> lock(cout_mutex);
+ std::cout << "x" << std::flush;
+ }
+ std::this_thread::sleep_for(std::chrono::microseconds(50));
+ }
+ };
+ t_ = new std::thread(std::move(thread_f));
+ }
+
+ ~TestThread() { delete t_; }
+
+ void stop() { stop_ = true; }
+
+ void join() const {
+ py::gil_scoped_release gil_lock;
+ t_->join();
+ }
+
+ void sleep() {
+ py::gil_scoped_release gil_lock;
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ }
+
+ std::thread *t_{nullptr};
+ std::atomic<bool> stop_;
+};
+
TEST_SUBMODULE(iostream, m) {
add_ostream_redirect(m);
// test_evals
- m.def("captured_output_default", [](std::string msg) {
+ m.def("captured_output_default", [](const std::string &msg) {
py::scoped_ostream_redirect redir;
std::cout << msg << std::flush;
});
- m.def("captured_output", [](std::string msg) {
+ m.def("captured_output", [](const 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("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) {
+ m.def("captured_err", [](const 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("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_output", [](const std::string &msg) { std::cout << msg << std::flush; });
- m.def("raw_err", [](std::string msg) {
- std::cerr << msg << std::flush;
- });
+ m.def("raw_err", [](const std::string &msg) { std::cerr << msg << std::flush; });
- m.def("captured_dual", [](std::string msg, std::string emsg) {
+ m.def("captured_dual", [](const std::string &msg, const 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;
});
+
+ py::class_<TestThread>(m, "TestThread")
+ .def(py::init<>())
+ .def("stop", &TestThread::stop)
+ .def("join", &TestThread::join)
+ .def("sleep", &TestThread::sleep);
}
diff --git a/3rdparty/pybind11/tests/test_iostream.py b/3rdparty/pybind11/tests/test_iostream.py
index 506db42e..5bbdf695 100644
--- a/3rdparty/pybind11/tests/test_iostream.py
+++ b/3rdparty/pybind11/tests/test_iostream.py
@@ -1,43 +1,7 @@
-# -*- coding: utf-8 -*-
+from contextlib import redirect_stderr, redirect_stdout
+from io import StringIO
+
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):
@@ -69,6 +33,96 @@ def test_captured_large_string(capsys):
assert stderr == ""
+def test_captured_utf8_2byte_offset0(capsys):
+ msg = "\u07FF"
+ msg = "" + msg * (1024 // len(msg) + 1)
+
+ m.captured_output_default(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == msg
+ assert stderr == ""
+
+
+def test_captured_utf8_2byte_offset1(capsys):
+ msg = "\u07FF"
+ msg = "1" + msg * (1024 // len(msg) + 1)
+
+ m.captured_output_default(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == msg
+ assert stderr == ""
+
+
+def test_captured_utf8_3byte_offset0(capsys):
+ msg = "\uFFFF"
+ msg = "" + msg * (1024 // len(msg) + 1)
+
+ m.captured_output_default(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == msg
+ assert stderr == ""
+
+
+def test_captured_utf8_3byte_offset1(capsys):
+ msg = "\uFFFF"
+ msg = "1" + msg * (1024 // len(msg) + 1)
+
+ m.captured_output_default(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == msg
+ assert stderr == ""
+
+
+def test_captured_utf8_3byte_offset2(capsys):
+ msg = "\uFFFF"
+ msg = "12" + msg * (1024 // len(msg) + 1)
+
+ m.captured_output_default(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == msg
+ assert stderr == ""
+
+
+def test_captured_utf8_4byte_offset0(capsys):
+ msg = "\U0010FFFF"
+ msg = "" + msg * (1024 // len(msg) + 1)
+
+ m.captured_output_default(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == msg
+ assert stderr == ""
+
+
+def test_captured_utf8_4byte_offset1(capsys):
+ msg = "\U0010FFFF"
+ msg = "1" + msg * (1024 // len(msg) + 1)
+
+ m.captured_output_default(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == msg
+ assert stderr == ""
+
+
+def test_captured_utf8_4byte_offset2(capsys):
+ msg = "\U0010FFFF"
+ msg = "12" + msg * (1024 // len(msg) + 1)
+
+ m.captured_output_default(msg)
+ stdout, stderr = capsys.readouterr()
+ assert stdout == msg
+ assert stderr == ""
+
+
+def test_captured_utf8_4byte_offset3(capsys):
+ msg = "\U0010FFFF"
+ msg = "123" + 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)
@@ -216,3 +270,26 @@ def test_redirect_both(capfd):
assert stderr == ""
assert stream.getvalue() == msg
assert stream2.getvalue() == msg2
+
+
+def test_threading():
+ with m.ostream_redirect(stdout=True, stderr=False):
+ # start some threads
+ threads = []
+
+ # start some threads
+ for _j in range(20):
+ threads.append(m.TestThread())
+
+ # give the threads some time to fail
+ threads[0].sleep()
+
+ # stop all the threads
+ for t in threads:
+ t.stop()
+
+ for t in threads:
+ t.join()
+
+ # if a thread segfaults, we don't get here
+ assert True
diff --git a/3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp b/3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp
index 627a7969..2f3cabaf 100644
--- a/3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp
+++ b/3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp
@@ -7,136 +7,276 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
-#include "constructor_stats.h"
#include <pybind11/stl.h>
+#include "constructor_stats.h"
+#include "pybind11_tests.h"
+
+#include <utility>
+
TEST_SUBMODULE(kwargs_and_defaults, m) {
- auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); };
+ 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!"));
+ 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_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);
+ 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);
+#ifdef PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wreturn-std-move"
+#endif
+ return args;
+#ifdef PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING
+# pragma clang diagnostic pop
+#endif
});
- m.def("args_kwargs_function", [](py::args args, py::kwargs kwargs) {
+ m.def("args_kwargs_function", [](const py::args &args, const 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) {
+ m.def("mixed_plus_args",
+ [](int i, double j, const py::args &args) { return py::make_tuple(i, j, args); });
+ m.def("mixed_plus_kwargs",
+ [](int i, double j, const py::kwargs &kwargs) { return py::make_tuple(i, j, kwargs); });
+ auto mixed_plus_both = [](int i, double j, const py::args &args, const 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("mixed_plus_args_kwargs_defaults",
+ mixed_plus_both,
+ py::arg("i") = 1,
+ py::arg("j") = 3.14159);
+
+ m.def(
+ "args_kwonly",
+ [](int i, double j, const py::args &args, int z) { return py::make_tuple(i, j, args, z); },
+ "i"_a,
+ "j"_a,
+ "z"_a);
+ m.def(
+ "args_kwonly_kwargs",
+ [](int i, double j, const py::args &args, int z, const py::kwargs &kwargs) {
+ return py::make_tuple(i, j, args, z, kwargs);
+ },
+ "i"_a,
+ "j"_a,
+ py::kw_only{},
+ "z"_a);
+ m.def(
+ "args_kwonly_kwargs_defaults",
+ [](int i, double j, const py::args &args, int z, const py::kwargs &kwargs) {
+ return py::make_tuple(i, j, args, z, kwargs);
+ },
+ "i"_a = 1,
+ "j"_a = 3.14159,
+ "z"_a = 42);
+ m.def(
+ "args_kwonly_full_monty",
+ [](int h, int i, double j, const py::args &args, int z, const py::kwargs &kwargs) {
+ return py::make_tuple(h, i, j, args, z, kwargs);
+ },
+ py::arg() = 1,
+ py::arg() = 2,
+ py::pos_only{},
+ "j"_a = 3.14159,
+ "z"_a = 42);
+
+// 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", [](const 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++)
+ 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<py::ssize_t>(i)));
+ }
return t;
});
- m.def("mixed_args_refcount", [](py::object o, py::args a) {
+ m.def("mixed_args_refcount", [](const 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++)
+ 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<py::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) {});
+ // 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_keyword_only_args
- m.def("kw_only_all", [](int i, int j) { return py::make_tuple(i, j); },
- py::kw_only(), py::arg("i"), py::arg("j"));
- m.def("kw_only_some", [](int i, int j, int k) { return py::make_tuple(i, j, k); },
- py::arg(), py::kw_only(), py::arg("j"), py::arg("k"));
- m.def("kw_only_with_defaults", [](int i, int j, int k, int z) { return py::make_tuple(i, j, k, z); },
- py::arg() = 3, "j"_a = 4, py::kw_only(), "k"_a = 5, "z"_a);
- m.def("kw_only_mixed", [](int i, int j) { return py::make_tuple(i, j); },
- "i"_a, py::kw_only(), "j"_a);
- m.def("kw_only_plus_more", [](int i, int j, int k, py::kwargs kwargs) {
- return py::make_tuple(i, j, k, kwargs); },
- py::arg() /* positional */, py::arg("j") = -1 /* both */, py::kw_only(), py::arg("k") /* kw-only */);
+ m.def(
+ "kw_only_all",
+ [](int i, int j) { return py::make_tuple(i, j); },
+ py::kw_only(),
+ py::arg("i"),
+ py::arg("j"));
+ m.def(
+ "kw_only_some",
+ [](int i, int j, int k) { return py::make_tuple(i, j, k); },
+ py::arg(),
+ py::kw_only(),
+ py::arg("j"),
+ py::arg("k"));
+ m.def(
+ "kw_only_with_defaults",
+ [](int i, int j, int k, int z) { return py::make_tuple(i, j, k, z); },
+ py::arg() = 3,
+ "j"_a = 4,
+ py::kw_only(),
+ "k"_a = 5,
+ "z"_a);
+ m.def(
+ "kw_only_mixed",
+ [](int i, int j) { return py::make_tuple(i, j); },
+ "i"_a,
+ py::kw_only(),
+ "j"_a);
+ m.def(
+ "kw_only_plus_more",
+ [](int i, int j, int k, const py::kwargs &kwargs) {
+ return py::make_tuple(i, j, k, kwargs);
+ },
+ py::arg() /* positional */,
+ py::arg("j") = -1 /* both */,
+ py::kw_only(),
+ py::arg("k") /* kw-only */);
m.def("register_invalid_kw_only", [](py::module_ m) {
- m.def("bad_kw_only", [](int i, int j) { return py::make_tuple(i, j); },
- py::kw_only(), py::arg() /* invalid unnamed argument */, "j"_a);
+ m.def(
+ "bad_kw_only",
+ [](int i, int j) { return py::make_tuple(i, j); },
+ py::kw_only(),
+ py::arg() /* invalid unnamed argument */,
+ "j"_a);
});
// test_positional_only_args
- m.def("pos_only_all", [](int i, int j) { return py::make_tuple(i, j); },
- py::arg("i"), py::arg("j"), py::pos_only());
- m.def("pos_only_mix", [](int i, int j) { return py::make_tuple(i, j); },
- py::arg("i"), py::pos_only(), py::arg("j"));
- m.def("pos_kw_only_mix", [](int i, int j, int k) { return py::make_tuple(i, j, k); },
- py::arg("i"), py::pos_only(), py::arg("j"), py::kw_only(), py::arg("k"));
- m.def("pos_only_def_mix", [](int i, int j, int k) { return py::make_tuple(i, j, k); },
- py::arg("i"), py::arg("j") = 2, py::pos_only(), py::arg("k") = 3);
-
+ m.def(
+ "pos_only_all",
+ [](int i, int j) { return py::make_tuple(i, j); },
+ py::arg("i"),
+ py::arg("j"),
+ py::pos_only());
+ m.def(
+ "pos_only_mix",
+ [](int i, int j) { return py::make_tuple(i, j); },
+ py::arg("i"),
+ py::pos_only(),
+ py::arg("j"));
+ m.def(
+ "pos_kw_only_mix",
+ [](int i, int j, int k) { return py::make_tuple(i, j, k); },
+ py::arg("i"),
+ py::pos_only(),
+ py::arg("j"),
+ py::kw_only(),
+ py::arg("k"));
+ m.def(
+ "pos_only_def_mix",
+ [](int i, int j, int k) { return py::make_tuple(i, j, k); },
+ py::arg("i"),
+ py::arg("j") = 2,
+ py::pos_only(),
+ py::arg("k") = 3);
// These should fail to compile:
+#ifdef PYBIND11_NEVER_DEFINED_EVER
// argument annotations are required when using kw_only
-// m.def("bad_kw_only1", [](int) {}, py::kw_only());
+ m.def(
+ "bad_kw_only1", [](int) {}, py::kw_only());
// can't specify both `py::kw_only` and a `py::args` argument
-// m.def("bad_kw_only2", [](int i, py::args) {}, py::kw_only(), "i"_a);
+ m.def(
+ "bad_kw_only2", [](int i, py::args) {}, py::kw_only(), "i"_a);
+#endif
// test_function_signatures (along with most of the above)
- struct KWClass { void foo(int, float) {} };
+ struct KWClass {
+ void foo(int, float) {}
+ };
py::class_<KWClass>(m, "KWClass")
.def("foo0", &KWClass::foo)
.def("foo1", &KWClass::foo, "x"_a, "y"_a);
// Make sure a class (not an instance) can be used as a default argument.
// The return value doesn't matter, only that the module is importable.
- m.def("class_default_argument", [](py::object a) { return py::repr(a); },
+ m.def(
+ "class_default_argument",
+ [](py::object a) { return py::repr(std::move(a)); },
"a"_a = py::module_::import("decimal").attr("Decimal"));
+
+ // Initial implementation of kw_only was broken when used on a method/constructor before any
+ // other arguments
+ // https://github.com/pybind/pybind11/pull/3402#issuecomment-963341987
+
+ struct first_arg_kw_only {};
+ py::class_<first_arg_kw_only>(m, "first_arg_kw_only")
+ .def(py::init([](int) { return first_arg_kw_only(); }),
+ py::kw_only(), // This being before any args was broken
+ py::arg("i") = 0)
+ .def(
+ "method",
+ [](first_arg_kw_only &, int, int) {},
+ py::kw_only(), // and likewise here
+ py::arg("i") = 1,
+ py::arg("j") = 2)
+ // Closely related: pos_only marker didn't show up properly when it was before any other
+ // arguments (although that is fairly useless in practice).
+ .def(
+ "pos_only",
+ [](first_arg_kw_only &, int, int) {},
+ py::pos_only{},
+ py::arg("i"),
+ py::arg("j"));
}
diff --git a/3rdparty/pybind11/tests/test_kwargs_and_defaults.py b/3rdparty/pybind11/tests/test_kwargs_and_defaults.py
index 12fe705b..ab701788 100644
--- a/3rdparty/pybind11/tests/test_kwargs_and_defaults.py
+++ b/3rdparty/pybind11/tests/test_kwargs_and_defaults.py
@@ -1,8 +1,5 @@
-# -*- coding: utf-8 -*-
import pytest
-import env # noqa: F401
-
from pybind11_tests import kwargs_and_defaults as m
@@ -83,7 +80,7 @@ def test_mixed_args_and_kwargs(msg):
1. (arg0: int, arg1: float, *args) -> tuple
Invoked with: 1
- """ # noqa: E501 line too long
+ """
)
with pytest.raises(TypeError) as excinfo:
assert mpa()
@@ -94,7 +91,7 @@ def test_mixed_args_and_kwargs(msg):
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) == (
@@ -128,7 +125,7 @@ def test_mixed_args_and_kwargs(msg):
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)
@@ -139,9 +136,56 @@ def test_mixed_args_and_kwargs(msg):
1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
Invoked with: 1, 2; kwargs: j=1
- """ # noqa: E501 line too long
+ """
+ )
+
+ # Arguments after a py::args are automatically keyword-only (pybind 2.9+)
+ assert m.args_kwonly(2, 2.5, z=22) == (2, 2.5, (), 22)
+ assert m.args_kwonly(2, 2.5, "a", "b", "c", z=22) == (2, 2.5, ("a", "b", "c"), 22)
+ assert m.args_kwonly(z=22, i=4, j=16) == (4, 16, (), 22)
+
+ with pytest.raises(TypeError) as excinfo:
+ assert m.args_kwonly(2, 2.5, 22) # missing z= keyword
+ assert (
+ msg(excinfo.value)
+ == """
+ args_kwonly(): incompatible function arguments. The following argument types are supported:
+ 1. (i: int, j: float, *args, z: int) -> tuple
+
+ Invoked with: 2, 2.5, 22
+ """
)
+ assert m.args_kwonly_kwargs(i=1, k=4, j=10, z=-1, y=9) == (
+ 1,
+ 10,
+ (),
+ -1,
+ {"k": 4, "y": 9},
+ )
+ assert m.args_kwonly_kwargs(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, z=11, y=12) == (
+ 1,
+ 2,
+ (3, 4, 5, 6, 7, 8, 9, 10),
+ 11,
+ {"y": 12},
+ )
+ assert (
+ m.args_kwonly_kwargs.__doc__
+ == "args_kwonly_kwargs(i: int, j: float, *args, z: int, **kwargs) -> tuple\n"
+ )
+
+ assert (
+ m.args_kwonly_kwargs_defaults.__doc__
+ == "args_kwonly_kwargs_defaults(i: int = 1, j: float = 3.14159, *args, z: int = 42, **kwargs) -> tuple\n" # noqa: E501 line too long
+ )
+ assert m.args_kwonly_kwargs_defaults() == (1, 3.14159, (), 42, {})
+ assert m.args_kwonly_kwargs_defaults(2) == (2, 3.14159, (), 42, {})
+ assert m.args_kwonly_kwargs_defaults(z=-99) == (1, 3.14159, (), -99, {})
+ assert m.args_kwonly_kwargs_defaults(5, 6, 7, 8) == (5, 6, (7, 8), 42, {})
+ assert m.args_kwonly_kwargs_defaults(5, 6, 7, m=8) == (5, 6, (7,), 42, {"m": 8})
+ assert m.args_kwonly_kwargs_defaults(5, 6, 7, m=8, z=9) == (5, 6, (7,), 9, {"m": 8})
+
def test_keyword_only_args(msg):
assert m.kw_only_all(i=1, j=2) == (1, 2)
@@ -179,10 +223,23 @@ def test_keyword_only_args(msg):
assert (
msg(excinfo.value)
== """
- arg(): cannot specify an unnamed argument after an kw_only() annotation
+ arg(): cannot specify an unnamed argument after a kw_only() annotation or args() argument
"""
)
+ # https://github.com/pybind/pybind11/pull/3402#issuecomment-963341987
+ x = m.first_arg_kw_only(i=1)
+ x.method()
+ x.method(i=1, j=2)
+ assert (
+ m.first_arg_kw_only.__init__.__doc__
+ == "__init__(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, *, i: int = 0) -> None\n" # noqa: E501 line too long
+ )
+ assert (
+ m.first_arg_kw_only.method.__doc__
+ == "method(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, *, i: int = 1, j: int = 2) -> None\n" # noqa: E501 line too long
+ )
+
def test_positional_only_args(msg):
assert m.pos_only_all(1, 2) == (1, 2)
@@ -223,6 +280,55 @@ def test_positional_only_args(msg):
m.pos_only_def_mix(1, j=4)
assert "incompatible function arguments" in str(excinfo.value)
+ # Mix it with args and kwargs:
+ assert (
+ m.args_kwonly_full_monty.__doc__
+ == "args_kwonly_full_monty(arg0: int = 1, arg1: int = 2, /, j: float = 3.14159, *args, z: int = 42, **kwargs) -> tuple\n" # noqa: E501 line too long
+ )
+ assert m.args_kwonly_full_monty() == (1, 2, 3.14159, (), 42, {})
+ assert m.args_kwonly_full_monty(8) == (8, 2, 3.14159, (), 42, {})
+ assert m.args_kwonly_full_monty(8, 9) == (8, 9, 3.14159, (), 42, {})
+ assert m.args_kwonly_full_monty(8, 9, 10) == (8, 9, 10.0, (), 42, {})
+ assert m.args_kwonly_full_monty(3, 4, 5, 6, 7, m=8, z=9) == (
+ 3,
+ 4,
+ 5.0,
+ (
+ 6,
+ 7,
+ ),
+ 9,
+ {"m": 8},
+ )
+ assert m.args_kwonly_full_monty(3, 4, 5, 6, 7, m=8, z=9) == (
+ 3,
+ 4,
+ 5.0,
+ (
+ 6,
+ 7,
+ ),
+ 9,
+ {"m": 8},
+ )
+ assert m.args_kwonly_full_monty(5, j=7, m=8, z=9) == (5, 2, 7.0, (), 9, {"m": 8})
+ assert m.args_kwonly_full_monty(i=5, j=7, m=8, z=9) == (
+ 1,
+ 2,
+ 7.0,
+ (),
+ 9,
+ {"i": 5, "m": 8},
+ )
+
+ # pos_only at the beginning of the argument list was "broken" in how it was displayed (though
+ # this is fairly useless in practice). Related to:
+ # https://github.com/pybind/pybind11/pull/3402#issuecomment-963341987
+ assert (
+ m.first_arg_kw_only.pos_only.__doc__
+ == "pos_only(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, /, i: int, j: int) -> None\n" # noqa: E501 line too long
+ )
+
def test_signatures():
assert "kw_only_all(*, i: int, j: int) -> tuple\n" == m.kw_only_all.__doc__
@@ -235,7 +341,6 @@ def test_signatures():
)
-@pytest.mark.xfail("env.PYPY and env.PY2", reason="PyPy2 doesn't double count")
def test_args_refcount():
"""Issue/PR #1216 - py::args elements get double-inc_ref()ed when combined with regular
arguments"""
diff --git a/3rdparty/pybind11/tests/test_local_bindings.cpp b/3rdparty/pybind11/tests/test_local_bindings.cpp
index c61e3888..13736774 100644
--- a/3rdparty/pybind11/tests/test_local_bindings.cpp
+++ b/3rdparty/pybind11/tests/test_local_bindings.cpp
@@ -8,11 +8,14 @@
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 "local_bindings.h"
+#include "pybind11_tests.h"
+
#include <numeric>
+#include <utility>
TEST_SUBMODULE(local_bindings, m) {
// test_load_external
@@ -21,9 +24,9 @@ TEST_SUBMODULE(local_bindings, m) {
// 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; })
- ;
+ 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; });
@@ -32,20 +35,21 @@ TEST_SUBMODULE(local_bindings, m) {
// 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; })
- ;
+ .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).
+ // 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");
}
- else throw std::runtime_error("test_class not enabled");
});
// test_stl_bind_local
@@ -75,23 +79,24 @@ TEST_SUBMODULE(local_bindings, m) {
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(); });
+ m.def("local_cpp_types_addr",
+ []() { return (uintptr_t) &py::detail::get_local_internals().registered_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);
- });
+ 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);
+ class Cat : public pets::Pet {
+ public:
+ explicit Cat(std::string name) : Pet(std::move(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>());
+ 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>());
diff --git a/3rdparty/pybind11/tests/test_local_bindings.py b/3rdparty/pybind11/tests/test_local_bindings.py
index d23c4675..654d96d4 100644
--- a/3rdparty/pybind11/tests/test_local_bindings.py
+++ b/3rdparty/pybind11/tests/test_local_bindings.py
@@ -1,8 +1,6 @@
-# -*- coding: utf-8 -*-
import pytest
import env # noqa: F401
-
from pybind11_tests import local_bindings as m
@@ -193,7 +191,7 @@ def test_stl_caster_vs_stl_bind(msg):
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
+ cm.load_vector_via_binding(v2)
assert (
msg(excinfo.value)
== """
@@ -201,7 +199,7 @@ def test_stl_caster_vs_stl_bind(msg):
1. (arg0: pybind11_cross_module_tests.VectorInt) -> int
Invoked with: [1, 2, 3]
- """ # noqa: E501 line too long
+ """
)
diff --git a/3rdparty/pybind11/tests/test_methods_and_attributes.cpp b/3rdparty/pybind11/tests/test_methods_and_attributes.cpp
index 6a2cfb6f..815dd5e9 100644
--- a/3rdparty/pybind11/tests/test_methods_and_attributes.cpp
+++ b/3rdparty/pybind11/tests/test_methods_and_attributes.cpp
@@ -8,8 +8,8 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
#include "constructor_stats.h"
+#include "pybind11_tests.h"
#if !defined(PYBIND11_OVERLOAD_CAST)
template <typename... Args>
@@ -19,55 +19,61 @@ using overload_cast_ = pybind11::detail::overload_cast_impl<Args...>;
class ExampleMandA {
public:
ExampleMandA() { print_default_created(this); }
- ExampleMandA(int value) : value(value) { print_created(this, value); }
+ explicit ExampleMandA(int value) : value(value) { print_created(this, value); }
ExampleMandA(const ExampleMandA &e) : value(e.value) { print_copy_created(this); }
- ExampleMandA(std::string&&) {}
- ExampleMandA(ExampleMandA &&e) : value(e.value) { print_move_created(this); }
+ explicit ExampleMandA(std::string &&) {}
+ ExampleMandA(ExampleMandA &&e) noexcept : value(e.value) { print_move_created(this); }
~ExampleMandA() { print_destroyed(this); }
- std::string toString() {
- return "ExampleMandA[value=" + std::to_string(value) + "]";
- }
+ std::string toString() const { 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 operator=(const ExampleMandA &e) {
+ print_copy_assigned(this);
+ value = e.value;
+ }
+ void operator=(ExampleMandA &&e) noexcept {
+ print_move_assigned(this);
+ value = e.value;
+ }
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
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
-
- void consume_str(std::string&&) {}
-
- 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)"; }
+ 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
+ // NOLINTNEXTLINE(readability-non-const-parameter) Deliberately non-const for testing
+ void add9(int *other) { value += *other; } // passing by pointer
+ void add10(const int *other) { value += *other; } // passing by const pointer
+
+ void consume_str(std::string &&) {}
+
+ ExampleMandA self1() { return *this; } // return by value
+ ExampleMandA &self2() { return *this; } // return by reference
+ const ExampleMandA &self3() const { return *this; } // return by const reference
+ ExampleMandA *self4() { return this; } // return by pointer
+ const ExampleMandA *self5() const { return this; } // return by const pointer
+
+ int internal1() const { return value; } // return by value
+ int &internal2() { return value; } // return by reference
+ const int &internal3() const { 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(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"; }
@@ -109,25 +115,40 @@ UserType TestPropRVP::sv1(1);
UserType TestPropRVP::sv2(1);
// Test None-allowed py::arg argument policy
-class NoneTester { public: int answer = 42; };
+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; }
+int none5(const std::shared_ptr<NoneTester> &obj) { return obj ? obj->answer : -1; }
+
+// Issue #2778: implicit casting from None to object (not pointer)
+class NoneCastTester {
+public:
+ int answer = -1;
+ NoneCastTester() = default;
+ explicit NoneCastTester(int v) : answer(v) {}
+};
struct StrIssue {
int val = -1;
StrIssue() = default;
- StrIssue(int i) : val{i} {}
+ explicit StrIssue(int i) : val{i} {}
};
-// Issues #854, #910: incompatible function args when member function/pointer is in unregistered base class
+// 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 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; }
@@ -148,13 +169,21 @@ struct RefQualified {
int constRefQualified(int other) const & { return value + other; }
};
+// Test rvalue ref param
+struct RValueRefParam {
+ std::size_t func1(std::string &&s) { return s.size(); }
+ std::size_t func2(std::string &&s) const { return s.size(); }
+ std::size_t func3(std::string &&s) & { return s.size(); }
+ std::size_t func4(std::string &&s) const & { return s.size(); }
+};
+
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<std::string&&>())
- .def(py::init<const ExampleMandA&>())
+ .def(py::init<std::string &&>())
+ .def(py::init<const ExampleMandA &>())
.def("add1", &ExampleMandA::add1)
.def("add2", &ExampleMandA::add2)
.def("add3", &ExampleMandA::add3)
@@ -179,16 +208,20 @@ TEST_SUBMODULE(methods_and_attributes, m) {
#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<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_))
+ .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))
@@ -206,16 +239,29 @@ TEST_SUBMODULE(methods_and_attributes, m) {
#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_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);
@@ -228,36 +274,41 @@ TEST_SUBMODULE(methods_and_attributes, m) {
.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_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); });
+ .def_property_static("def_writeonly_static",
+ nullptr,
+ [](const py::object &, int v) { TestProperties::static_value = v; })
+ .def_property_readonly_static(
+ "def_property_readonly_static",
+ [](const py::object &) { return TestProperties::static_get(); })
+ .def_property_static(
+ "def_property_writeonly_static",
+ nullptr,
+ [](const py::object &, int v) { return TestProperties::static_set(v); })
+ .def_property_static(
+ "def_property_static",
+ [](const py::object &) { return TestProperties::static_get(); },
+ [](const py::object &, int v) { TestProperties::static_set(v); })
+ .def_property_static(
+ "static_cls",
+ [](py::object cls) { return cls; },
+ [](const py::object &cls, const 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 static_get1 = [](const py::object &) -> const UserType & { return TestPropRVP::sv1; };
+ auto static_get2 = [](const py::object &) -> const UserType & { return TestPropRVP::sv2; };
+ auto static_set1 = [](const py::object &, int v) { TestPropRVP::sv1.set(v); };
+ auto static_set2 = [](const py::object &, int v) { TestPropRVP::sv2.set(v); };
auto rvp_copy = py::return_value_policy::copy;
// test_property_return_value_policies
@@ -268,85 +319,104 @@ TEST_SUBMODULE(methods_and_attributes, m) {
.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(
+ "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)
+ .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); });
+ .def_property_readonly_static("static_rvalue",
+ [](const py::object &) { return UserType(1); });
// test_metaclass_override
- struct MetaclassOverride { };
+ struct MetaclassOverride {};
py::class_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type))
- .def_property_readonly_static("readonly", [](py::object) { return 1; });
+ .def_property_readonly_static("readonly", [](const py::object &) { return 1; });
// test_overload_ordering
- m.def("overload_order", [](std::string) { return 1; });
- m.def("overload_order", [](std::string) { return 2; });
+ m.def("overload_order", [](const std::string &) { return 1; });
+ m.def("overload_order", [](const std::string &) { return 2; });
m.def("overload_order", [](int) { return 3; });
- m.def("overload_order", [](int) { return 4; }, py::prepend{});
+ m.def(
+ "overload_order", [](int) { return 4; }, py::prepend{});
#if !defined(PYPY_VERSION)
// test_dynamic_attributes
class DynamicClass {
public:
DynamicClass() { print_default_created(this); }
- DynamicClass(const DynamicClass&) = delete;
+ DynamicClass(const DynamicClass &) = delete;
~DynamicClass() { print_destroyed(this); }
};
- py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr())
- .def(py::init());
+ py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr()).def(py::init());
- class CppDerivedDynamicClass : public DynamicClass { };
- py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass")
- .def(py::init());
+ class CppDerivedDynamicClass : public DynamicClass {};
+ py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass").def(py::init());
#endif
// test_bad_arg_default
// Issue/PR #648: bad arg default debugging output
-#if !defined(NDEBUG)
- m.attr("debug_enabled") = true;
+#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
+ m.attr("detailed_error_messages_enabled") = true;
#else
- m.attr("debug_enabled") = false;
+ m.attr("detailed_error_messages_enabled") = false;
#endif
- m.def("bad_arg_def_named", []{
+ 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(
+ "should_fail",
+ [](int, UnregisteredType) {},
+ py::arg(),
+ py::arg("a") = UnregisteredType());
});
- m.def("bad_arg_def_unnamed", []{
+ m.def("bad_arg_def_unnamed", [] {
auto m = py::module_::import("pybind11_tests");
- m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType());
+ m.def(
+ "should_fail",
+ [](int, UnregisteredType) {},
+ py::arg(),
+ py::arg() = UnregisteredType());
});
+ // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
+
// 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));
+ 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_none2", &none2, py::arg{}.none(true));
m.def("ok_none3", &none3);
- m.def("ok_none4", &none4, py::arg().none(true));
+ m.def("ok_none4", &none4, py::arg{}.none(true));
m.def("ok_none5", &none5);
- m.def("no_none_kwarg", &none2, py::arg("a").none(false));
- m.def("no_none_kwarg_kw_only", &none2, py::kw_only(), py::arg("a").none(false));
+ m.def("no_none_kwarg", &none2, "a"_a.none(false));
+ m.def("no_none_kwarg_kw_only", &none2, py::kw_only(), "a"_a.none(false));
+
+ // test_casts_none
+ // Issue #2778: implicit casting from None to object (not pointer)
+ py::class_<NoneCastTester>(m, "NoneCastTester")
+ .def(py::init<>())
+ .def(py::init<int>())
+ .def(py::init([](py::none const &) { return NoneCastTester{}; }));
+ py::implicitly_convertible<py::none, NoneCastTester>();
+ m.def("ok_obj_or_none", [](NoneCastTester const &foo) { return foo.answer; });
// 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) + "]"; }
- );
+ .def("__str__",
+ [](const StrIssue &si) { return "StrIssue[" + std::to_string(si.val) + "]"; });
// test_unregistered_base_implementations
//
@@ -360,16 +430,17 @@ TEST_SUBMODULE(methods_and_attributes, m) {
.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
+ // Uncommenting the next line should trigger a static_assert:
+ // .def_readwrite("fails", &UserType::value)
+ // Uncommenting the next line should trigger a static_assert:
+ // .def_readonly("fails", &UserType::value)
.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)
- ;
+ .def("sum", &RegisteredDerived::sum);
- using Adapted = decltype(py::method_adaptor<RegisteredDerived>(&RegisteredDerived::do_nothing));
+ using Adapted
+ = decltype(py::method_adaptor<RegisteredDerived>(&RegisteredDerived::do_nothing));
static_assert(std::is_same<Adapted, void (RegisteredDerived::*)() const>::value, "");
// test_methods_and_attributes
@@ -378,4 +449,11 @@ TEST_SUBMODULE(methods_and_attributes, m) {
.def_readonly("value", &RefQualified::value)
.def("refQualified", &RefQualified::refQualified)
.def("constRefQualified", &RefQualified::constRefQualified);
+
+ py::class_<RValueRefParam>(m, "RValueRefParam")
+ .def(py::init<>())
+ .def("func1", &RValueRefParam::func1)
+ .def("func2", &RValueRefParam::func2)
+ .def("func3", &RValueRefParam::func3)
+ .def("func4", &RValueRefParam::func4);
}
diff --git a/3rdparty/pybind11/tests/test_methods_and_attributes.py b/3rdparty/pybind11/tests/test_methods_and_attributes.py
index 2aaf9331..0a2ae123 100644
--- a/3rdparty/pybind11/tests/test_methods_and_attributes.py
+++ b/3rdparty/pybind11/tests/test_methods_and_attributes.py
@@ -1,10 +1,20 @@
-# -*- coding: utf-8 -*-
+import sys
+
import pytest
import env # noqa: F401
-
-from pybind11_tests import methods_and_attributes as m
from pybind11_tests import ConstructorStats
+from pybind11_tests import methods_and_attributes as m
+
+NO_GETTER_MSG = (
+ "unreadable attribute" if sys.version_info < (3, 11) else "object has no getter"
+)
+NO_SETTER_MSG = (
+ "can't set attribute" if sys.version_info < (3, 11) else "object has no setter"
+)
+NO_DELETER_MSG = (
+ "can't delete attribute" if sys.version_info < (3, 11) else "object has no deleter"
+)
def test_methods_and_attributes():
@@ -103,33 +113,33 @@ def test_properties():
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)
+ dummy = instance.def_property_writeonly # unused var
+ assert NO_GETTER_MSG 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)
+ assert NO_GETTER_MSG in str(excinfo.value)
with pytest.raises(AttributeError) as excinfo:
instance.def_property_impossible = 5
- assert "can't set attribute" in str(excinfo.value)
+ assert NO_SETTER_MSG 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)
+ assert NO_SETTER_MSG 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)
+ dummy = m.TestProperties.def_writeonly_static # unused var
+ assert NO_GETTER_MSG in str(excinfo.value)
m.TestProperties.def_writeonly_static = 3
assert m.TestProperties.def_readonly_static == 3
@@ -137,14 +147,14 @@ def test_static_properties():
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)
+ assert NO_SETTER_MSG 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)
+ assert NO_GETTER_MSG in str(excinfo.value)
m.TestProperties.def_property_writeonly_static = 5
assert m.TestProperties.def_property_static == 5
@@ -162,7 +172,7 @@ def test_static_properties():
with pytest.raises(AttributeError) as excinfo:
dummy = instance.def_property_writeonly_static # noqa: F841 unused var
- assert "unreadable attribute" in str(excinfo.value)
+ assert NO_GETTER_MSG in str(excinfo.value)
instance.def_property_writeonly_static = 4
assert instance.def_property_static == 4
@@ -182,7 +192,7 @@ def test_static_properties():
properties_override = m.TestPropertiesOverride()
with pytest.raises(AttributeError) as excinfo:
del properties_override.def_readonly
- assert "can't delete attribute" in str(excinfo.value)
+ assert NO_DELETER_MSG in str(excinfo.value)
def test_static_cls():
@@ -218,15 +228,15 @@ def test_metaclass_override():
def test_no_mixed_overloads():
- from pybind11_tests import debug_enabled
+ from pybind11_tests import detailed_error_messages_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
+ "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more details"
+ if not detailed_error_messages_enabled
else "error while attempting to bind static method ExampleMandA.overload_mixed1"
"(arg0: float) -> str"
)
@@ -236,8 +246,8 @@ def test_no_mixed_overloads():
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
+ "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more details"
+ if not detailed_error_messages_enabled
else "error while attempting to bind instance method ExampleMandA.overload_mixed2"
"(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)"
" -> str"
@@ -346,16 +356,16 @@ def test_cyclic_gc():
def test_bad_arg_default(msg):
- from pybind11_tests import debug_enabled
+ from pybind11_tests import detailed_error_messages_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
+ if detailed_error_messages_enabled
else "arg(): could not convert default argument into a Python object (type not registered "
- "yet?). Compile in debug mode for more information."
+ "yet?). #define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more information."
)
with pytest.raises(RuntimeError) as excinfo:
@@ -363,9 +373,9 @@ def test_bad_arg_default(msg):
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
+ if detailed_error_messages_enabled
else "arg(): could not convert default argument into a Python object (type not registered "
- "yet?). Compile in debug mode for more information."
+ "yet?). #define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more information."
)
@@ -431,6 +441,17 @@ def test_accepts_none(msg):
assert "incompatible function arguments" in str(excinfo.value)
+def test_casts_none():
+ """#2778: implicit casting from None to object (not pointer)"""
+ a = m.NoneCastTester()
+ assert m.ok_obj_or_none(a) == -1
+ a = m.NoneCastTester(4)
+ assert m.ok_obj_or_none(a) == 4
+ a = m.NoneCastTester(None)
+ assert m.ok_obj_or_none(a) == -1
+ assert m.ok_obj_or_none(None) == -1
+
+
def test_str_issue(msg):
"""#283: __str__ called on uninitialized instance when constructor arguments invalid"""
@@ -484,24 +505,23 @@ def test_overload_ordering():
assert m.overload_order("string") == 1
assert m.overload_order(0) == 4
- # Different for Python 2 vs. 3
- uni_name = type(u"").__name__
-
assert "1. overload_order(arg0: int) -> int" in m.overload_order.__doc__
- assert (
- "2. overload_order(arg0: {}) -> int".format(uni_name)
- in m.overload_order.__doc__
- )
- assert (
- "3. overload_order(arg0: {}) -> int".format(uni_name)
- in m.overload_order.__doc__
- )
+ assert "2. overload_order(arg0: str) -> int" in m.overload_order.__doc__
+ assert "3. overload_order(arg0: str) -> int" in m.overload_order.__doc__
assert "4. overload_order(arg0: int) -> int" in m.overload_order.__doc__
with pytest.raises(TypeError) as err:
m.overload_order(1.1)
assert "1. (arg0: int) -> int" in str(err.value)
- assert "2. (arg0: {}) -> int".format(uni_name) in str(err.value)
- assert "3. (arg0: {}) -> int".format(uni_name) in str(err.value)
+ assert "2. (arg0: str) -> int" in str(err.value)
+ assert "3. (arg0: str) -> int" in str(err.value)
assert "4. (arg0: int) -> int" in str(err.value)
+
+
+def test_rvalue_ref_param():
+ r = m.RValueRefParam()
+ assert r.func1("123") == 3
+ assert r.func2("1234") == 4
+ assert r.func3("12345") == 5
+ assert r.func4("123456") == 6
diff --git a/3rdparty/pybind11/tests/test_modules.cpp b/3rdparty/pybind11/tests/test_modules.cpp
index 67387e80..18a7ec74 100644
--- a/3rdparty/pybind11/tests/test_modules.cpp
+++ b/3rdparty/pybind11/tests/test_modules.cpp
@@ -8,8 +8,8 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
#include "constructor_stats.h"
+#include "pybind11_tests.h"
TEST_SUBMODULE(modules, m) {
// test_nested_modules
@@ -20,24 +20,32 @@ TEST_SUBMODULE(modules, m) {
// test_reference_internal
class A {
public:
- A(int v) : v(v) { print_created(this, v); }
+ explicit 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) + "]"; }
+ A(const A &) { print_copy_created(this); }
+ A &operator=(const A &copy) {
+ print_copy_assigned(this);
+ v = copy.v;
+ return *this;
+ }
+ std::string toString() const { return "A[" + std::to_string(v) + "]"; }
+
private:
int v;
};
- py::class_<A>(m_sub, "A")
- .def(py::init<int>())
- .def("__repr__", &A::toString);
+ 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; }
+ 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; }
@@ -46,9 +54,16 @@ TEST_SUBMODULE(modules, m) {
};
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("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);
// This is intentionally "py::module" to verify it still can be used in place of "py::module_"
@@ -57,13 +72,14 @@ TEST_SUBMODULE(modules, m) {
// test_duplicate_registration
// Registering two things with the same name
m.def("duplicate_registration", []() {
- class Dupe1 { };
- class Dupe2 { };
- class Dupe3 { };
- class DupeException { };
+ class Dupe1 {};
+ class Dupe2 {};
+ class Dupe3 {};
+ class DupeException {};
// Go ahead and leak, until we have a non-leaking py::module_ constructor
- auto dm = py::module_::create_extension_module("dummy", nullptr, new py::module_::module_def);
+ auto dm
+ = py::module_::create_extension_module("dummy", nullptr, new py::module_::module_def);
auto failures = py::list();
py::class_<Dupe1>(dm, "Dupe1");
@@ -74,28 +90,36 @@ TEST_SUBMODULE(modules, m) {
try {
py::class_<Dupe1>(dm, "Dupe1");
failures.append("Dupe1 class");
- } catch (std::runtime_error &) {}
+ } catch (std::runtime_error &) {
+ }
try {
dm.def("Dupe1", []() { return Dupe1(); });
failures.append("Dupe1 function");
- } catch (std::runtime_error &) {}
+ } catch (std::runtime_error &) {
+ }
try {
py::class_<Dupe3>(dm, "dupe1_factory");
failures.append("dupe1_factory");
- } catch (std::runtime_error &) {}
+ } catch (std::runtime_error &) {
+ }
try {
py::exception<Dupe3>(dm, "Dupe2");
failures.append("Dupe2");
- } catch (std::runtime_error &) {}
+ } catch (std::runtime_error &) {
+ }
try {
dm.def("DupeException", []() { return 30; });
failures.append("DupeException1");
- } catch (std::runtime_error &) {}
+ } catch (std::runtime_error &) {
+ }
try {
py::class_<DupeException>(dm, "DupeException");
failures.append("DupeException2");
- } catch (std::runtime_error &) {}
+ } catch (std::runtime_error &) {
+ }
return failures;
});
+
+ m.def("def_submodule", [](py::module_ m, const char *name) { return m.def_submodule(name); });
}
diff --git a/3rdparty/pybind11/tests/test_modules.py b/3rdparty/pybind11/tests/test_modules.py
index 5630ccf9..e11d68e7 100644
--- a/3rdparty/pybind11/tests/test_modules.py
+++ b/3rdparty/pybind11/tests/test_modules.py
@@ -1,7 +1,9 @@
-# -*- coding: utf-8 -*-
+import pytest
+
+import env
+from pybind11_tests import ConstructorStats
from pybind11_tests import modules as m
from pybind11_tests.modules import subsubmodule as ms
-from pybind11_tests import ConstructorStats
def test_nested_modules():
@@ -54,18 +56,20 @@ def test_reference_internal():
def test_importing():
- from pybind11_tests.modules import OD
from collections import OrderedDict
+ from pybind11_tests.modules import OD
+
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
+ import pybind11_tests
+
assert pybind11_tests.__name__ == "pybind11_tests"
assert pybind11_tests.__doc__ == "pybind11 test module"
assert pydoc.text.docmodule(pybind11_tests)
@@ -75,3 +79,43 @@ def test_duplicate_registration():
"""Registering two things with the same name"""
assert m.duplicate_registration() == []
+
+
+def test_builtin_key_type():
+ """Test that all the keys in the builtin modules have type str.
+
+ Previous versions of pybind11 would add a unicode key in python 2.
+ """
+ if hasattr(__builtins__, "keys"):
+ keys = __builtins__.keys()
+ else: # this is to make pypy happy since builtins is different there.
+ keys = __builtins__.__dict__.keys()
+
+ assert {type(k) for k in keys} == {str}
+
+
+@pytest.mark.xfail("env.PYPY", reason="PyModule_GetName()")
+def test_def_submodule_failures():
+ sm = m.def_submodule(m, b"ScratchSubModuleName") # Using bytes to show it works.
+ assert sm.__name__ == m.__name__ + "." + "ScratchSubModuleName"
+ malformed_utf8 = b"\x80"
+ if env.PYPY:
+ # It is not worth the effort finding a trigger for a failure when running with PyPy.
+ pytest.skip("Sufficiently exercised on platforms other than PyPy.")
+ else:
+ # Meant to trigger PyModule_GetName() failure:
+ sm_name_orig = sm.__name__
+ sm.__name__ = malformed_utf8
+ try:
+ with pytest.raises(Exception):
+ # Seen with Python 3.9: SystemError: nameless module
+ # But we do not want to exercise the internals of PyModule_GetName(), which could
+ # change in future versions of Python, but a bad __name__ is very likely to cause
+ # some kind of failure indefinitely.
+ m.def_submodule(sm, b"SubSubModuleName")
+ finally:
+ # Clean up to ensure nothing gets upset by a module with an invalid __name__.
+ sm.__name__ = sm_name_orig # Purely precautionary.
+ # Meant to trigger PyImport_AddModule() failure:
+ with pytest.raises(UnicodeDecodeError):
+ m.def_submodule(sm, malformed_utf8)
diff --git a/3rdparty/pybind11/tests/test_multiple_inheritance.cpp b/3rdparty/pybind11/tests/test_multiple_inheritance.cpp
index e6720080..5916ae90 100644
--- a/3rdparty/pybind11/tests/test_multiple_inheritance.cpp
+++ b/3rdparty/pybind11/tests/test_multiple_inheritance.cpp
@@ -8,13 +8,16 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
#include "constructor_stats.h"
+#include "pybind11_tests.h"
+
+namespace {
// 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) { }
+template <int N>
+struct BaseN {
+ explicit BaseN(int i) : i(i) {}
int i;
};
@@ -43,103 +46,139 @@ int WithStatic2::static_value2 = 2;
int VanillaStaticMix1::static_value = 12;
int VanillaStaticMix2::static_value = 12;
+// test_multiple_inheritance_virtbase
+struct Base1a {
+ explicit Base1a(int i) : i(i) {}
+ int foo() const { return i; }
+ int i;
+};
+struct Base2a {
+ explicit Base2a(int i) : i(i) {}
+ int bar() const { return i; }
+ int i;
+};
+struct Base12a : Base1a, Base2a {
+ Base12a(int i, int j) : Base1a(i), Base2a(j) {}
+};
+
+// test_mi_unaligned_base
+// test_mi_base_return
+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
+
+} // namespace
+
TEST_SUBMODULE(multiple_inheritance, m) {
+ // Please do not interleave `struct` and `class` definitions with bindings code,
+ // but implement `struct`s and `class`es in the anonymous namespace above.
+ // This helps keeping the smart_holder branch in sync with master.
// test_multiple_inheritance_mix1
// test_multiple_inheritance_mix2
struct Base1 {
- Base1(int i) : i(i) { }
- int foo() { return i; }
+ explicit Base1(int i) : i(i) {}
+ int foo() const { return i; }
int i;
};
py::class_<Base1> b1(m, "Base1");
- b1.def(py::init<int>())
- .def("foo", &Base1::foo);
+ b1.def(py::init<int>()).def("foo", &Base1::foo);
struct Base2 {
- Base2(int i) : i(i) { }
- int bar() { return i; }
+ explicit Base2(int i) : i(i) {}
+ int bar() const { return i; }
int i;
};
py::class_<Base2> b2(m, "Base2");
- b2.def(py::init<int>())
- .def("bar", &Base2::bar);
-
+ 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) { }
+ Base12(int i, int j) : Base1(i), Base2(j) {}
};
struct MIType : Base12 {
- MIType(int i, int j) : Base12(i, j) { }
+ 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>());
-
+ 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);
+#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>());
-
+ // 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())
+ 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(); });
+ m.def("bar_base2a_sharedptr", [](const 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 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_<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<>());
@@ -164,11 +203,8 @@ TEST_SUBMODULE(multiple_inheritance, m) {
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_<Vanilla>(m, "Vanilla").def(py::init<>()).def("vanilla", &Vanilla::vanilla);
py::class_<WithStatic1>(m, "WithStatic1")
.def(py::init<>())
@@ -180,22 +216,19 @@ TEST_SUBMODULE(multiple_inheritance, m) {
.def_static("static_func2", &WithStatic2::static_func2)
.def_readwrite_static("static_value2", &WithStatic2::static_value2);
- py::class_<VanillaStaticMix1, Vanilla, WithStatic1, WithStatic2>(
- m, "VanillaStaticMix1")
+ 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")
+ 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);
-
- struct WithDict { };
- struct VanillaDictMix1 : Vanilla, WithDict { };
- struct VanillaDictMix2 : WithDict, Vanilla { };
+ 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<>());
@@ -203,16 +236,106 @@ TEST_SUBMODULE(multiple_inheritance, m) {
// 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<>());
+ 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<>());
+
+ // test_pr3635_diamond_*
+ // - functions are get_{base}_{var}, return {var}
+ struct MVB {
+ MVB() = default;
+ MVB(const MVB &) = default;
+ virtual ~MVB() = default;
+
+ int b = 1;
+ int get_b_b() const { return b; }
+ };
+ struct MVC : virtual MVB {
+ int c = 2;
+ int get_c_b() const { return b; }
+ int get_c_c() const { return c; }
+ };
+ struct MVD0 : virtual MVC {
+ int d0 = 3;
+ int get_d0_b() const { return b; }
+ int get_d0_c() const { return c; }
+ int get_d0_d0() const { return d0; }
+ };
+ struct MVD1 : virtual MVC {
+ int d1 = 4;
+ int get_d1_b() const { return b; }
+ int get_d1_c() const { return c; }
+ int get_d1_d1() const { return d1; }
+ };
+ struct MVE : virtual MVD0, virtual MVD1 {
+ int e = 5;
+ int get_e_b() const { return b; }
+ int get_e_c() const { return c; }
+ int get_e_d0() const { return d0; }
+ int get_e_d1() const { return d1; }
+ int get_e_e() const { return e; }
+ };
+ struct MVF : virtual MVE {
+ int f = 6;
+ int get_f_b() const { return b; }
+ int get_f_c() const { return c; }
+ int get_f_d0() const { return d0; }
+ int get_f_d1() const { return d1; }
+ int get_f_e() const { return e; }
+ int get_f_f() const { return f; }
+ };
+ py::class_<MVB>(m, "MVB")
+ .def(py::init<>())
+ .def("get_b_b", &MVB::get_b_b)
+ .def_readwrite("b", &MVB::b);
+ py::class_<MVC, MVB>(m, "MVC")
+ .def(py::init<>())
+ .def("get_c_b", &MVC::get_c_b)
+ .def("get_c_c", &MVC::get_c_c)
+ .def_readwrite("c", &MVC::c);
+ py::class_<MVD0, MVC>(m, "MVD0")
+ .def(py::init<>())
+ .def("get_d0_b", &MVD0::get_d0_b)
+ .def("get_d0_c", &MVD0::get_d0_c)
+ .def("get_d0_d0", &MVD0::get_d0_d0)
+ .def_readwrite("d0", &MVD0::d0);
+ py::class_<MVD1, MVC>(m, "MVD1")
+ .def(py::init<>())
+ .def("get_d1_b", &MVD1::get_d1_b)
+ .def("get_d1_c", &MVD1::get_d1_c)
+ .def("get_d1_d1", &MVD1::get_d1_d1)
+ .def_readwrite("d1", &MVD1::d1);
+ py::class_<MVE, MVD0, MVD1>(m, "MVE")
+ .def(py::init<>())
+ .def("get_e_b", &MVE::get_e_b)
+ .def("get_e_c", &MVE::get_e_c)
+ .def("get_e_d0", &MVE::get_e_d0)
+ .def("get_e_d1", &MVE::get_e_d1)
+ .def("get_e_e", &MVE::get_e_e)
+ .def_readwrite("e", &MVE::e);
+ py::class_<MVF, MVE>(m, "MVF")
+ .def(py::init<>())
+ .def("get_f_b", &MVF::get_f_b)
+ .def("get_f_c", &MVF::get_f_c)
+ .def("get_f_d0", &MVF::get_f_d0)
+ .def("get_f_d1", &MVF::get_f_d1)
+ .def("get_f_e", &MVF::get_f_e)
+ .def("get_f_f", &MVF::get_f_f)
+ .def_readwrite("f", &MVF::f);
}
diff --git a/3rdparty/pybind11/tests/test_multiple_inheritance.py b/3rdparty/pybind11/tests/test_multiple_inheritance.py
index e6a7f976..3a1d88d7 100644
--- a/3rdparty/pybind11/tests/test_multiple_inheritance.py
+++ b/3rdparty/pybind11/tests/test_multiple_inheritance.py
@@ -1,8 +1,6 @@
-# -*- coding: utf-8 -*-
import pytest
import env # noqa: F401
-
from pybind11_tests import ConstructorStats
from pybind11_tests import multiple_inheritance as m
@@ -14,8 +12,7 @@ def test_multiple_inheritance_cpp():
assert mt.bar() == 4
-@pytest.mark.skipif("env.PYPY and env.PY2")
-@pytest.mark.xfail("env.PYPY and not env.PY2")
+@pytest.mark.xfail("env.PYPY")
def test_multiple_inheritance_mix1():
class Base1:
def __init__(self, i):
@@ -54,15 +51,14 @@ def test_multiple_inheritance_mix2():
assert mt.bar() == 4
-@pytest.mark.skipif("env.PYPY and env.PY2")
-@pytest.mark.xfail("env.PYPY and not env.PY2")
+@pytest.mark.xfail("env.PYPY")
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):
+ class B1:
def v(self):
return 1
@@ -97,7 +93,7 @@ def test_multiple_inheritance_python():
def v(self):
return 2
- class B3(object):
+ class B3:
def v(self):
return 3
@@ -359,3 +355,139 @@ def test_diamond_inheritance():
assert d is d.c0().b()
assert d is d.c1().b()
assert d is d.c0().c1().b().c0().b()
+
+
+def test_pr3635_diamond_b():
+ o = m.MVB()
+ assert o.b == 1
+
+ assert o.get_b_b() == 1
+
+
+def test_pr3635_diamond_c():
+ o = m.MVC()
+ assert o.b == 1
+ assert o.c == 2
+
+ assert o.get_b_b() == 1
+ assert o.get_c_b() == 1
+
+ assert o.get_c_c() == 2
+
+
+def test_pr3635_diamond_d0():
+ o = m.MVD0()
+ assert o.b == 1
+ assert o.c == 2
+ assert o.d0 == 3
+
+ assert o.get_b_b() == 1
+ assert o.get_c_b() == 1
+ assert o.get_d0_b() == 1
+
+ assert o.get_c_c() == 2
+ assert o.get_d0_c() == 2
+
+ assert o.get_d0_d0() == 3
+
+
+def test_pr3635_diamond_d1():
+ o = m.MVD1()
+ assert o.b == 1
+ assert o.c == 2
+ assert o.d1 == 4
+
+ assert o.get_b_b() == 1
+ assert o.get_c_b() == 1
+ assert o.get_d1_b() == 1
+
+ assert o.get_c_c() == 2
+ assert o.get_d1_c() == 2
+
+ assert o.get_d1_d1() == 4
+
+
+def test_pr3635_diamond_e():
+ o = m.MVE()
+ assert o.b == 1
+ assert o.c == 2
+ assert o.d0 == 3
+ assert o.d1 == 4
+ assert o.e == 5
+
+ assert o.get_b_b() == 1
+ assert o.get_c_b() == 1
+ assert o.get_d0_b() == 1
+ assert o.get_d1_b() == 1
+ assert o.get_e_b() == 1
+
+ assert o.get_c_c() == 2
+ assert o.get_d0_c() == 2
+ assert o.get_d1_c() == 2
+ assert o.get_e_c() == 2
+
+ assert o.get_d0_d0() == 3
+ assert o.get_e_d0() == 3
+
+ assert o.get_d1_d1() == 4
+ assert o.get_e_d1() == 4
+
+ assert o.get_e_e() == 5
+
+
+def test_pr3635_diamond_f():
+ o = m.MVF()
+ assert o.b == 1
+ assert o.c == 2
+ assert o.d0 == 3
+ assert o.d1 == 4
+ assert o.e == 5
+ assert o.f == 6
+
+ assert o.get_b_b() == 1
+ assert o.get_c_b() == 1
+ assert o.get_d0_b() == 1
+ assert o.get_d1_b() == 1
+ assert o.get_e_b() == 1
+ assert o.get_f_b() == 1
+
+ assert o.get_c_c() == 2
+ assert o.get_d0_c() == 2
+ assert o.get_d1_c() == 2
+ assert o.get_e_c() == 2
+ assert o.get_f_c() == 2
+
+ assert o.get_d0_d0() == 3
+ assert o.get_e_d0() == 3
+ assert o.get_f_d0() == 3
+
+ assert o.get_d1_d1() == 4
+ assert o.get_e_d1() == 4
+ assert o.get_f_d1() == 4
+
+ assert o.get_e_e() == 5
+ assert o.get_f_e() == 5
+
+ assert o.get_f_f() == 6
+
+
+def test_python_inherit_from_mi():
+ """Tests extending a Python class from a single inheritor of a MI class"""
+
+ class PyMVF(m.MVF):
+ g = 7
+
+ def get_g_g(self):
+ return self.g
+
+ o = PyMVF()
+
+ assert o.b == 1
+ assert o.c == 2
+ assert o.d0 == 3
+ assert o.d1 == 4
+ assert o.e == 5
+ assert o.f == 6
+ assert o.g == 7
+
+ assert o.get_g_g() == 7
diff --git a/3rdparty/pybind11/tests/test_numpy_array.cpp b/3rdparty/pybind11/tests/test_numpy_array.cpp
index a84de77f..69ddbe1e 100644
--- a/3rdparty/pybind11/tests/test_numpy_array.cpp
+++ b/3rdparty/pybind11/tests/test_numpy_array.cpp
@@ -7,12 +7,13 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
-
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
+#include "pybind11_tests.h"
+
#include <cstdint>
+#include <utility>
// Size / dtype checks.
struct DtypeCheck {
@@ -21,7 +22,7 @@ struct DtypeCheck {
};
template <typename T>
-DtypeCheck get_dtype_check(const char* name) {
+DtypeCheck get_dtype_check(const char *name) {
py::module_ np = py::module_::import("numpy");
DtypeCheck check{};
check.numpy = np.attr("dtype")(np.attr(name));
@@ -30,17 +31,15 @@ DtypeCheck get_dtype_check(const char* name) {
}
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")
- };
+ 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 {
@@ -79,43 +78,71 @@ 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) {
+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) {
+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 (py::ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++)
+template <typename... Ix>
+arr &mutate_data(arr &a, Ix... index) {
+ auto *ptr = (uint8_t *) a.mutable_data(index...);
+ for (py::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) {
+template <typename... Ix>
+arr_t &mutate_data_t(arr_t &a, Ix... index) {
auto ptr = a.mutable_data(index...);
- for (py::ssize_t i = 0; i < a.size() - a.index_at(index...); i++)
+ for (py::ssize_t i = 0; i < a.size() - a.index_at(index...); i++) {
ptr[i]++;
+ }
+ return a;
+}
+
+template <typename... Ix>
+py::ssize_t index_at(const arr &a, Ix... idx) {
+ return a.index_at(idx...);
+}
+template <typename... Ix>
+py::ssize_t index_at_t(const arr_t &a, Ix... idx) {
+ return a.index_at(idx...);
+}
+template <typename... Ix>
+py::ssize_t offset_at(const arr &a, Ix... idx) {
+ return a.offset_at(idx...);
+}
+template <typename... Ix>
+py::ssize_t offset_at_t(const arr_t &a, Ix... idx) {
+ return a.offset_at(idx...);
+}
+template <typename... Ix>
+py::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;
}
-template<typename... Ix> py::ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); }
-template<typename... Ix> py::ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); }
-template<typename... Ix> py::ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); }
-template<typename... Ix> py::ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); }
-template<typename... Ix> py::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); }); \
+#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");
+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));
@@ -133,16 +160,18 @@ template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) {
static int data_i = 42;
TEST_SUBMODULE(numpy_array, sm) {
- try { py::module_::import("numpy"); }
- catch (...) { return; }
+ try {
+ py::module_::import("numpy");
+ } catch (const py::error_already_set &) {
+ 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);
+ .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);
@@ -150,41 +179,41 @@ TEST_SUBMODULE(numpy_array, sm) {
.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);
+ .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, py::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, py::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(); });
+ 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, py::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, py::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&);
+ 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&);
+ 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&);
+ 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 }); });
+ 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"), {}, {}); });
@@ -192,19 +221,17 @@ TEST_SUBMODULE(numpy_array, sm) {
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
- );
+ sm.def("wrap", [](const 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 };
+ int data[2] = {1, 2};
ArrayClass() { py::print("ArrayClass()"); }
~ArrayClass() { py::print("~ArrayClass()"); }
};
@@ -212,103 +239,121 @@ TEST_SUBMODULE(numpy_array, sm) {
.def(py::init<>())
.def("numpy_view", [](py::object &obj) {
py::print("ArrayClass::numpy_view()");
- auto &a = obj.cast<ArrayClass&>();
+ auto &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) { });
+ 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);
+ return py::isinstance<py::array>(std::move(yes))
+ && !py::isinstance<py::array>(std::move(no));
});
- sm.def("isinstance_typed", [](py::object o) {
+ sm.def("isinstance_typed", [](const 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>()
- );
+ 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)
- );
+ sm.def("converting_constructors", [](const 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"; });
+ sm.def("overloaded", [](const py::array_t<double> &) { return "double"; });
+ sm.def("overloaded", [](const py::array_t<float> &) { return "float"; });
+ sm.def("overloaded", [](const py::array_t<int> &) { return "int"; });
+ sm.def("overloaded", [](const py::array_t<unsigned short> &) { return "unsigned short"; });
+ sm.def("overloaded", [](const py::array_t<long long> &) { return "long long"; });
+ sm.def("overloaded",
+ [](const py::array_t<std::complex<double>> &) { return "double complex"; });
+ sm.def("overloaded", [](const py::array_t<std::complex<float>> &) { return "float complex"; });
+
+ sm.def("overloaded2",
+ [](const py::array_t<std::complex<double>> &) { return "double complex"; });
+ sm.def("overloaded2", [](const py::array_t<double> &) { return "double"; });
+ sm.def("overloaded2",
+ [](const py::array_t<std::complex<float>> &) { return "float complex"; });
+ sm.def("overloaded2", [](const py::array_t<float> &) { return "float"; });
+
+ // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
// 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());
+ sm.def(
+ "overloaded3", [](const py::array_t<int> &) { return "int"; }, py::arg{}.noconvert());
+ sm.def(
+ "overloaded3",
+ [](const 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"; });
+ sm.def("overloaded4", [](const py::array_t<long long, 0> &) { return "long long"; });
+ sm.def("overloaded4", [](const 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"; });
+ sm.def("overloaded5", [](const py::array_t<unsigned int> &) { return "unsigned int"; });
+ sm.def("overloaded5", [](const 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"; });
+ sm.def("issue685", [](const std::string &) { return "string"; });
+ sm.def("issue685", [](const py::array &) { return "array"; });
+ sm.def("issue685", [](const 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 (py::ssize_t i = 0; i < r.shape(0); i++)
- for (py::ssize_t j = 0; j < r.shape(1); j++)
- r(i, j) += v;
- }, py::arg().noconvert(), py::arg());
+ sm.def(
+ "proxy_add2",
+ [](py::array_t<double> a, double v) {
+ auto r = a.mutable_unchecked<2>();
+ for (py::ssize_t i = 0; i < r.shape(0); i++) {
+ for (py::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 });
+ py::array_t<double, py::array::c_style> a({3, 3, 3});
auto r = a.mutable_unchecked<3>();
- for (py::ssize_t i = 0; i < r.shape(0); i++)
- for (py::ssize_t j = 0; j < r.shape(1); j++)
- for (py::ssize_t k = 0; k < r.shape(2); k++)
- r(i, j, k) = start++;
+ for (py::ssize_t i = 0; i < r.shape(0); i++) {
+ for (py::ssize_t j = 0; j < r.shape(1); j++) {
+ for (py::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 });
+ py::array_t<double, py::array::f_style> a({3, 3, 3});
auto r = a.mutable_unchecked<3>();
- for (py::ssize_t k = 0; k < r.shape(2); k++)
- for (py::ssize_t j = 0; j < r.shape(1); j++)
- for (py::ssize_t i = 0; i < r.shape(0); i++)
- r(i, j, k) = start++;
+ for (py::ssize_t k = 0; k < r.shape(2); k++) {
+ for (py::ssize_t j = 0; j < r.shape(1); j++) {
+ for (py::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) {
+ sm.def("proxy_squared_L2_norm", [](const py::array_t<double> &a) {
auto r = a.unchecked<1>();
double sumsq = 0;
- for (py::ssize_t i = 0; i < r.shape(0); i++)
+ for (py::ssize_t i = 0; i < r.shape(0); i++) {
sumsq += r[i] * r(i); // Either notation works for a 1D array
+ }
return sumsq;
});
@@ -332,51 +377,69 @@ TEST_SUBMODULE(numpy_array, sm) {
// 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 (py::ssize_t i = 0; i < r.shape(0); i++)
- for (py::ssize_t j = 0; j < r.shape(1); j++)
- r(i, j) += v;
- }, py::arg().noconvert(), py::arg());
+ 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 (py::ssize_t i = 0; i < r.shape(0); i++) {
+ for (py::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 });
+ 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 (py::ssize_t i = 0; i < r.shape(0); i++)
- for (py::ssize_t j = 0; j < r.shape(1); j++)
- for (py::ssize_t k = 0; k < r.shape(2); k++)
- r(i, j, k) = start++;
+ if (r.ndim() != 3) {
+ throw std::domain_error("error: ndim != 3");
+ }
+ for (py::ssize_t i = 0; i < r.shape(0); i++) {
+ for (py::ssize_t j = 0; j < r.shape(1); j++) {
+ for (py::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);
- });
+ 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:
+ // 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); });
+ 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 }); });
+ sm.def("array_initializer_list1", []() { return py::array_t<float>(1); });
+ // { 1 } also works for the above, 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 auto dim_sz = (py::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");
+ const auto dim_sz = (py::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});
});
@@ -394,45 +457,68 @@ TEST_SUBMODULE(numpy_array, sm) {
return a;
});
- sm.def("index_using_ellipsis", [](py::array a) {
- return a[py::make_tuple(0, py::ellipsis(), 0)];
+ sm.def("array_view",
+ [](py::array_t<uint8_t> a, const std::string &dtype) { return a.view(dtype); });
+
+ sm.def("reshape_initializer_list", [](py::array_t<int> a, size_t N, size_t M, size_t O) {
+ return a.reshape({N, M, O});
+ });
+ sm.def("reshape_tuple", [](py::array_t<int> a, const std::vector<int> &new_shape) {
+ return a.reshape(new_shape);
});
+ sm.def("index_using_ellipsis",
+ [](const py::array &a) { return a[py::make_tuple(0, py::ellipsis(), 0)]; });
+
// test_argument_conversions
- sm.def("accept_double",
- [](py::array_t<double, 0>) {},
- py::arg("a"));
- sm.def("accept_double_forcecast",
- [](py::array_t<double, py::array::forcecast>) {},
- py::arg("a"));
- sm.def("accept_double_c_style",
- [](py::array_t<double, py::array::c_style>) {},
- py::arg("a"));
- sm.def("accept_double_c_style_forcecast",
- [](py::array_t<double, py::array::forcecast | py::array::c_style>) {},
- py::arg("a"));
- sm.def("accept_double_f_style",
- [](py::array_t<double, py::array::f_style>) {},
- py::arg("a"));
- sm.def("accept_double_f_style_forcecast",
- [](py::array_t<double, py::array::forcecast | py::array::f_style>) {},
- py::arg("a"));
- sm.def("accept_double_noconvert",
- [](py::array_t<double, 0>) {},
- py::arg("a").noconvert());
- sm.def("accept_double_forcecast_noconvert",
- [](py::array_t<double, py::array::forcecast>) {},
- py::arg("a").noconvert());
- sm.def("accept_double_c_style_noconvert",
- [](py::array_t<double, py::array::c_style>) {},
- py::arg("a").noconvert());
- sm.def("accept_double_c_style_forcecast_noconvert",
- [](py::array_t<double, py::array::forcecast | py::array::c_style>) {},
- py::arg("a").noconvert());
- sm.def("accept_double_f_style_noconvert",
- [](py::array_t<double, py::array::f_style>) {},
- py::arg("a").noconvert());
- sm.def("accept_double_f_style_forcecast_noconvert",
- [](py::array_t<double, py::array::forcecast | py::array::f_style>) {},
- py::arg("a").noconvert());
+ sm.def(
+ "accept_double", [](const py::array_t<double, 0> &) {}, py::arg("a"));
+ sm.def(
+ "accept_double_forcecast",
+ [](const py::array_t<double, py::array::forcecast> &) {},
+ py::arg("a"));
+ sm.def(
+ "accept_double_c_style",
+ [](const py::array_t<double, py::array::c_style> &) {},
+ py::arg("a"));
+ sm.def(
+ "accept_double_c_style_forcecast",
+ [](const py::array_t<double, py::array::forcecast | py::array::c_style> &) {},
+ py::arg("a"));
+ sm.def(
+ "accept_double_f_style",
+ [](const py::array_t<double, py::array::f_style> &) {},
+ py::arg("a"));
+ sm.def(
+ "accept_double_f_style_forcecast",
+ [](const py::array_t<double, py::array::forcecast | py::array::f_style> &) {},
+ py::arg("a"));
+ sm.def(
+ "accept_double_noconvert", [](const py::array_t<double, 0> &) {}, "a"_a.noconvert());
+ sm.def(
+ "accept_double_forcecast_noconvert",
+ [](const py::array_t<double, py::array::forcecast> &) {},
+ "a"_a.noconvert());
+ sm.def(
+ "accept_double_c_style_noconvert",
+ [](const py::array_t<double, py::array::c_style> &) {},
+ "a"_a.noconvert());
+ sm.def(
+ "accept_double_c_style_forcecast_noconvert",
+ [](const py::array_t<double, py::array::forcecast | py::array::c_style> &) {},
+ "a"_a.noconvert());
+ sm.def(
+ "accept_double_f_style_noconvert",
+ [](const py::array_t<double, py::array::f_style> &) {},
+ "a"_a.noconvert());
+ sm.def(
+ "accept_double_f_style_forcecast_noconvert",
+ [](const py::array_t<double, py::array::forcecast | py::array::f_style> &) {},
+ "a"_a.noconvert());
+
+ // Check that types returns correct npy format descriptor
+ sm.def("test_fmt_desc_float", [](const py::array_t<float> &) {});
+ sm.def("test_fmt_desc_double", [](const py::array_t<double> &) {});
+ sm.def("test_fmt_desc_const_float", [](const py::array_t<const float> &) {});
+ sm.def("test_fmt_desc_const_double", [](const py::array_t<const double> &) {});
}
diff --git a/3rdparty/pybind11/tests/test_numpy_array.py b/3rdparty/pybind11/tests/test_numpy_array.py
index 02f3ecfc..504963b1 100644
--- a/3rdparty/pybind11/tests/test_numpy_array.py
+++ b/3rdparty/pybind11/tests/test_numpy_array.py
@@ -1,8 +1,6 @@
-# -*- coding: utf-8 -*-
import pytest
import env # noqa: F401
-
from pybind11_tests import numpy_array as m
np = pytest.importorskip("numpy")
@@ -20,9 +18,7 @@ def test_dtypes():
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
- )
+ f"NOTE: typenum mismatch for {check}: {check.numpy.num} != {check.pybind11.num}"
)
@@ -118,9 +114,7 @@ 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
- )
+ assert str(excinfo.value) == f"index dimension mismatch: {dim} (ndim = 2)"
def test_at(arr):
@@ -194,8 +188,6 @@ def test_make_empty_shaped_array():
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
@@ -206,7 +198,8 @@ def test_wrap():
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"):
+ # 1.13 supported Python 3.6
+ if tuple(int(x) for x in np.__version__.split(".")[:2]) >= (1, 14):
assert a.flags.writebackifcopy == b.flags.writebackifcopy
else:
assert a.flags.updateifcopy == b.flags.updateifcopy
@@ -412,7 +405,7 @@ def test_array_unchecked_fixed_dims(msg):
assert m.proxy_auxiliaries2_const_ref(z1)
-def test_array_unchecked_dyn_dims(msg):
+def test_array_unchecked_dyn_dims():
z1 = np.array([[1, 2], [3, 4]], dtype="float64")
m.proxy_add2_dyn(z1, 10)
assert np.all(z1 == [[11, 12], [13, 14]])
@@ -445,7 +438,7 @@ def test_initializer_list():
assert m.array_initializer_list4().shape == (1, 2, 3, 4)
-def test_array_resize(msg):
+def test_array_resize():
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype="float64")
m.array_reshape2(a)
assert a.size == 9
@@ -471,17 +464,70 @@ def test_array_resize(msg):
@pytest.mark.xfail("env.PYPY")
-def test_array_create_and_resize(msg):
+def test_array_create_and_resize():
a = m.create_and_resize(2)
assert a.size == 4
assert np.all(a == 42.0)
+def test_array_view():
+ a = np.ones(100 * 4).astype("uint8")
+ a_float_view = m.array_view(a, "float32")
+ assert a_float_view.shape == (100 * 1,) # 1 / 4 bytes = 8 / 32
+
+ a_int16_view = m.array_view(a, "int16") # 1 / 2 bytes = 16 / 32
+ assert a_int16_view.shape == (100 * 2,)
+
+
+def test_array_view_invalid():
+ a = np.ones(100 * 4).astype("uint8")
+ with pytest.raises(TypeError):
+ m.array_view(a, "deadly_dtype")
+
+
+def test_reshape_initializer_list():
+ a = np.arange(2 * 7 * 3) + 1
+ x = m.reshape_initializer_list(a, 2, 7, 3)
+ assert x.shape == (2, 7, 3)
+ assert list(x[1][4]) == [34, 35, 36]
+ with pytest.raises(ValueError) as excinfo:
+ m.reshape_initializer_list(a, 1, 7, 3)
+ assert str(excinfo.value) == "cannot reshape array of size 42 into shape (1,7,3)"
+
+
+def test_reshape_tuple():
+ a = np.arange(3 * 7 * 2) + 1
+ x = m.reshape_tuple(a, (3, 7, 2))
+ assert x.shape == (3, 7, 2)
+ assert list(x[1][4]) == [23, 24]
+ y = m.reshape_tuple(x, (x.size,))
+ assert y.shape == (42,)
+ with pytest.raises(ValueError) as excinfo:
+ m.reshape_tuple(a, (3, 7, 1))
+ assert str(excinfo.value) == "cannot reshape array of size 42 into shape (3,7,1)"
+ with pytest.raises(ValueError) as excinfo:
+ m.reshape_tuple(a, ())
+ assert str(excinfo.value) == "cannot reshape array of size 42 into shape ()"
+
+
def test_index_using_ellipsis():
a = m.index_using_ellipsis(np.zeros((5, 6, 7)))
assert a.shape == (6,)
+@pytest.mark.parametrize(
+ "test_func",
+ [
+ m.test_fmt_desc_float,
+ m.test_fmt_desc_double,
+ m.test_fmt_desc_const_float,
+ m.test_fmt_desc_const_double,
+ ],
+)
+def test_format_descriptors_for_floating_point_types(test_func):
+ assert "numpy.ndarray[numpy.float" in test_func.__doc__
+
+
@pytest.mark.parametrize("forcecast", [False, True])
@pytest.mark.parametrize("contiguity", [None, "C", "F"])
@pytest.mark.parametrize("noconvert", [False, True])
diff --git a/3rdparty/pybind11/tests/test_numpy_dtypes.cpp b/3rdparty/pybind11/tests/test_numpy_dtypes.cpp
index b2e5e607..6654f9ed 100644
--- a/3rdparty/pybind11/tests/test_numpy_dtypes.cpp
+++ b/3rdparty/pybind11/tests/test_numpy_dtypes.cpp
@@ -7,13 +7,14 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
#include <pybind11/numpy.h>
+#include "pybind11_tests.h"
+
#ifdef __GNUC__
-#define PYBIND11_PACKED(cls) cls __attribute__((__packed__))
+# define PYBIND11_PACKED(cls) cls __attribute__((__packed__))
#else
-#define PYBIND11_PACKED(cls) __pragma(pack(push, 1)) cls __pragma(pack(pop))
+# define PYBIND11_PACKED(cls) __pragma(pack(push, 1)) cls __pragma(pack(pop))
#endif
namespace py = pybind11;
@@ -25,7 +26,7 @@ struct SimpleStruct {
long double ldbl_;
};
-std::ostream& operator<<(std::ostream& os, const SimpleStruct& v) {
+std::ostream &operator<<(std::ostream &os, const SimpleStruct &v) {
return os << "s:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_;
}
@@ -43,7 +44,7 @@ PYBIND11_PACKED(struct PackedStruct {
long double ldbl_;
});
-std::ostream& operator<<(std::ostream& os, const PackedStruct& v) {
+std::ostream &operator<<(std::ostream &os, const PackedStruct &v) {
return os << "p:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_;
}
@@ -52,7 +53,7 @@ PYBIND11_PACKED(struct NestedStruct {
PackedStruct b;
});
-std::ostream& operator<<(std::ostream& os, const NestedStruct& v) {
+std::ostream &operator<<(std::ostream &os, const NestedStruct &v) {
return os << "n:a=" << v.a << ";b=" << v.b;
}
@@ -70,7 +71,7 @@ struct PartialNestedStruct {
uint64_t dummy2;
};
-struct UnboundStruct { };
+struct UnboundStruct {};
struct StringStruct {
char a[3];
@@ -82,7 +83,7 @@ struct ComplexStruct {
std::complex<double> cdbl;
};
-std::ostream& operator<<(std::ostream& os, const ComplexStruct& v) {
+std::ostream &operator<<(std::ostream &os, const ComplexStruct &v) {
return os << "c:" << v.cflt << "," << v.cdbl;
}
@@ -106,57 +107,65 @@ PYBIND11_PACKED(struct EnumStruct {
E2 e2;
});
-std::ostream& operator<<(std::ostream& os, const StringStruct& v) {
+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];
+ for (size_t i = 0; i < 3 && (v.a[i] != 0); i++) {
+ os << v.a[i];
+ }
os << "',b='";
- for (size_t i = 0; i < 3 && v.b[i]; i++) os << v.b[i];
+ for (size_t i = 0; i < 3 && (v.b[i] != 0); i++) {
+ os << v.b[i];
+ }
return os << "'";
}
-std::ostream& operator<<(std::ostream& os, const ArrayStruct& v) {
+std::ostream &operator<<(std::ostream &os, const ArrayStruct &v) {
os << "a={";
for (int i = 0; i < 3; i++) {
- if (i > 0)
+ if (i > 0) {
os << ',';
+ }
os << '{';
- for (int j = 0; j < 3; j++)
+ 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)
+ if (i > 0) {
os << ',';
+ }
os << '{' << v.d[i][0] << ',' << v.d[i][1] << '}';
}
return os << '}';
}
-std::ostream& operator<<(std::ostream& os, const EnumStruct& v) {
+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) }));
+ 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)
+#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);
+ auto *ptr = static_cast<S *>(req.ptr);
for (size_t i = 0; i < n; i++) {
SET_TEST_VALS(ptr[i], i);
}
@@ -166,7 +175,7 @@ py::array_t<S, 0> create_recarray(size_t n) {
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 *const ptr = static_cast<S *>(req.ptr);
auto l = py::list();
for (py::ssize_t i = 0; i < req.size; i++) {
std::stringstream ss;
@@ -179,12 +188,12 @@ py::list print_recarray(py::array_t<S, 0> arr) {
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<py::ssize_t> shape { 3, 2 };
- std::vector<py::ssize_t> strides { 8, 4 };
+ std::vector<int32_t> data{1, 2, 3, 4, 5, 6};
+ std::vector<py::ssize_t> shape{3, 2};
+ std::vector<py::ssize_t> strides{8, 4};
- auto ptr = data.data();
- auto vptr = (void *) ptr;
+ auto *ptr = data.data();
+ auto *vptr = (void *) ptr;
auto dtype = py::dtype("int32");
py::buffer_info buf_ndim1(vptr, 4, "i", 6);
@@ -194,41 +203,69 @@ py::array_t<int32_t, 0> test_array_ctors(int i) {
auto fill = [](py::array arr) {
auto req = arr.request();
- for (int i = 0; i < 6; i++) ((int32_t *) req.ptr)[i] = i + 1;
+ 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));
+ // 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();
}
@@ -240,14 +277,21 @@ py::list test_dtype_ctors() {
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;
+ 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)));
+ list.append(py::dtype(py::buffer_info((void *) nullptr, sizeof(unsigned int), "I", 1)));
+ list.append(py::dtype(py::buffer_info((void *) nullptr, 0, "T{i:a:f:b:}", 1)));
+ list.append(py::dtype(py::detail::npy_api::NPY_DOUBLE_));
return list;
}
@@ -255,8 +299,11 @@ struct A {};
struct B {};
TEST_SUBMODULE(numpy_dtypes, m) {
- try { py::module_::import("numpy"); }
- catch (...) { return; }
+ try {
+ py::module_::import("numpy");
+ } catch (const py::error_already_set &) {
+ return;
+ }
// typeinfo may be registered before the dtype descriptor for scalar casts to work...
py::class_<SimpleStruct>(m, "SimpleStruct")
@@ -266,18 +313,18 @@ TEST_SUBMODULE(numpy_dtypes, m) {
.def_readwrite("uint_", &SimpleStruct::uint_)
.def_readwrite("float_", &SimpleStruct::float_)
.def_readwrite("ldbl_", &SimpleStruct::ldbl_)
- .def("astuple", [](const SimpleStruct& self) {
- return py::make_tuple(self.bool_, self.uint_, self.float_, self.ldbl_);
- })
- .def_static("fromtuple", [](const py::tuple tup) {
+ .def("astuple",
+ [](const SimpleStruct &self) {
+ return py::make_tuple(self.bool_, self.uint_, self.float_, self.ldbl_);
+ })
+ .def_static("fromtuple", [](const py::tuple &tup) {
if (py::len(tup) != 4) {
throw py::cast_error("Invalid size");
}
- return SimpleStruct{
- tup[0].cast<bool>(),
- tup[1].cast<uint32_t>(),
- tup[2].cast<float>(),
- tup[3].cast<long double>()};
+ return SimpleStruct{tup[0].cast<bool>(),
+ tup[1].cast<uint32_t>(),
+ tup[2].cast<float>(),
+ tup[3].cast<long double>()};
});
PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_);
@@ -296,19 +343,21 @@ TEST_SUBMODULE(numpy_dtypes, m) {
PYBIND11_NUMPY_DTYPE_EX(StructWithUglyNames, __x__, "x", __y__, "y");
- // If uncommented, this should produce a static_assert failure telling the user that the struct
+#ifdef PYBIND11_NEVER_DEFINED_EVER
+ // If enabled, 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);
+ struct NotPOD {
+ std::string v;
+ NotPOD() : v("hi"){};
+ };
+ PYBIND11_NUMPY_DTYPE(NotPOD, v);
+#endif
// 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<A>::register_dtype({});
py::detail::npy_format_descriptor<B>::register_dtype(
- std::vector<py::detail::field_descriptor>{}
- );
+ std::vector<py::detail::field_descriptor>{});
// test_recarray, test_scalar_conversion
m.def("create_rec_simple", &create_recarray<SimpleStruct>);
@@ -316,7 +365,7 @@ TEST_SUBMODULE(numpy_dtypes, m) {
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);
+ 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);
@@ -327,7 +376,7 @@ TEST_SUBMODULE(numpy_dtypes, m) {
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);
+ auto *ptr = static_cast<PartialNestedStruct *>(req.ptr);
for (size_t i = 0; i < n; i++) {
SET_TEST_VALS(ptr[i].a, i);
}
@@ -341,48 +390,95 @@ TEST_SUBMODULE(numpy_dtypes, m) {
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()
- }) {
+ 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
+ std::vector<const char *> dtype_names{
+ "byte", "short", "intc", "int_", "longlong", "ubyte", "ushort",
+ "uintc", "uint", "ulonglong", "half", "single", "double", "longdouble",
+ "csingle", "cdouble", "clongdouble", "bool_", "datetime64", "timedelta64", "object_"};
+
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>()
- })
+ 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_kind", [dtype_names]() {
+ py::list list;
+ for (const auto &dt_name : dtype_names) {
+ list.append(py::dtype(dt_name).kind());
+ }
+ return list;
+ });
+ m.def("test_dtype_char_", [dtype_names]() {
+ py::list list;
+ for (const auto &dt_name : dtype_names) {
+ list.append(py::dtype(dt_name).char_());
+ }
+ return list;
+ });
+ m.def("test_dtype_num", [dtype_names]() {
+ py::list list;
+ for (const auto &dt_name : dtype_names) {
+ list.append(py::dtype(dt_name).num());
+ }
+ return list;
+ });
+ m.def("test_dtype_byteorder", [dtype_names]() {
+ py::list list;
+ for (const auto &dt_name : dtype_names) {
+ list.append(py::dtype(dt_name).byteorder());
+ }
+ return list;
+ });
+ m.def("test_dtype_alignment", [dtype_names]() {
+ py::list list;
+ for (const auto &dt_name : dtype_names) {
+ list.append(py::dtype(dt_name).alignment());
+ }
+ return list;
+ });
+ m.def("test_dtype_flags", [dtype_names]() {
+ py::list list;
+ for (const auto &dt_name : dtype_names) {
+ list.append(py::dtype(dt_name).flags());
+ }
+ return list;
+ });
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()));
+ 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 {
@@ -397,17 +493,24 @@ TEST_SUBMODULE(numpy_dtypes, m) {
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 (py::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';
+ auto *ptr = static_cast<StringStruct *>(req.ptr);
+ for (py::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;
});
@@ -416,18 +519,24 @@ TEST_SUBMODULE(numpy_dtypes, m) {
// 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();
+ 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++)
+ 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++)
+ }
+ }
+ 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++)
+ }
+ 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++)
+ }
+ 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;
});
@@ -436,7 +545,7 @@ TEST_SUBMODULE(numpy_dtypes, m) {
// 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();
+ 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));
@@ -448,7 +557,7 @@ TEST_SUBMODULE(numpy_dtypes, m) {
// 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();
+ 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);
@@ -471,14 +580,19 @@ TEST_SUBMODULE(numpy_dtypes, m) {
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))));
+ 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()); });
+ m.def("buffer_to_dtype", [](py::buffer &buf) { return py::dtype(buf.request()); });
// test_scalar_conversion
auto f_simple = [](SimpleStruct s) { return s.uint_ * 10; };
@@ -492,8 +606,9 @@ TEST_SUBMODULE(numpy_dtypes, m) {
m.def("f_simple_pass_thru_vectorized", py::vectorize(f_simple_pass_thru));
// test_register_dtype
- m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
+ 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)); });
+ m.def("dtype_wrapper", [](const py::object &d) { return py::dtype::from_args(d); });
}
diff --git a/3rdparty/pybind11/tests/test_numpy_dtypes.py b/3rdparty/pybind11/tests/test_numpy_dtypes.py
index f56b776a..fcfd587b 100644
--- a/3rdparty/pybind11/tests/test_numpy_dtypes.py
+++ b/3rdparty/pybind11/tests/test_numpy_dtypes.py
@@ -1,10 +1,8 @@
-# -*- coding: utf-8 -*-
import re
import pytest
import env # noqa: F401
-
from pybind11_tests import numpy_dtypes as m
np = pytest.importorskip("numpy")
@@ -16,7 +14,7 @@ def simple_dtype():
return np.dtype(
{
"names": ["bool_", "uint_", "float_", "ldbl_"],
- "formats": ["?", "u4", "f4", "f{}".format(ld.itemsize)],
+ "formats": ["?", "u4", "f4", f"f{ld.itemsize}"],
"offsets": [0, 4, 8, (16 if ld.alignment > 4 else 12)],
}
)
@@ -33,8 +31,8 @@ def dt_fmt():
e = "<" if byteorder == "little" else ">"
return (
"{{'names':['bool_','uint_','float_','ldbl_'],"
- " 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}'],"
- " 'offsets':[0,4,8,{}], 'itemsize':{}}}"
+ "'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}'],"
+ "'offsets':[0,4,8,{}],'itemsize':{}}}"
)
@@ -47,7 +45,7 @@ def simple_dtype_fmt():
def packed_dtype_fmt():
from sys import byteorder
- return "[('bool_', '?'), ('uint_', '{e}u4'), ('float_', '{e}f4'), ('ldbl_', '{e}f{}')]".format(
+ return "[('bool_','?'),('uint_','{e}u4'),('float_','{e}f4'),('ldbl_','{e}f{}')]".format(
np.dtype("longdouble").itemsize, e="<" if byteorder == "little" else ">"
)
@@ -64,15 +62,21 @@ def partial_ld_offset():
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)
+ partial_size = partial_ld_off + ld.itemsize
+ partial_end_padding = partial_size % np.dtype("uint64").alignment
+ return dt_fmt().format(
+ ld.itemsize, partial_ld_off, partial_size + partial_end_padding
+ )
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_size = partial_ld_off + ld.itemsize
+ partial_end_padding = partial_size % np.dtype("uint64").alignment
+ partial_nested_size = partial_nested_off * 2 + partial_size + partial_end_padding
+ return "{{'names':['a'],'formats':[{}],'offsets':[{}],'itemsize':{}}}".format(
partial_dtype_fmt(), partial_nested_off, partial_nested_size
)
@@ -92,10 +96,12 @@ def test_format_descriptors():
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")
+ end_padding = ld.itemsize % np.dtype("uint64").alignment
partial_fmt = (
"^T{?:bool_:3xI:uint_:f:float_:"
+ str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8))
- + "xg:ldbl_:}"
+ + "xg:ldbl_:"
+ + (str(end_padding) + "x}" if end_padding > 0 else "}")
)
nested_extra = str(max(8, ld.alignment))
assert m.print_format_descriptors() == [
@@ -116,25 +122,25 @@ def test_dtype(simple_dtype):
e = "<" if byteorder == "little" else ">"
- assert m.print_dtypes() == [
+ assert [x.replace(" ", "") for x in m.print_dtypes()] == [
simple_dtype_fmt(),
packed_dtype_fmt(),
- "[('a', {}), ('b', {})]".format(simple_dtype_fmt(), packed_dtype_fmt()),
+ f"[('a',{simple_dtype_fmt()}),('b',{packed_dtype_fmt()})]",
partial_dtype_fmt(),
partial_nested_fmt(),
- "[('a', 'S3'), ('b', 'S3')]",
+ "[('a','S3'),('b','S3')]",
(
- "{{'names':['a','b','c','d'], "
- + "'formats':[('S4', (3,)),('"
+ "{{'names':['a','b','c','d'],"
+ + "'formats':[('S4',(3,)),('"
+ e
- + "i4', (2,)),('u1', (3,)),('"
+ + "i4',(2,)),('u1',(3,)),('"
+ e
- + "f4', (4, 2))], "
- + "'offsets':[0,12,20,24], 'itemsize':56}}"
+ + "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')]",
+ "[('e1','" + e + "i8'),('e2','u1')]",
+ "[('x','i1'),('y','" + e + "u8')]",
+ "[('cflt','" + e + "c8'),('cdbl','" + e + "c16')]",
]
d1 = np.dtype(
@@ -154,6 +160,7 @@ def test_dtype(simple_dtype):
d1,
np.dtype("uint32"),
d2,
+ np.dtype("d"),
]
assert m.test_dtype_methods() == [
@@ -169,6 +176,14 @@ def test_dtype(simple_dtype):
np.zeros(1, m.trailing_padding_dtype())
)
+ expected_chars = "bhilqBHILQefdgFDG?MmO"
+ assert m.test_dtype_kind() == list("iiiiiuuuuuffffcccbMmO")
+ assert m.test_dtype_char_() == list(expected_chars)
+ assert m.test_dtype_num() == [np.dtype(ch).num for ch in expected_chars]
+ assert m.test_dtype_byteorder() == [np.dtype(ch).byteorder for ch in expected_chars]
+ assert m.test_dtype_alignment() == [np.dtype(ch).alignment for ch in expected_chars]
+ assert m.test_dtype_flags() == [chr(np.dtype(ch).flags) for ch in expected_chars]
+
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)]
@@ -228,7 +243,7 @@ def test_recarray(simple_dtype, packed_dtype):
]
arr = m.create_rec_partial(3)
- assert str(arr.dtype) == partial_dtype_fmt()
+ assert str(arr.dtype).replace(" ", "") == partial_dtype_fmt()
partial_dtype = arr.dtype
assert "" not in arr.dtype.fields
assert partial_dtype.itemsize > simple_dtype.itemsize
@@ -236,7 +251,7 @@ def test_recarray(simple_dtype, packed_dtype):
assert_equal(arr, elements, packed_dtype)
arr = m.create_rec_partial_nested(3)
- assert str(arr.dtype) == partial_nested_fmt()
+ assert str(arr.dtype).replace(" ", "") == 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
@@ -275,12 +290,12 @@ def test_array_array():
e = "<" if byteorder == "little" else ">"
arr = m.create_array_array(3)
- assert str(arr.dtype) == (
- "{{'names':['a','b','c','d'], "
- + "'formats':[('S4', (3,)),('"
+ assert str(arr.dtype).replace(" ", "") == (
+ "{{'names':['a','b','c','d'],"
+ + "'formats':[('S4',(3,)),('"
+ e
- + "i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], "
- + "'offsets':[0,12,20,24], 'itemsize':56}}"
+ + "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},"
diff --git a/3rdparty/pybind11/tests/test_numpy_vectorize.cpp b/3rdparty/pybind11/tests/test_numpy_vectorize.cpp
index 274b7558..dcc4c6ac 100644
--- a/3rdparty/pybind11/tests/test_numpy_vectorize.cpp
+++ b/3rdparty/pybind11/tests/test_numpy_vectorize.cpp
@@ -8,66 +8,80 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
#include <pybind11/numpy.h>
+#include "pybind11_tests.h"
+
+#include <utility>
+
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;
+ return (float) x * y * z;
}
TEST_SUBMODULE(numpy_vectorize, m) {
- try { py::module_::import("numpy"); }
- catch (...) { return; }
+ try {
+ py::module_::import("numpy");
+ } catch (const py::error_already_set &) {
+ 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 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); })(std::move(x),
+ std::move(y));
+ });
// Vectorize a complex-valued function
- m.def("vectorized_func3", py::vectorize(
- [](std::complex<double> c) { return c * std::complex<double>(2.f); }
- ));
+ 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."; });
-
+ // A lot of these no lints could be replaced with const refs, and probably should at some
+ // point.
+ m.def("selective_func",
+ [](const py::array_t<int, py::array::c_style> &) { return "Int branch taken."; });
+ m.def("selective_func",
+ [](const py::array_t<float, py::array::c_style> &) { return "Float branch taken."; });
+ m.def("selective_func", [](const 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):
+ // 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} {}
+ explicit NonPODClass(int v) : value{v} {}
int value;
};
py::class_<NonPODClass>(m, "NonPODClass")
.def(py::init<int>())
.def_readwrite("value", &NonPODClass::value);
- 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;
- }
- ));
+ m.def("vec_passthrough",
+ py::vectorize([](const double *a,
+ double b,
+ // Changing this broke things
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
+ 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); }
+ explicit VectorizeTestClass(int v) : value{v} {};
+ float method(int x, float y) const { return y + (float) (x + value); }
int value = 0;
};
py::class_<VectorizeTestClass> vtc(m, "VectorizeTestClass");
- vtc .def(py::init<int>())
- .def_readwrite("value", &VectorizeTestClass::value);
+ vtc.def(py::init<int>()).def_readwrite("value", &VectorizeTestClass::value);
// Automatic vectorizing of methods
vtc.def("method", py::vectorize(&VectorizeTestClass::method));
@@ -78,16 +92,16 @@ TEST_SUBMODULE(numpy_vectorize, m) {
.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
- ) {
- py::ssize_t ndim;
- std::vector<py::ssize_t> shape;
- std::array<py::buffer_info, 3> buffers {{ arg1.request(), arg2.request(), arg3.request() }};
- return py::detail::broadcast(buffers, ndim, shape);
- });
+ m.def("vectorized_is_trivial",
+ [](const py::array_t<int, py::array::forcecast> &arg1,
+ const py::array_t<float, py::array::forcecast> &arg2,
+ const py::array_t<double, py::array::forcecast> &arg3) {
+ py::ssize_t ndim = 0;
+ std::vector<py::ssize_t> shape;
+ std::array<py::buffer_info, 3> buffers{
+ {arg1.request(), arg2.request(), arg3.request()}};
+ return py::detail::broadcast(buffers, ndim, shape);
+ });
- m.def("add_to", py::vectorize([](NonPODClass& x, int a) { x.value += a; }));
+ m.def("add_to", py::vectorize([](NonPODClass &x, int a) { x.value += a; }));
}
diff --git a/3rdparty/pybind11/tests/test_numpy_vectorize.py b/3rdparty/pybind11/tests/test_numpy_vectorize.py
index 4e6b2d19..7e8c015c 100644
--- a/3rdparty/pybind11/tests/test_numpy_vectorize.py
+++ b/3rdparty/pybind11/tests/test_numpy_vectorize.py
@@ -1,5 +1,5 @@
-# -*- coding: utf-8 -*-
import pytest
+
from pybind11_tests import numpy_vectorize as m
np = pytest.importorskip("numpy")
diff --git a/3rdparty/pybind11/tests/test_opaque_types.cpp b/3rdparty/pybind11/tests/test_opaque_types.cpp
index 5a234316..0386dba0 100644
--- a/3rdparty/pybind11/tests/test_opaque_types.cpp
+++ b/3rdparty/pybind11/tests/test_opaque_types.cpp
@@ -7,8 +7,10 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
#include <pybind11/stl.h>
+
+#include "pybind11_tests.h"
+
#include <vector>
// IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures
@@ -26,12 +28,13 @@ TEST_SUBMODULE(opaque_types, m) {
.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("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>());
+ .def(
+ "__iter__",
+ [](StringList &v) { return py::make_iterator(v.begin(), v.end()); },
+ py::keep_alive<0, 1>());
class ClassWithSTLVecProperty {
public:
@@ -44,9 +47,10 @@ TEST_SUBMODULE(opaque_types, m) {
m.def("print_opaque_list", [](const StringList &l) {
std::string ret = "Opaque list: [";
bool first = true;
- for (auto entry : l) {
- if (!first)
+ for (const auto &entry : l) {
+ if (!first) {
ret += ", ";
+ }
ret += entry;
first = false;
}
diff --git a/3rdparty/pybind11/tests/test_opaque_types.py b/3rdparty/pybind11/tests/test_opaque_types.py
index 77379463..5d4f2a1b 100644
--- a/3rdparty/pybind11/tests/test_opaque_types.py
+++ b/3rdparty/pybind11/tests/test_opaque_types.py
@@ -1,7 +1,7 @@
-# -*- coding: utf-8 -*-
import pytest
-from pybind11_tests import opaque_types as m
+
from pybind11_tests import ConstructorStats, UserType
+from pybind11_tests import opaque_types as m
def test_string_list():
@@ -12,7 +12,7 @@ def test_string_list():
assert lst.back() == "Element 2"
for i, k in enumerate(lst, start=1):
- assert k == "Element {}".format(i)
+ assert k == f"Element {i}"
lst.pop_back()
assert m.print_opaque_list(lst) == "Opaque list: [Element 1]"
@@ -39,7 +39,7 @@ def test_pointers(msg):
1. (arg0: capsule) -> int
Invoked with: [1, 2, 3]
- """ # noqa: E501 line too long
+ """
)
assert m.return_null_str() is None
diff --git a/3rdparty/pybind11/tests/test_operator_overloading.cpp b/3rdparty/pybind11/tests/test_operator_overloading.cpp
index 0a27bfd5..a4b895a8 100644
--- a/3rdparty/pybind11/tests/test_operator_overloading.cpp
+++ b/3rdparty/pybind11/tests/test_operator_overloading.cpp
@@ -7,21 +7,40 @@
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>
+
+#include "constructor_stats.h"
+#include "pybind11_tests.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(Vector2 &&v) noexcept : 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) noexcept {
+ 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) + "]"; }
+ 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); }
@@ -32,71 +51,104 @@ public:
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; }
+ 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); }
- bool operator==(const Vector2 &v) const {
- return x == v.x && y == v.y;
- }
- bool operator!=(const Vector2 &v) const {
- return x != v.x || y != v.y;
- }
+ bool operator==(const Vector2 &v) const { return x == v.x && y == v.y; }
+ bool operator!=(const Vector2 &v) const { return x != v.x || y != v.y; }
+
private:
float x, y;
};
-class C1 { };
-class C2 { };
+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; }
+struct HashMe {
+ std::string member;
+};
+
+bool operator==(const HashMe &lhs, const HashMe &rhs) { return lhs.member == rhs.member; }
+
// Note: Specializing explicit within `namespace std { ... }` is done due to a
// bug in GCC<7. If you are supporting compilers later than this, consider
// specializing `using template<> struct std::hash<...>` in the global
// namespace instead, per this recommendation:
// https://en.cppreference.com/w/cpp/language/extending_std#Adding_template_specializations
namespace std {
- template<>
- struct hash<Vector2> {
- // Not a good hash function, but easy to test
- size_t operator()(const Vector2 &) { return 4; }
- };
+template <>
+struct hash<Vector2> {
+ // Not a good hash function, but easy to test
+ size_t operator()(const Vector2 &) { return 4; }
+};
+
+// HashMe has a hash function in C++ but no `__hash__` for Python.
+template <>
+struct hash<HashMe> {
+ std::size_t operator()(const HashMe &selector) const {
+ return std::hash<std::string>()(selector.member);
+ }
+};
} // namespace std
// Not a good abs function, but easy to test.
-std::string abs(const Vector2&) {
- return "abs(Vector2)";
-}
+std::string abs(const Vector2 &) { return "abs(Vector2)"; }
-// 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 defined(__APPLE__) && defined(__clang__)
- #if (__clang_major__ >= 10)
- #pragma GCC diagnostic ignored "-Wself-assign-overloaded"
- #endif
- #elif defined(__clang__)
- #if (__clang_major__ >= 7)
- #pragma GCC diagnostic ignored "-Wself-assign-overloaded"
- #endif
- #endif
+// MSVC & Intel warns about unknown pragmas, and warnings are errors.
+#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+# 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 defined(__APPLE__) && defined(__clang__)
+# if (__clang_major__ >= 10)
+# pragma GCC diagnostic ignored "-Wself-assign-overloaded"
+# endif
+# elif defined(__clang__)
+# if (__clang_major__ >= 7)
+# pragma GCC diagnostic ignored "-Wself-assign-overloaded"
+# endif
+# endif
#endif
TEST_SUBMODULE(operators, m) {
@@ -130,46 +182,52 @@ TEST_SUBMODULE(operators, m) {
.def(py::hash(py::self))
// N.B. See warning about usage of `py::detail::abs(py::self)` in
// `operators.h`.
- .def("__abs__", [](const Vector2& v) { return abs(v); })
- ;
+ .def("__abs__", [](const Vector2 &v) { return abs(v); });
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_<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; });
+ .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; };
+ 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; }
+ 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);
+ .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; }
+ NestB &operator-=(int i) {
+ value -= i;
+ return *this;
+ }
};
py::class_<NestB>(m, "NestB")
.def(py::init<>())
@@ -180,7 +238,10 @@ TEST_SUBMODULE(operators, m) {
struct NestC {
NestB b;
int value = 5;
- NestC& operator*=(int i) { value *= i; return *this; }
+ NestC &operator*=(int i) {
+ value *= i;
+ return *this;
+ }
};
py::class_<NestC>(m, "NestC")
.def(py::init<>())
@@ -188,16 +249,15 @@ TEST_SUBMODULE(operators, m) {
.def_readwrite("b", &NestC::b);
m.def("get_NestC", [](const NestC &c) { return c.value; });
-
// test_overriding_eq_reset_hash
// #2191 Overriding __eq__ should set __hash__ to None
struct Comparable {
int value;
- bool operator==(const Comparable& rhs) const {return value == rhs.value;}
+ bool operator==(const Comparable &rhs) const { return value == rhs.value; }
};
struct Hashable : Comparable {
- explicit Hashable(int value): Comparable{value}{};
+ explicit Hashable(int value) : Comparable{value} {};
size_t hash() const { return static_cast<size_t>(value); }
};
@@ -205,9 +265,7 @@ TEST_SUBMODULE(operators, m) {
using Hashable::Hashable;
};
- py::class_<Comparable>(m, "Comparable")
- .def(py::init<int>())
- .def(py::self == py::self);
+ py::class_<Comparable>(m, "Comparable").def(py::init<int>()).def(py::self == py::self);
py::class_<Hashable>(m, "Hashable")
.def(py::init<int>())
@@ -219,8 +277,12 @@ TEST_SUBMODULE(operators, m) {
.def("__hash__", &Hashable::hash)
.def(py::init<int>())
.def(py::self == py::self);
-}
-#ifndef _MSC_VER
- #pragma GCC diagnostic pop
+ // define __eq__ but not __hash__
+ py::class_<HashMe>(m, "HashMe").def(py::self == py::self);
+
+ m.def("get_unhashable_HashMe_set", []() { return std::unordered_set<HashMe>{{"one"}}; });
+}
+#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+# pragma GCC diagnostic pop
#endif
diff --git a/3rdparty/pybind11/tests/test_operator_overloading.py b/3rdparty/pybind11/tests/test_operator_overloading.py
index 5dbfb32c..b228da3c 100644
--- a/3rdparty/pybind11/tests/test_operator_overloading.py
+++ b/3rdparty/pybind11/tests/test_operator_overloading.py
@@ -1,7 +1,7 @@
-# -*- coding: utf-8 -*-
import pytest
-from pybind11_tests import operators as m
+
from pybind11_tests import ConstructorStats
+from pybind11_tests import operators as m
def test_operator_overloading():
@@ -134,8 +134,9 @@ def test_overriding_eq_reset_hash():
assert m.Comparable(15) is not m.Comparable(15)
assert m.Comparable(15) == m.Comparable(15)
- with pytest.raises(TypeError):
- hash(m.Comparable(15)) # TypeError: unhashable type: 'm.Comparable'
+ with pytest.raises(TypeError) as excinfo:
+ hash(m.Comparable(15))
+ assert str(excinfo.value).startswith("unhashable type:")
for hashable in (m.Hashable, m.Hashable2):
assert hashable(15) is not hashable(15)
@@ -143,3 +144,9 @@ def test_overriding_eq_reset_hash():
assert hash(hashable(15)) == 15
assert hash(hashable(15)) == hash(hashable(15))
+
+
+def test_return_set_of_unhashable():
+ with pytest.raises(TypeError) as excinfo:
+ m.get_unhashable_HashMe_set()
+ assert str(excinfo.value.__cause__).startswith("unhashable type:")
diff --git a/3rdparty/pybind11/tests/test_pickling.cpp b/3rdparty/pybind11/tests/test_pickling.cpp
index 9dc63bda..e154bc48 100644
--- a/3rdparty/pybind11/tests/test_pickling.cpp
+++ b/3rdparty/pybind11/tests/test_pickling.cpp
@@ -2,6 +2,7 @@
tests/test_pickling.cpp -- pickle support
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+ Copyright (c) 2021 The Pybind Development Team.
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
@@ -9,17 +10,70 @@
#include "pybind11_tests.h"
+#include <memory>
+#include <stdexcept>
+#include <utility>
+
+namespace exercise_trampoline {
+
+struct SimpleBase {
+ int num = 0;
+ virtual ~SimpleBase() = default;
+
+ // For compatibility with old clang versions:
+ SimpleBase() = default;
+ SimpleBase(const SimpleBase &) = default;
+};
+
+struct SimpleBaseTrampoline : SimpleBase {};
+
+struct SimpleCppDerived : SimpleBase {};
+
+void wrap(py::module m) {
+ py::class_<SimpleBase, SimpleBaseTrampoline>(m, "SimpleBase")
+ .def(py::init<>())
+ .def_readwrite("num", &SimpleBase::num)
+ .def(py::pickle(
+ [](const py::object &self) {
+ py::dict d;
+ if (py::hasattr(self, "__dict__")) {
+ d = self.attr("__dict__");
+ }
+ return py::make_tuple(self.attr("num"), d);
+ },
+ [](const py::tuple &t) {
+ if (t.size() != 2) {
+ throw std::runtime_error("Invalid state!");
+ }
+ auto cpp_state = std::unique_ptr<SimpleBase>(new SimpleBaseTrampoline);
+ cpp_state->num = t[0].cast<int>();
+ auto py_state = t[1].cast<py::dict>();
+ return std::make_pair(std::move(cpp_state), py_state);
+ }));
+
+ m.def("make_SimpleCppDerivedAsBase",
+ []() { return std::unique_ptr<SimpleBase>(new SimpleCppDerived); });
+ m.def("check_dynamic_cast_SimpleCppDerived", [](const SimpleBase *base_ptr) {
+ return dynamic_cast<const SimpleCppDerived *>(base_ptr) != nullptr;
+ });
+}
+
+} // namespace exercise_trampoline
+
TEST_SUBMODULE(pickling, m) {
+ m.def("simple_callable", []() { return 20220426; });
+
// test_roundtrip
class Pickleable {
public:
- Pickleable(const std::string &value) : m_value(value) { }
+ explicit 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;
@@ -31,8 +85,8 @@ TEST_SUBMODULE(pickling, m) {
using Pickleable::Pickleable;
};
- py::class_<Pickleable>(m, "Pickleable")
- .def(py::init<std::string>())
+ py::class_<Pickleable> pyPickleable(m, "Pickleable");
+ pyPickleable.def(py::init<std::string>())
.def("value", &Pickleable::value)
.def("extra1", &Pickleable::extra1)
.def("extra2", &Pickleable::extra2)
@@ -43,10 +97,12 @@ TEST_SUBMODULE(pickling, m) {
.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)
+ });
+ ignoreOldStyleInitWarnings([&pyPickleable]() {
+ pyPickleable.def("__setstate__", [](Pickleable &p, const 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>());
@@ -54,6 +110,7 @@ TEST_SUBMODULE(pickling, m) {
p.setExtra1(t[1].cast<int>());
p.setExtra2(t[2].cast<int>());
});
+ });
py::class_<PickleableNew, Pickleable>(m, "PickleableNew")
.def(py::init<std::string>())
@@ -61,22 +118,22 @@ TEST_SUBMODULE(pickling, m) {
[](const PickleableNew &p) {
return py::make_tuple(p.value(), p.extra1(), p.extra2());
},
- [](py::tuple t) {
- if (t.size() != 3)
+ [](const 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) { }
+ explicit PickleableWithDict(const std::string &value) : value(value) {}
std::string value;
int extra;
@@ -87,19 +144,22 @@ TEST_SUBMODULE(pickling, m) {
using PickleableWithDict::PickleableWithDict;
};
- py::class_<PickleableWithDict>(m, "PickleableWithDict", py::dynamic_attr())
- .def(py::init<std::string>())
+ py::class_<PickleableWithDict> pyPickleableWithDict(
+ m, "PickleableWithDict", py::dynamic_attr());
+ pyPickleableWithDict.def(py::init<std::string>())
.def_readwrite("value", &PickleableWithDict::value)
.def_readwrite("extra", &PickleableWithDict::extra)
- .def("__getstate__", [](py::object self) {
+ .def("__getstate__", [](const 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)
+ });
+ ignoreOldStyleInitWarnings([&pyPickleableWithDict]() {
+ pyPickleableWithDict.def("__setstate__", [](const py::object &self, const py::tuple &t) {
+ if (t.size() != 3) {
throw std::runtime_error("Invalid state!");
+ }
/* Cast and construct */
- auto& p = self.cast<PickleableWithDict&>();
+ auto &p = self.cast<PickleableWithDict &>();
new (&p) PickleableWithDict(t[0].cast<std::string>());
/* Assign C++ state */
@@ -108,23 +168,27 @@ TEST_SUBMODULE(pickling, m) {
/* 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::object &self) {
+ return py::make_tuple(
+ self.attr("value"), self.attr("extra"), self.attr("__dict__"));
},
[](const py::tuple &t) {
- if (t.size() != 3)
+ 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
+
+ exercise_trampoline::wrap(m);
}
diff --git a/3rdparty/pybind11/tests/test_pickling.py b/3rdparty/pybind11/tests/test_pickling.py
index 6b27a73a..12361a66 100644
--- a/3rdparty/pybind11/tests/test_pickling.py
+++ b/3rdparty/pybind11/tests/test_pickling.py
@@ -1,14 +1,24 @@
-# -*- coding: utf-8 -*-
-import pytest
+import pickle
+import re
-import env # noqa: F401
+import pytest
+import env
from pybind11_tests import pickling as m
-try:
- import cPickle as pickle # Use cPickle on Python 2.7
-except ImportError:
- import pickle
+
+def test_pickle_simple_callable():
+ assert m.simple_callable() == 20220426
+ if env.PYPY:
+ serialized = pickle.dumps(m.simple_callable)
+ deserialized = pickle.loads(serialized)
+ assert deserialized() == 20220426
+ else:
+ # To document broken behavior: currently it fails universally with
+ # all C Python versions.
+ with pytest.raises(TypeError) as excinfo:
+ pickle.dumps(m.simple_callable)
+ assert re.search("can.*t pickle .*PyCapsule.* object", str(excinfo.value))
@pytest.mark.parametrize("cls_name", ["Pickleable", "PickleableNew"])
@@ -45,3 +55,39 @@ def test_enum_pickle():
data = pickle.dumps(e.EOne, 2)
assert e.EOne == pickle.loads(data)
+
+
+#
+# exercise_trampoline
+#
+class SimplePyDerived(m.SimpleBase):
+ pass
+
+
+def test_roundtrip_simple_py_derived():
+ p = SimplePyDerived()
+ p.num = 202
+ p.stored_in_dict = 303
+ data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL)
+ p2 = pickle.loads(data)
+ assert isinstance(p2, SimplePyDerived)
+ assert p2.num == 202
+ assert p2.stored_in_dict == 303
+
+
+def test_roundtrip_simple_cpp_derived():
+ p = m.make_SimpleCppDerivedAsBase()
+ assert m.check_dynamic_cast_SimpleCppDerived(p)
+ p.num = 404
+ if not env.PYPY:
+ # To ensure that this unit test is not accidentally invalidated.
+ with pytest.raises(AttributeError):
+ # Mimics the `setstate` C++ implementation.
+ setattr(p, "__dict__", {}) # noqa: B010
+ data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL)
+ p2 = pickle.loads(data)
+ assert isinstance(p2, m.SimpleBase)
+ assert p2.num == 404
+ # Issue #3062: pickleable base C++ classes can incur object slicing
+ # if derived typeid is not registered with pybind11
+ assert not m.check_dynamic_cast_SimpleCppDerived(p2)
diff --git a/3rdparty/pybind11/tests/test_pytypes.cpp b/3rdparty/pybind11/tests/test_pytypes.cpp
index 113cf5cb..da0dc8f6 100644
--- a/3rdparty/pybind11/tests/test_pytypes.cpp
+++ b/3rdparty/pybind11/tests/test_pytypes.cpp
@@ -9,15 +9,119 @@
#include "pybind11_tests.h"
+#include <utility>
+
+namespace external {
+namespace detail {
+bool check(PyObject *o) { return PyFloat_Check(o) != 0; }
+
+PyObject *conv(PyObject *o) {
+ PyObject *ret = nullptr;
+ if (PyLong_Check(o)) {
+ double v = PyLong_AsDouble(o);
+ if (!(v == -1.0 && PyErr_Occurred())) {
+ ret = PyFloat_FromDouble(v);
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Unexpected type");
+ }
+ return ret;
+}
+
+PyObject *default_constructed() { return PyFloat_FromDouble(0.0); }
+} // namespace detail
+class float_ : public py::object {
+ PYBIND11_OBJECT_CVT(float_, py::object, external::detail::check, external::detail::conv)
+
+ float_() : py::object(external::detail::default_constructed(), stolen_t{}) {}
+
+ double get_value() const { return PyFloat_AsDouble(this->ptr()); }
+};
+} // namespace external
+
+namespace implicit_conversion_from_0_to_handle {
+// Uncomment to trigger compiler error. Note: Before PR #4008 this used to compile successfully.
+// void expected_to_trigger_compiler_error() { py::handle(0); }
+} // namespace implicit_conversion_from_0_to_handle
+
+// Used to validate systematically that PR #4008 does/did NOT change the behavior.
+void pure_compile_tests_for_handle_from_PyObject_pointers() {
+ {
+ PyObject *ptr = Py_None;
+ py::handle{ptr};
+ }
+ {
+ PyObject *const ptr = Py_None;
+ py::handle{ptr};
+ }
+ // Uncomment to trigger compiler errors.
+ // PyObject const * ptr = Py_None; py::handle{ptr};
+ // PyObject const *const ptr = Py_None; py::handle{ptr};
+ // PyObject volatile * ptr = Py_None; py::handle{ptr};
+ // PyObject volatile *const ptr = Py_None; py::handle{ptr};
+ // PyObject const volatile * ptr = Py_None; py::handle{ptr};
+ // PyObject const volatile *const ptr = Py_None; py::handle{ptr};
+}
+
+namespace handle_from_move_only_type_with_operator_PyObject {
+
+// Reduced from
+// https://github.com/pytorch/pytorch/blob/279634f384662b7c3a9f8bf7ccc3a6afd2f05657/torch/csrc/utils/object_ptr.h
+struct operator_ncnst {
+ operator_ncnst() = default;
+ operator_ncnst(operator_ncnst &&) = default;
+ operator PyObject *() /* */ { return Py_None; } // NOLINT(google-explicit-constructor)
+};
+
+struct operator_const {
+ operator_const() = default;
+ operator_const(operator_const &&) = default;
+ operator PyObject *() const { return Py_None; } // NOLINT(google-explicit-constructor)
+};
+
+bool from_ncnst() {
+ operator_ncnst obj;
+ auto h = py::handle(obj); // Critical part of test: does this compile?
+ return h.ptr() == Py_None; // Just something.
+}
+
+bool from_const() {
+ operator_const obj;
+ auto h = py::handle(obj); // Critical part of test: does this compile?
+ return h.ptr() == Py_None; // Just something.
+}
+
+void m_defs(py::module_ &m) {
+ m.def("handle_from_move_only_type_with_operator_PyObject_ncnst", from_ncnst);
+ m.def("handle_from_move_only_type_with_operator_PyObject_const", from_const);
+}
+
+} // namespace handle_from_move_only_type_with_operator_PyObject
TEST_SUBMODULE(pytypes, m) {
+ handle_from_move_only_type_with_operator_PyObject::m_defs(m);
+
+ // test_bool
+ m.def("get_bool", [] { return py::bool_(false); });
// test_int
- m.def("get_int", []{return py::int_(0);});
+ m.def("get_int", [] { return py::int_(0); });
// test_iterator
- m.def("get_iterator", []{return py::iterator();});
+ m.def("get_iterator", [] { return py::iterator(); });
// test_iterable
- m.def("get_iterable", []{return py::iterable();});
+ m.def("get_iterable", [] { return py::iterable(); });
+ m.def("get_frozenset_from_iterable",
+ [](const py::iterable &iter) { return py::frozenset(iter); });
+ m.def("get_list_from_iterable", [](const py::iterable &iter) { return py::list(iter); });
+ m.def("get_set_from_iterable", [](const py::iterable &iter) { return py::set(iter); });
+ m.def("get_tuple_from_iterable", [](const py::iterable &iter) { return py::tuple(iter); });
+ // test_float
+ m.def("get_float", [] { return py::float_(0.0f); });
// test_list
+ m.def("list_no_args", []() { return py::list{}; });
+ m.def("list_ssize_t", []() { return py::list{(py::ssize_t) 0}; });
+ m.def("list_size_t", []() { return py::list{(py::size_t) 0}; });
+ m.def("list_insert_ssize_t", [](py::list *l) { return l->insert((py::ssize_t) 1, 83); });
+ m.def("list_insert_size_t", [](py::list *l) { return l->insert((py::size_t) 3, 57); });
m.def("get_list", []() {
py::list list;
list.append("value");
@@ -27,18 +131,17 @@ TEST_SUBMODULE(pytypes, m) {
list.insert(2, "inserted-2");
return list;
});
- m.def("print_list", [](py::list list) {
+ m.def("print_list", [](const py::list &list) {
int index = 0;
- for (auto item : list)
+ for (auto item : list) {
py::print("list item {}: {}"_s.format(index++, item));
+ }
});
// test_none
- m.def("get_none", []{return py::none();});
- m.def("print_none", [](py::none none) {
- py::print("none: {}"_s.format(none));
- });
+ m.def("get_none", [] { return py::none(); });
+ m.def("print_none", [](const py::none &none) { py::print("none: {}"_s.format(none)); });
- // test_set
+ // test_set, test_frozenset
m.def("get_set", []() {
py::set set;
set.add(py::str("key1"));
@@ -46,58 +149,101 @@ TEST_SUBMODULE(pytypes, m) {
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("get_frozenset", []() {
+ py::set set;
+ set.add(py::str("key1"));
+ set.add("key2");
+ set.add(std::string("key3"));
+ return py::frozenset(set);
});
- m.def("set_contains", [](py::set set, const char* key) {
- return set.contains(key);
+ m.def("print_anyset", [](const py::anyset &set) {
+ for (auto item : set) {
+ py::print("key:", item);
+ }
});
+ m.def("anyset_size", [](const py::anyset &set) { return set.size(); });
+ m.def("anyset_empty", [](const py::anyset &set) { return set.empty(); });
+ m.def("anyset_contains",
+ [](const py::anyset &set, const py::object &key) { return set.contains(key); });
+ m.def("anyset_contains",
+ [](const py::anyset &set, const char *key) { return set.contains(key); });
+ m.def("set_add", [](py::set &set, const py::object &key) { set.add(key); });
+ m.def("set_clear", [](py::set &set) { set.clear(); });
// test_dict
- m.def("get_dict", []() { return py::dict("key"_a="value"); });
- m.def("print_dict", [](py::dict dict) {
- for (auto item : dict)
+ m.def("get_dict", []() { return py::dict("key"_a = "value"); });
+ m.def("print_dict", [](const 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);
+ 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);
+ m.def("dict_contains",
+ [](const py::dict &dict, py::object val) { return dict.contains(val); });
+ m.def("dict_contains",
+ [](const py::dict &dict, const char *val) { return dict.contains(val); });
+
+ // test_tuple
+ m.def("tuple_no_args", []() { return py::tuple{}; });
+ m.def("tuple_ssize_t", []() { return py::tuple{(py::ssize_t) 0}; });
+ m.def("tuple_size_t", []() { return py::tuple{(py::size_t) 0}; });
+ m.def("get_tuple", []() { return py::make_tuple(42, py::none(), "spam"); });
+
+ // test_simple_namespace
+ m.def("get_simple_namespace", []() {
+ auto ns = py::module_::import("types").attr("SimpleNamespace")(
+ "attr"_a = 42, "x"_a = "foo", "wrong"_a = 1);
+ py::delattr(ns, "wrong");
+ py::setattr(ns, "right", py::int_(2));
+ return ns;
});
// test_str
+ m.def("str_from_char_ssize_t", []() { return py::str{"red", (py::ssize_t) 3}; });
+ m.def("str_from_char_size_t", []() { return py::str{"blue", (py::size_t) 4}; });
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_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_from_handle", [](py::handle h) { return py::str(h); });
+ m.def("str_from_string_from_str",
+ [](const py::str &obj) { return py::str(static_cast<std::string>(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);
+ 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_char_ssize_t", []() { return py::bytes{"green", (py::ssize_t) 5}; });
+ m.def("bytes_from_char_size_t", []() { return py::bytes{"purple", (py::size_t) 6}; });
m.def("bytes_from_string", []() { return py::bytes(std::string("foo")); });
m.def("bytes_from_str", []() { return py::bytes(py::str("bar", 3)); });
+ // test bytearray
+ m.def("bytearray_from_char_ssize_t", []() { return py::bytearray{"$%", (py::ssize_t) 2}; });
+ m.def("bytearray_from_char_size_t", []() { return py::bytearray{"@$!", (py::size_t) 3}; });
+ m.def("bytearray_from_string", []() { return py::bytearray(std::string("foo")); });
+ m.def("bytearray_size", []() { return py::bytearray("foo").size(); });
+
// test_capsule
m.def("return_capsule_with_destructor", []() {
py::print("creating capsule");
- return py::capsule([]() {
- py::print("destructing capsule");
- });
+ return py::capsule([]() { py::print("destructing capsule"); });
+ });
+
+ m.def("return_renamed_capsule_with_destructor", []() {
+ py::print("creating capsule");
+ auto cap = py::capsule([]() { py::print("destructing capsule"); });
+ static const char *capsule_name = "test_name1";
+ py::print("renaming capsule");
+ cap.set_name(capsule_name);
+ return cap;
});
m.def("return_capsule_with_destructor_2", []() {
@@ -107,33 +253,44 @@ TEST_SUBMODULE(pytypes, m) {
});
});
+ m.def("return_renamed_capsule_with_destructor_2", []() {
+ py::print("creating capsule");
+ auto cap = py::capsule((void *) 1234, [](void *ptr) {
+ py::print("destructing capsule: {}"_s.format((size_t) ptr));
+ });
+ static const char *capsule_name = "test_name2";
+ py::print("renaming capsule");
+ cap.set_name(capsule_name);
+ return cap;
+ });
+
m.def("return_capsule_with_name_and_destructor", []() {
auto capsule = py::capsule((void *) 12345, "pointer type description", [](PyObject *ptr) {
if (ptr) {
- auto name = PyCapsule_GetName(ptr);
+ const auto *name = PyCapsule_GetName(ptr);
py::print("destructing capsule ({}, '{}')"_s.format(
- (size_t) PyCapsule_GetPointer(ptr, name), name
- ));
+ (size_t) PyCapsule_GetPointer(ptr, name), name));
}
});
capsule.set_pointer((void *) 1234);
// Using get_pointer<T>()
- void* contents1 = static_cast<void*>(capsule);
- void* contents2 = capsule.get_pointer();
- void* contents3 = capsule.get_pointer<void>();
+ void *contents1 = static_cast<void *>(capsule);
+ void *contents2 = capsule.get_pointer();
+ void *contents3 = capsule.get_pointer<void>();
auto result1 = reinterpret_cast<size_t>(contents1);
auto result2 = reinterpret_cast<size_t>(contents2);
auto result3 = reinterpret_cast<size_t>(contents3);
- py::print("created capsule ({}, '{}')"_s.format(result1 & result2 & result3, capsule.name()));
+ py::print(
+ "created capsule ({}, '{}')"_s.format(result1 & result2 & result3, capsule.name()));
return capsule;
});
// test_accessors
- m.def("accessor_api", [](py::object o) {
+ m.def("accessor_api", [](const py::object &o) {
auto d = py::dict();
d["basic_attr"] = o.attr("basic_attr");
@@ -174,7 +331,7 @@ TEST_SUBMODULE(pytypes, m) {
return d;
});
- m.def("tuple_accessor", [](py::tuple existing_t) {
+ m.def("tuple_accessor", [](const py::tuple &existing_t) {
try {
existing_t[0] = 1;
} catch (const py::error_already_set &) {
@@ -206,66 +363,118 @@ TEST_SUBMODULE(pytypes, m) {
return d;
});
+ m.def("accessor_moves", []() { // See PR #3970
+ py::list return_list;
+#ifdef PYBIND11_HANDLE_REF_DEBUG
+ py::int_ py_int_0(0);
+ py::int_ py_int_42(42);
+ py::str py_str_count("count");
+
+ auto tup = py::make_tuple(0);
+
+ py::sequence seq(tup);
+
+ py::list lst;
+ lst.append(0);
+
+# define PYBIND11_LOCAL_DEF(...) \
+ { \
+ std::size_t inc_refs = py::handle::inc_ref_counter(); \
+ __VA_ARGS__; \
+ inc_refs = py::handle::inc_ref_counter() - inc_refs; \
+ return_list.append(inc_refs); \
+ }
+
+ PYBIND11_LOCAL_DEF(tup[py_int_0]) // l-value (to have a control)
+ PYBIND11_LOCAL_DEF(tup[py::int_(0)]) // r-value
+
+ PYBIND11_LOCAL_DEF(tup.attr(py_str_count)) // l-value
+ PYBIND11_LOCAL_DEF(tup.attr(py::str("count"))) // r-value
+
+ PYBIND11_LOCAL_DEF(seq[py_int_0]) // l-value
+ PYBIND11_LOCAL_DEF(seq[py::int_(0)]) // r-value
+
+ PYBIND11_LOCAL_DEF(seq.attr(py_str_count)) // l-value
+ PYBIND11_LOCAL_DEF(seq.attr(py::str("count"))) // r-value
+
+ PYBIND11_LOCAL_DEF(lst[py_int_0]) // l-value
+ PYBIND11_LOCAL_DEF(lst[py::int_(0)]) // r-value
+
+ PYBIND11_LOCAL_DEF(lst.attr(py_str_count)) // l-value
+ PYBIND11_LOCAL_DEF(lst.attr(py::str("count"))) // r-value
+
+ auto lst_acc = lst[py::int_(0)];
+ lst_acc = py::int_(42); // Detaches lst_acc from lst.
+ PYBIND11_LOCAL_DEF(lst_acc = py_int_42) // l-value
+ PYBIND11_LOCAL_DEF(lst_acc = py::int_(42)) // r-value
+# undef PYBIND11_LOCAL_DEF
+#endif
+ return return_list;
+ });
+
// test_constructors
m.def("default_constructors", []() {
- return py::dict(
- "bytes"_a=py::bytes(),
- "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(
- "bytes"_a=py::bytes(d["bytes"]),
- "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) {
+ return py::dict("bytes"_a = py::bytes(),
+ "bytearray"_a = py::bytearray(),
+ "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", [](const py::dict &d) {
+ return py::dict("bytes"_a = py::bytes(d["bytes"]),
+ "bytearray"_a = py::bytearray(d["bytearray"]),
+ "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"]),
+ "frozenset"_a = py::frozenset(d["frozenset"]),
+ "memoryview"_a = py::memoryview(d["memoryview"]));
+ });
+
+ m.def("cast_functions", [](const py::dict &d) {
// When converting between Python types, obj.cast<T>() should be the same as T(obj)
- return py::dict(
- "bytes"_a=d["bytes"].cast<py::bytes>(),
- "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("convert_to_pybind11_str", [](py::object o) { return py::str(o); });
-
- m.def("nonconverting_constructor", [](std::string type, py::object value) -> py::object {
- if (type == "bytes") {
- return py::bytes(value);
- }
- else if (type == "none") {
- return py::none(value);
- }
- else if (type == "ellipsis") {
- return py::ellipsis(value);
- }
- throw std::runtime_error("Invalid type");
- });
+ return py::dict("bytes"_a = d["bytes"].cast<py::bytes>(),
+ "bytearray"_a = d["bytearray"].cast<py::bytearray>(),
+ "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>(),
+ "frozenset"_a = d["frozenset"].cast<py::frozenset>(),
+ "memoryview"_a = d["memoryview"].cast<py::memoryview>());
+ });
+
+ m.def("convert_to_pybind11_str", [](const py::object &o) { return py::str(o); });
+
+ m.def("nonconverting_constructor",
+ [](const std::string &type, py::object value, bool move) -> py::object {
+ if (type == "bytes") {
+ return move ? py::bytes(std::move(value)) : py::bytes(value);
+ }
+ if (type == "none") {
+ return move ? py::none(std::move(value)) : py::none(value);
+ }
+ if (type == "ellipsis") {
+ return move ? py::ellipsis(std::move(value)) : py::ellipsis(value);
+ }
+ if (type == "type") {
+ return move ? py::type(std::move(value)) : py::type(value);
+ }
+ throw std::runtime_error("Invalid type");
+ });
m.def("get_implicit_casting", []() {
py::dict d;
@@ -298,10 +507,7 @@ TEST_SUBMODULE(pytypes, m) {
l.append(py::cast(12));
l.append(py::int_(15));
- return py::dict(
- "d"_a=d,
- "l"_a=l
- );
+ return py::dict("d"_a = d, "l"_a = l);
});
// test_print
@@ -309,23 +515,24 @@ TEST_SUBMODULE(pytypes, m) {
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("*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("this goes to stderr", "file"_a = py_stderr);
- py::print("flush", "flush"_a=true);
+ py::print("flush", "flush"_a = true);
- py::print("{a} + {b} = {c}"_s.format("a"_a="py::print", "b"_a="str.format", "c"_a="this"));
+ 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("hash_function", [](py::object obj) { return py::hash(std::move(obj)); });
- m.def("test_number_protocol", [](py::object a, py::object b) {
+ m.def("test_number_protocol", [](const py::object &a, const py::object &b) {
py::list l;
l.append(a.equal(b));
l.append(a.not_equal(b));
@@ -345,9 +552,7 @@ TEST_SUBMODULE(pytypes, m) {
return l;
});
- m.def("test_list_slicing", [](py::list a) {
- return a[py::slice(0, -1, 2)];
- });
+ m.def("test_list_slicing", [](const py::list &a) { return a[py::slice(0, -1, 2)]; });
// See #2361
m.def("issue2361_str_implicit_copy_none", []() {
@@ -359,55 +564,235 @@ TEST_SUBMODULE(pytypes, m) {
return is_this_none;
});
- m.def("test_memoryview_object", [](py::buffer b) {
- return py::memoryview(b);
- });
+ m.def("test_memoryview_object", [](const py::buffer &b) { return py::memoryview(b); });
- m.def("test_memoryview_buffer_info", [](py::buffer b) {
- return py::memoryview(b.request());
- });
+ m.def("test_memoryview_buffer_info",
+ [](const py::buffer &b) { return py::memoryview(b.request()); });
m.def("test_memoryview_from_buffer", [](bool is_unsigned) {
- static const int16_t si16[] = { 3, 1, 4, 1, 5 };
- static const uint16_t ui16[] = { 2, 7, 1, 8 };
- if (is_unsigned)
- return py::memoryview::from_buffer(
- ui16, { 4 }, { sizeof(uint16_t) });
- else
- return py::memoryview::from_buffer(
- si16, { 5 }, { sizeof(int16_t) });
+ static const int16_t si16[] = {3, 1, 4, 1, 5};
+ static const uint16_t ui16[] = {2, 7, 1, 8};
+ if (is_unsigned) {
+ return py::memoryview::from_buffer(ui16, {4}, {sizeof(uint16_t)});
+ }
+ return py::memoryview::from_buffer(si16, {5}, {sizeof(int16_t)});
});
m.def("test_memoryview_from_buffer_nativeformat", []() {
- static const char* format = "@i";
- static const int32_t arr[] = { 4, 7, 5 };
- return py::memoryview::from_buffer(
- arr, sizeof(int32_t), format, { 3 }, { sizeof(int32_t) });
+ static const char *format = "@i";
+ static const int32_t arr[] = {4, 7, 5};
+ return py::memoryview::from_buffer(arr, sizeof(int32_t), format, {3}, {sizeof(int32_t)});
});
m.def("test_memoryview_from_buffer_empty_shape", []() {
- static const char* buf = "";
- return py::memoryview::from_buffer(buf, 1, "B", { }, { });
+ static const char *buf = "";
+ return py::memoryview::from_buffer(buf, 1, "B", {}, {});
});
m.def("test_memoryview_from_buffer_invalid_strides", []() {
- static const char* buf = "\x02\x03\x04";
- return py::memoryview::from_buffer(buf, 1, "B", { 3 }, { });
+ static const char *buf = "\x02\x03\x04";
+ return py::memoryview::from_buffer(buf, 1, "B", {3}, {});
});
m.def("test_memoryview_from_buffer_nullptr", []() {
- return py::memoryview::from_buffer(
- static_cast<void*>(nullptr), 1, "B", { }, { });
+ return py::memoryview::from_buffer(static_cast<void *>(nullptr), 1, "B", {}, {});
});
-#if PY_MAJOR_VERSION >= 3
m.def("test_memoryview_from_memory", []() {
- const char* buf = "\xff\xe1\xab\x37";
- return py::memoryview::from_memory(
- buf, static_cast<py::ssize_t>(strlen(buf)));
+ const char *buf = "\xff\xe1\xab\x37";
+ return py::memoryview::from_memory(buf, static_cast<py::ssize_t>(strlen(buf)));
});
-#endif
// test_builtin_functions
m.def("get_len", [](py::handle h) { return py::len(h); });
+
+#ifdef PYBIND11_STR_LEGACY_PERMISSIVE
+ m.attr("PYBIND11_STR_LEGACY_PERMISSIVE") = true;
+#endif
+
+ m.def("isinstance_pybind11_bytes",
+ [](py::object o) { return py::isinstance<py::bytes>(std::move(o)); });
+ m.def("isinstance_pybind11_str",
+ [](py::object o) { return py::isinstance<py::str>(std::move(o)); });
+
+ m.def("pass_to_pybind11_bytes", [](py::bytes b) { return py::len(std::move(b)); });
+ m.def("pass_to_pybind11_str", [](py::str s) { return py::len(std::move(s)); });
+ m.def("pass_to_std_string", [](const std::string &s) { return s.size(); });
+
+ // test_weakref
+ m.def("weakref_from_handle", [](py::handle h) { return py::weakref(h); });
+ m.def("weakref_from_handle_and_function",
+ [](py::handle h, py::function f) { return py::weakref(h, std::move(f)); });
+ m.def("weakref_from_object", [](const py::object &o) { return py::weakref(o); });
+ m.def("weakref_from_object_and_function",
+ [](py::object o, py::function f) { return py::weakref(std::move(o), std::move(f)); });
+
+// See PR #3263 for background (https://github.com/pybind/pybind11/pull/3263):
+// pytypes.h could be changed to enforce the "most correct" user code below, by removing
+// `const` from iterator `reference` using type aliases, but that will break existing
+// user code.
+#if (defined(__APPLE__) && defined(__clang__)) || defined(PYPY_VERSION)
+// This is "most correct" and enforced on these platforms.
+# define PYBIND11_AUTO_IT auto it
+#else
+// This works on many platforms and is (unfortunately) reflective of existing user code.
+// NOLINTNEXTLINE(bugprone-macro-parentheses)
+# define PYBIND11_AUTO_IT auto &it
+#endif
+
+ m.def("tuple_iterator", []() {
+ auto tup = py::make_tuple(5, 7);
+ int tup_sum = 0;
+ for (PYBIND11_AUTO_IT : tup) {
+ tup_sum += it.cast<int>();
+ }
+ return tup_sum;
+ });
+
+ m.def("dict_iterator", []() {
+ py::dict dct;
+ dct[py::int_(3)] = 5;
+ dct[py::int_(7)] = 11;
+ int kv_sum = 0;
+ for (PYBIND11_AUTO_IT : dct) {
+ kv_sum += it.first.cast<int>() * 100 + it.second.cast<int>();
+ }
+ return kv_sum;
+ });
+
+ m.def("passed_iterator", [](const py::iterator &py_it) {
+ int elem_sum = 0;
+ for (PYBIND11_AUTO_IT : py_it) {
+ elem_sum += it.cast<int>();
+ }
+ return elem_sum;
+ });
+
+#undef PYBIND11_AUTO_IT
+
+ // Tests below this line are for pybind11 IMPLEMENTATION DETAILS:
+
+ m.def("sequence_item_get_ssize_t", [](const py::object &o) {
+ return py::detail::accessor_policies::sequence_item::get(o, (py::ssize_t) 1);
+ });
+ m.def("sequence_item_set_ssize_t", [](const py::object &o) {
+ auto s = py::str{"peppa", 5};
+ py::detail::accessor_policies::sequence_item::set(o, (py::ssize_t) 1, s);
+ });
+ m.def("sequence_item_get_size_t", [](const py::object &o) {
+ return py::detail::accessor_policies::sequence_item::get(o, (py::size_t) 2);
+ });
+ m.def("sequence_item_set_size_t", [](const py::object &o) {
+ auto s = py::str{"george", 6};
+ py::detail::accessor_policies::sequence_item::set(o, (py::size_t) 2, s);
+ });
+ m.def("list_item_get_ssize_t", [](const py::object &o) {
+ return py::detail::accessor_policies::list_item::get(o, (py::ssize_t) 3);
+ });
+ m.def("list_item_set_ssize_t", [](const py::object &o) {
+ auto s = py::str{"rebecca", 7};
+ py::detail::accessor_policies::list_item::set(o, (py::ssize_t) 3, s);
+ });
+ m.def("list_item_get_size_t", [](const py::object &o) {
+ return py::detail::accessor_policies::list_item::get(o, (py::size_t) 4);
+ });
+ m.def("list_item_set_size_t", [](const py::object &o) {
+ auto s = py::str{"richard", 7};
+ py::detail::accessor_policies::list_item::set(o, (py::size_t) 4, s);
+ });
+ m.def("tuple_item_get_ssize_t", [](const py::object &o) {
+ return py::detail::accessor_policies::tuple_item::get(o, (py::ssize_t) 5);
+ });
+ m.def("tuple_item_set_ssize_t", []() {
+ auto s0 = py::str{"emely", 5};
+ auto s1 = py::str{"edmond", 6};
+ auto o = py::tuple{2};
+ py::detail::accessor_policies::tuple_item::set(o, (py::ssize_t) 0, s0);
+ py::detail::accessor_policies::tuple_item::set(o, (py::ssize_t) 1, s1);
+ return o;
+ });
+ m.def("tuple_item_get_size_t", [](const py::object &o) {
+ return py::detail::accessor_policies::tuple_item::get(o, (py::size_t) 6);
+ });
+ m.def("tuple_item_set_size_t", []() {
+ auto s0 = py::str{"candy", 5};
+ auto s1 = py::str{"cat", 3};
+ auto o = py::tuple{2};
+ py::detail::accessor_policies::tuple_item::set(o, (py::size_t) 1, s1);
+ py::detail::accessor_policies::tuple_item::set(o, (py::size_t) 0, s0);
+ return o;
+ });
+
+ m.def("square_float_", [](const external::float_ &x) -> double {
+ double v = x.get_value();
+ return v * v;
+ });
+
+ m.def("tuple_rvalue_getter", [](const py::tuple &tup) {
+ // tests accessing tuple object with rvalue int
+ for (size_t i = 0; i < tup.size(); i++) {
+ auto o = py::handle(tup[py::int_(i)]);
+ if (!o) {
+ throw py::value_error("tuple is malformed");
+ }
+ }
+ return tup;
+ });
+ m.def("list_rvalue_getter", [](const py::list &l) {
+ // tests accessing list with rvalue int
+ for (size_t i = 0; i < l.size(); i++) {
+ auto o = py::handle(l[py::int_(i)]);
+ if (!o) {
+ throw py::value_error("list is malformed");
+ }
+ }
+ return l;
+ });
+ m.def("populate_dict_rvalue", [](int population) {
+ auto d = py::dict();
+ for (int i = 0; i < population; i++) {
+ d[py::int_(i)] = py::int_(i);
+ }
+ return d;
+ });
+ m.def("populate_obj_str_attrs", [](py::object &o, int population) {
+ for (int i = 0; i < population; i++) {
+ o.attr(py::str(py::int_(i))) = py::str(py::int_(i));
+ }
+ return o;
+ });
+
+ // testing immutable object augmented assignment: #issue 3812
+ m.def("inplace_append", [](py::object &a, const py::object &b) {
+ a += b;
+ return a;
+ });
+ m.def("inplace_subtract", [](py::object &a, const py::object &b) {
+ a -= b;
+ return a;
+ });
+ m.def("inplace_multiply", [](py::object &a, const py::object &b) {
+ a *= b;
+ return a;
+ });
+ m.def("inplace_divide", [](py::object &a, const py::object &b) {
+ a /= b;
+ return a;
+ });
+ m.def("inplace_or", [](py::object &a, const py::object &b) {
+ a |= b;
+ return a;
+ });
+ m.def("inplace_and", [](py::object &a, const py::object &b) {
+ a &= b;
+ return a;
+ });
+ m.def("inplace_lshift", [](py::object &a, const py::object &b) {
+ a <<= b;
+ return a;
+ });
+ m.def("inplace_rshift", [](py::object &a, const py::object &b) {
+ a >>= b;
+ return a;
+ });
}
diff --git a/3rdparty/pybind11/tests/test_pytypes.py b/3rdparty/pybind11/tests/test_pytypes.py
index 9e5c302e..a34eaa59 100644
--- a/3rdparty/pybind11/tests/test_pytypes.py
+++ b/3rdparty/pybind11/tests/test_pytypes.py
@@ -1,12 +1,21 @@
-# -*- coding: utf-8 -*-
-from __future__ import division
-import pytest
+import contextlib
import sys
+import types
-import env # noqa: F401
+import pytest
+import env
+from pybind11_tests import detailed_error_messages_enabled
from pybind11_tests import pytypes as m
-from pybind11_tests import debug_enabled
+
+
+def test_handle_from_move_only_type_with_operator_PyObject(): # noqa: N802
+ assert m.handle_from_move_only_type_with_operator_PyObject_ncnst()
+ assert m.handle_from_move_only_type_with_operator_PyObject_const()
+
+
+def test_bool(doc):
+ assert doc(m.get_bool) == "get_bool() -> bool"
def test_int(doc):
@@ -17,11 +26,40 @@ def test_iterator(doc):
assert doc(m.get_iterator) == "get_iterator() -> Iterator"
+@pytest.mark.parametrize(
+ "pytype, from_iter_func",
+ [
+ (frozenset, m.get_frozenset_from_iterable),
+ (list, m.get_list_from_iterable),
+ (set, m.get_set_from_iterable),
+ (tuple, m.get_tuple_from_iterable),
+ ],
+)
+def test_from_iterable(pytype, from_iter_func):
+ my_iter = iter(range(10))
+ s = from_iter_func(my_iter)
+ assert type(s) == pytype
+ assert s == pytype(range(10))
+
+
def test_iterable(doc):
assert doc(m.get_iterable) == "get_iterable() -> Iterable"
+def test_float(doc):
+ assert doc(m.get_float) == "get_float() -> float"
+
+
def test_list(capture, doc):
+ assert m.list_no_args() == []
+ assert m.list_ssize_t() == []
+ assert m.list_size_t() == []
+ lins = [1, 2]
+ m.list_insert_ssize_t(lins)
+ assert lins == [1, 83, 2]
+ m.list_insert_size_t(lins)
+ assert lins == [1, 83, 2, 57]
+
with capture:
lst = m.get_list()
assert lst == ["inserted-0", "overwritten", "inserted-2"]
@@ -50,11 +88,12 @@ def test_none(capture, doc):
def test_set(capture, doc):
s = m.get_set()
+ assert isinstance(s, set)
assert s == {"key1", "key2", "key3"}
+ s.add("key4")
with capture:
- s.add("key4")
- m.print_set(s)
+ m.print_anyset(s)
assert (
capture.unordered
== """
@@ -65,12 +104,43 @@ def test_set(capture, doc):
"""
)
- assert not m.set_contains(set([]), 42)
- assert m.set_contains({42}, 42)
- assert m.set_contains({"foo"}, "foo")
+ m.set_add(s, "key5")
+ assert m.anyset_size(s) == 5
- assert doc(m.get_list) == "get_list() -> list"
- assert doc(m.print_list) == "print_list(arg0: list) -> None"
+ m.set_clear(s)
+ assert m.anyset_empty(s)
+
+ assert not m.anyset_contains(set(), 42)
+ assert m.anyset_contains({42}, 42)
+ assert m.anyset_contains({"foo"}, "foo")
+
+ assert doc(m.get_set) == "get_set() -> set"
+ assert doc(m.print_anyset) == "print_anyset(arg0: anyset) -> None"
+
+
+def test_frozenset(capture, doc):
+ s = m.get_frozenset()
+ assert isinstance(s, frozenset)
+ assert s == frozenset({"key1", "key2", "key3"})
+
+ with capture:
+ m.print_anyset(s)
+ assert (
+ capture.unordered
+ == """
+ key: key1
+ key: key2
+ key: key3
+ """
+ )
+ assert m.anyset_size(s) == 3
+ assert not m.anyset_empty(s)
+
+ assert not m.anyset_contains(frozenset(), 42)
+ assert m.anyset_contains(frozenset({42}), 42)
+ assert m.anyset_contains(frozenset({"foo"}), "foo")
+
+ assert doc(m.get_frozenset) == "get_frozenset() -> frozenset"
def test_dict(capture, doc):
@@ -98,13 +168,30 @@ def test_dict(capture, doc):
assert m.dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3}
+def test_tuple():
+ assert m.tuple_no_args() == ()
+ assert m.tuple_ssize_t() == ()
+ assert m.tuple_size_t() == ()
+ assert m.get_tuple() == (42, None, "spam")
+
+
+def test_simple_namespace():
+ ns = m.get_simple_namespace()
+ assert ns.attr == 42
+ assert ns.x == "foo"
+ assert ns.right == 2
+ assert not hasattr(ns, "wrong")
+
+
def test_str(doc):
+ assert m.str_from_char_ssize_t().encode().decode() == "red"
+ assert m.str_from_char_size_t().encode().decode() == "blue"
assert m.str_from_string().encode().decode() == "baz"
assert m.str_from_bytes().encode().decode() == "boo"
assert doc(m.str_from_bytes) == "str_from_bytes() -> str"
- class A(object):
+ class A:
def __str__(self):
return "this is a str"
@@ -120,24 +207,32 @@ def test_str(doc):
assert s1 == s2
malformed_utf8 = b"\x80"
- assert m.str_from_object(malformed_utf8) is malformed_utf8 # To be fixed; see #2380
- if env.PY2:
- # with pytest.raises(UnicodeDecodeError):
- # m.str_from_object(malformed_utf8)
- with pytest.raises(UnicodeDecodeError):
- m.str_from_handle(malformed_utf8)
+ if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
+ assert m.str_from_object(malformed_utf8) is malformed_utf8
else:
- # assert m.str_from_object(malformed_utf8) == "b'\\x80'"
- assert m.str_from_handle(malformed_utf8) == "b'\\x80'"
+ assert m.str_from_object(malformed_utf8) == "b'\\x80'"
+ assert m.str_from_handle(malformed_utf8) == "b'\\x80'"
+
+ assert m.str_from_string_from_str("this is a str") == "this is a str"
+ ucs_surrogates_str = "\udcc3"
+ with pytest.raises(UnicodeEncodeError):
+ m.str_from_string_from_str(ucs_surrogates_str)
def test_bytes(doc):
+ assert m.bytes_from_char_ssize_t().decode() == "green"
+ assert m.bytes_from_char_size_t().decode() == "purple"
assert m.bytes_from_string().decode() == "foo"
assert m.bytes_from_str().decode() == "bar"
- assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format(
- "str" if env.PY2 else "bytes"
- )
+ assert doc(m.bytes_from_str) == "bytes_from_str() -> bytes"
+
+
+def test_bytearray(doc):
+ assert m.bytearray_from_char_ssize_t().decode() == "$%"
+ assert m.bytearray_from_char_size_t().decode() == "@$!"
+ assert m.bytearray_from_string().decode() == "foo"
+ assert m.bytearray_size() == len("foo")
def test_capsule(capture):
@@ -155,6 +250,19 @@ def test_capsule(capture):
)
with capture:
+ a = m.return_renamed_capsule_with_destructor()
+ del a
+ pytest.gc_collect()
+ assert (
+ capture.unordered
+ == """
+ creating capsule
+ renaming capsule
+ destructing capsule
+ """
+ )
+
+ with capture:
a = m.return_capsule_with_destructor_2()
del a
pytest.gc_collect()
@@ -167,6 +275,19 @@ def test_capsule(capture):
)
with capture:
+ a = m.return_renamed_capsule_with_destructor_2()
+ del a
+ pytest.gc_collect()
+ assert (
+ capture.unordered
+ == """
+ creating capsule
+ renaming capsule
+ destructing capsule: 1234
+ """
+ )
+
+ with capture:
a = m.return_capsule_with_name_and_destructor()
del a
pytest.gc_collect()
@@ -218,19 +339,23 @@ def test_accessors():
assert d["var"] == 99
+def test_accessor_moves():
+ inc_refs = m.accessor_moves()
+ if inc_refs:
+ assert inc_refs == [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
+ else:
+ pytest.skip("Not defined: PYBIND11_HANDLE_REF_DEBUG")
+
+
def test_constructors():
"""C++ default and converting constructors are equivalent to type calls in Python"""
- types = [bytes, str, bool, int, float, tuple, list, dict, set]
+ types = [bytes, bytearray, str, bool, int, float, tuple, list, dict, set]
expected = {t.__name__: t() for t in types}
- if env.PY2:
- # Note that bytes.__name__ == 'str' in Python 2.
- # pybind11::str is unicode even under Python 2.
- expected["bytes"] = bytes()
- expected["str"] = unicode() # noqa: F821
assert m.default_constructors() == expected
data = {
bytes: b"41", # Currently no supported or working conversions.
+ bytearray: bytearray(b"41"),
str: 42,
bool: "Not empty",
int: "42",
@@ -239,15 +364,11 @@ def test_constructors():
list: range(3),
dict: [("two", 2), ("one", 1), ("three", 3)],
set: [4, 4, 5, 6, 6, 6],
+ frozenset: [4, 4, 5, 6, 6, 6],
memoryview: b"abc",
}
inputs = {k.__name__: v for k, v in data.items()}
expected = {k.__name__: k(v) for k, v in data.items()}
- if env.PY2: # Similar to the above. See comments above.
- inputs["bytes"] = b"41"
- inputs["str"] = 42
- expected["bytes"] = b"41"
- expected["str"] = u"42"
assert m.converting_constructors(inputs) == expected
assert m.cast_functions(inputs) == expected
@@ -268,46 +389,54 @@ def test_non_converting_constructors():
("bytes", range(10)),
("none", 42),
("ellipsis", 42),
+ ("type", 42),
]
for t, v in non_converting_test_cases:
- with pytest.raises(TypeError) as excinfo:
- m.nonconverting_constructor(t, v)
- expected_error = "Object of type '{}' is not an instance of '{}'".format(
- type(v).__name__, t
- )
- assert str(excinfo.value) == expected_error
+ for move in [True, False]:
+ with pytest.raises(TypeError) as excinfo:
+ m.nonconverting_constructor(t, v, move)
+ expected_error = (
+ f"Object of type '{type(v).__name__}' is not an instance of '{t}'"
+ )
+ assert str(excinfo.value) == expected_error
def test_pybind11_str_raw_str():
# specifically to exercise pybind11::str::raw_str
cvt = m.convert_to_pybind11_str
- assert cvt(u"Str") == u"Str"
- assert cvt(b"Bytes") == u"Bytes" if env.PY2 else "b'Bytes'"
- assert cvt(None) == u"None"
- assert cvt(False) == u"False"
- assert cvt(True) == u"True"
- assert cvt(42) == u"42"
- assert cvt(2 ** 65) == u"36893488147419103232"
- assert cvt(-1.50) == u"-1.5"
- assert cvt(()) == u"()"
- assert cvt((18,)) == u"(18,)"
- assert cvt([]) == u"[]"
- assert cvt([28]) == u"[28]"
- assert cvt({}) == u"{}"
- assert cvt({3: 4}) == u"{3: 4}"
- assert cvt(set()) == u"set([])" if env.PY2 else "set()"
- assert cvt({3, 3}) == u"set([3])" if env.PY2 else "{3}"
-
- valid_orig = u"DZ"
+ assert cvt("Str") == "Str"
+ assert cvt(b"Bytes") == "b'Bytes'"
+ assert cvt(None) == "None"
+ assert cvt(False) == "False"
+ assert cvt(True) == "True"
+ assert cvt(42) == "42"
+ assert cvt(2**65) == "36893488147419103232"
+ assert cvt(-1.50) == "-1.5"
+ assert cvt(()) == "()"
+ assert cvt((18,)) == "(18,)"
+ assert cvt([]) == "[]"
+ assert cvt([28]) == "[28]"
+ assert cvt({}) == "{}"
+ assert cvt({3: 4}) == "{3: 4}"
+ assert cvt(set()) == "set()"
+ assert cvt({3, 3}) == "{3}"
+
+ valid_orig = "DZ"
valid_utf8 = valid_orig.encode("utf-8")
valid_cvt = cvt(valid_utf8)
- assert type(valid_cvt) == bytes # Probably surprising.
- assert valid_cvt == b"\xc7\xb1"
+ if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
+ assert valid_cvt is valid_utf8
+ else:
+ assert type(valid_cvt) is str
+ assert valid_cvt == "b'\\xc7\\xb1'"
malformed_utf8 = b"\x80"
- malformed_cvt = cvt(malformed_utf8)
- assert type(malformed_cvt) == bytes # Probably surprising.
- assert malformed_cvt == b"\x80"
+ if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
+ assert cvt(malformed_utf8) is malformed_utf8
+ else:
+ malformed_cvt = cvt(malformed_utf8)
+ assert type(malformed_cvt) is str
+ assert malformed_cvt == "b'\\x80'"
def test_implicit_casting():
@@ -348,22 +477,22 @@ def test_print(capture):
with pytest.raises(RuntimeError) as excinfo:
m.print_failure()
- assert str(excinfo.value) == "make_tuple(): unable to convert " + (
- "argument of type 'UnregisteredType' to Python object"
- if debug_enabled
- else "arguments to Python object (compile in debug mode for details)"
+ assert str(excinfo.value) == "Unable to convert call argument " + (
+ "'1' of type 'UnregisteredType' to Python object"
+ if detailed_error_messages_enabled
+ else "to Python object (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"
)
def test_hash():
- class Hashable(object):
+ class Hashable:
def __init__(self, value):
self.value = value
def __hash__(self):
return self.value
- class Unhashable(object):
+ class Unhashable:
__hash__ = None
assert m.hash_function(Hashable(42)) == 42
@@ -403,7 +532,8 @@ def test_issue2361():
assert m.issue2361_str_implicit_copy_none() == "None"
with pytest.raises(TypeError) as excinfo:
assert m.issue2361_dict_implicit_copy_none()
- assert "'NoneType' object is not iterable" in str(excinfo.value)
+ assert "NoneType" in str(excinfo.value)
+ assert "iterable" in str(excinfo.value)
@pytest.mark.parametrize(
@@ -420,12 +550,7 @@ def test_memoryview(method, args, fmt, expected_view):
view = method(*args)
assert isinstance(view, memoryview)
assert view.format == fmt
- if isinstance(expected_view, bytes) or not env.PY2:
- view_as_list = list(view)
- else:
- # Using max to pick non-zero byte (big-endian vs little-endian).
- view_as_list = [max([ord(c) for c in s]) for s in view]
- assert view_as_list == list(expected_view)
+ assert list(view) == list(expected_view)
@pytest.mark.xfail("env.PYPY", reason="getrefcount is not available")
@@ -449,12 +574,7 @@ def test_memoryview_from_buffer_empty_shape():
view = m.test_memoryview_from_buffer_empty_shape()
assert isinstance(view, memoryview)
assert view.format == "B"
- if env.PY2:
- # Python 2 behavior is weird, but Python 3 (the future) is fine.
- # PyPy3 has <memoryview, while CPython 2 has <memory
- assert bytes(view).startswith(b"<memory")
- else:
- assert bytes(view) == b""
+ assert bytes(view) == b""
def test_test_memoryview_from_buffer_invalid_strides():
@@ -463,14 +583,10 @@ def test_test_memoryview_from_buffer_invalid_strides():
def test_test_memoryview_from_buffer_nullptr():
- if env.PY2:
+ with pytest.raises(ValueError):
m.test_memoryview_from_buffer_nullptr()
- else:
- with pytest.raises(ValueError):
- m.test_memoryview_from_buffer_nullptr()
-@pytest.mark.skipif("env.PY2")
def test_memoryview_from_memory():
view = m.test_memoryview_from_memory()
assert isinstance(view, memoryview)
@@ -486,3 +602,228 @@ def test_builtin_functions():
"object of type 'generator' has no len()",
"'generator' has no length",
] # PyPy
+
+
+def test_isinstance_string_types():
+ assert m.isinstance_pybind11_bytes(b"")
+ assert not m.isinstance_pybind11_bytes("")
+
+ assert m.isinstance_pybind11_str("")
+ if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
+ assert m.isinstance_pybind11_str(b"")
+ else:
+ assert not m.isinstance_pybind11_str(b"")
+
+
+def test_pass_bytes_or_unicode_to_string_types():
+ assert m.pass_to_pybind11_bytes(b"Bytes") == 5
+ with pytest.raises(TypeError):
+ m.pass_to_pybind11_bytes("Str")
+
+ if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
+ assert m.pass_to_pybind11_str(b"Bytes") == 5
+ else:
+ with pytest.raises(TypeError):
+ m.pass_to_pybind11_str(b"Bytes")
+ assert m.pass_to_pybind11_str("Str") == 3
+
+ assert m.pass_to_std_string(b"Bytes") == 5
+ assert m.pass_to_std_string("Str") == 3
+
+ malformed_utf8 = b"\x80"
+ if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
+ assert m.pass_to_pybind11_str(malformed_utf8) == 1
+ else:
+ with pytest.raises(TypeError):
+ m.pass_to_pybind11_str(malformed_utf8)
+
+
+@pytest.mark.parametrize(
+ "create_weakref, create_weakref_with_callback",
+ [
+ (m.weakref_from_handle, m.weakref_from_handle_and_function),
+ (m.weakref_from_object, m.weakref_from_object_and_function),
+ ],
+)
+def test_weakref(create_weakref, create_weakref_with_callback):
+ from weakref import getweakrefcount
+
+ # Apparently, you cannot weakly reference an object()
+ class WeaklyReferenced:
+ pass
+
+ callback_called = False
+
+ def callback(wr):
+ nonlocal callback_called
+ callback_called = True
+
+ obj = WeaklyReferenced()
+ assert getweakrefcount(obj) == 0
+ wr = create_weakref(obj)
+ assert getweakrefcount(obj) == 1
+
+ obj = WeaklyReferenced()
+ assert getweakrefcount(obj) == 0
+ wr = create_weakref_with_callback(obj, callback) # noqa: F841
+ assert getweakrefcount(obj) == 1
+ assert not callback_called
+ del obj
+ pytest.gc_collect()
+ assert callback_called
+
+
+@pytest.mark.parametrize(
+ "create_weakref, has_callback",
+ [
+ (m.weakref_from_handle, False),
+ (m.weakref_from_object, False),
+ (m.weakref_from_handle_and_function, True),
+ (m.weakref_from_object_and_function, True),
+ ],
+)
+def test_weakref_err(create_weakref, has_callback):
+ class C:
+ __slots__ = []
+
+ def callback(_):
+ pass
+
+ ob = C()
+ # Should raise TypeError on CPython
+ with pytest.raises(TypeError) if not env.PYPY else contextlib.nullcontext():
+ if has_callback:
+ _ = create_weakref(ob, callback)
+ else:
+ _ = create_weakref(ob)
+
+
+def test_cpp_iterators():
+ assert m.tuple_iterator() == 12
+ assert m.dict_iterator() == 305 + 711
+ assert m.passed_iterator(iter((-7, 3))) == -4
+
+
+def test_implementation_details():
+ lst = [39, 43, 92, 49, 22, 29, 93, 98, 26, 57, 8]
+ tup = tuple(lst)
+ assert m.sequence_item_get_ssize_t(lst) == 43
+ assert m.sequence_item_set_ssize_t(lst) is None
+ assert lst[1] == "peppa"
+ assert m.sequence_item_get_size_t(lst) == 92
+ assert m.sequence_item_set_size_t(lst) is None
+ assert lst[2] == "george"
+ assert m.list_item_get_ssize_t(lst) == 49
+ assert m.list_item_set_ssize_t(lst) is None
+ assert lst[3] == "rebecca"
+ assert m.list_item_get_size_t(lst) == 22
+ assert m.list_item_set_size_t(lst) is None
+ assert lst[4] == "richard"
+ assert m.tuple_item_get_ssize_t(tup) == 29
+ assert m.tuple_item_set_ssize_t() == ("emely", "edmond")
+ assert m.tuple_item_get_size_t(tup) == 93
+ assert m.tuple_item_set_size_t() == ("candy", "cat")
+
+
+def test_external_float_():
+ r1 = m.square_float_(2.0)
+ assert r1 == 4.0
+
+
+def test_tuple_rvalue_getter():
+ pop = 1000
+ tup = tuple(range(pop))
+ m.tuple_rvalue_getter(tup)
+
+
+def test_list_rvalue_getter():
+ pop = 1000
+ my_list = list(range(pop))
+ m.list_rvalue_getter(my_list)
+
+
+def test_populate_dict_rvalue():
+ pop = 1000
+ my_dict = {i: i for i in range(pop)}
+ assert m.populate_dict_rvalue(pop) == my_dict
+
+
+def test_populate_obj_str_attrs():
+ pop = 1000
+ o = types.SimpleNamespace(**{str(i): i for i in range(pop)})
+ new_o = m.populate_obj_str_attrs(o, pop)
+ new_attrs = {k: v for k, v in new_o.__dict__.items() if not k.startswith("_")}
+ assert all(isinstance(v, str) for v in new_attrs.values())
+ assert len(new_attrs) == pop
+
+
+@pytest.mark.parametrize(
+ "a,b", [("foo", "bar"), (1, 2), (1.0, 2.0), (list(range(3)), list(range(3, 6)))]
+)
+def test_inplace_append(a, b):
+ expected = a + b
+ assert m.inplace_append(a, b) == expected
+
+
+@pytest.mark.parametrize("a,b", [(3, 2), (3.0, 2.0), (set(range(3)), set(range(2)))])
+def test_inplace_subtract(a, b):
+ expected = a - b
+ assert m.inplace_subtract(a, b) == expected
+
+
+@pytest.mark.parametrize("a,b", [(3, 2), (3.0, 2.0), ([1], 3)])
+def test_inplace_multiply(a, b):
+ expected = a * b
+ assert m.inplace_multiply(a, b) == expected
+
+
+@pytest.mark.parametrize("a,b", [(6, 3), (6.0, 3.0)])
+def test_inplace_divide(a, b):
+ expected = a / b
+ assert m.inplace_divide(a, b) == expected
+
+
+@pytest.mark.parametrize(
+ "a,b",
+ [
+ (False, True),
+ (
+ set(),
+ {
+ 1,
+ },
+ ),
+ ],
+)
+def test_inplace_or(a, b):
+ expected = a | b
+ assert m.inplace_or(a, b) == expected
+
+
+@pytest.mark.parametrize(
+ "a,b",
+ [
+ (True, False),
+ (
+ {1, 2, 3},
+ {
+ 1,
+ },
+ ),
+ ],
+)
+def test_inplace_and(a, b):
+ expected = a & b
+ assert m.inplace_and(a, b) == expected
+
+
+@pytest.mark.parametrize("a,b", [(8, 1), (-3, 2)])
+def test_inplace_lshift(a, b):
+ expected = a << b
+ assert m.inplace_lshift(a, b) == expected
+
+
+@pytest.mark.parametrize("a,b", [(8, 1), (-2, 2)])
+def test_inplace_rshift(a, b):
+ expected = a >> b
+ assert m.inplace_rshift(a, b) == expected
diff --git a/3rdparty/pybind11/tests/test_sequences_and_iterators.cpp b/3rdparty/pybind11/tests/test_sequences_and_iterators.cpp
index d318052a..b867f49a 100644
--- a/3rdparty/pybind11/tests/test_sequences_and_iterators.cpp
+++ b/3rdparty/pybind11/tests/test_sequences_and_iterators.cpp
@@ -8,38 +8,91 @@
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>
+#include "constructor_stats.h"
+#include "pybind11_tests.h"
+
#include <algorithm>
+#include <utility>
+#include <vector>
-template<typename T>
+#ifdef PYBIND11_HAS_OPTIONAL
+# include <optional>
+#endif // PYBIND11_HAS_OPTIONAL
+
+template <typename T>
class NonZeroIterator {
- const T* ptr_;
+ const T *ptr_;
+
public:
- NonZeroIterator(const T* ptr) : ptr_(ptr) {}
- const T& operator*() const { return *ptr_; }
- NonZeroIterator& operator++() { ++ptr_; return *this; }
+ explicit 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&) {
+template <typename A, typename B>
+bool operator==(const NonZeroIterator<std::pair<A, B>> &it, const NonZeroSentinel &) {
return !(*it).first || !(*it).second;
}
+/* Iterator where dereferencing returns prvalues instead of references. */
+template <typename T>
+class NonRefIterator {
+ const T *ptr_;
+
+public:
+ explicit NonRefIterator(const T *ptr) : ptr_(ptr) {}
+ T operator*() const { return T(*ptr_); }
+ NonRefIterator &operator++() {
+ ++ptr_;
+ return *this;
+ }
+ bool operator==(const NonRefIterator &other) const { return ptr_ == other.ptr_; }
+};
+
+class NonCopyableInt {
+public:
+ explicit NonCopyableInt(int value) : value_(value) {}
+ NonCopyableInt(const NonCopyableInt &) = delete;
+ NonCopyableInt(NonCopyableInt &&other) noexcept : value_(other.value_) {
+ other.value_ = -1; // detect when an unwanted move occurs
+ }
+ NonCopyableInt &operator=(const NonCopyableInt &) = delete;
+ NonCopyableInt &operator=(NonCopyableInt &&other) noexcept {
+ value_ = other.value_;
+ other.value_ = -1; // detect when an unwanted move occurs
+ return *this;
+ }
+ int get() const { return value_; }
+ void set(int value) { value_ = value; }
+ ~NonCopyableInt() = default;
+
+private:
+ int value_;
+};
+using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>;
+PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>);
+PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>);
+
template <typename PythonType>
py::list test_random_access_iterator(PythonType x) {
- if (x.size() < 5)
+ 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(); }
+ if (result == -1) {
+ throw py::error_already_set();
+ }
checks.append(result != 0);
};
@@ -74,63 +127,83 @@ py::list test_random_access_iterator(PythonType x) {
TEST_SUBMODULE(sequences_and_iterators, m) {
// test_sliceable
- class Sliceable{
+ class Sliceable {
public:
- Sliceable(int n): size(n) {}
- int start,stop,step;
- int size;
+ explicit Sliceable(int n) : size(n) {}
+ int start, stop, step;
+ int size;
};
- py::class_<Sliceable>(m,"Sliceable")
+ py::class_<Sliceable>(m, "Sliceable")
.def(py::init<int>())
- .def("__getitem__",[](const Sliceable &s, py::slice slice) {
- py::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);
- })
- ;
+ .def("__getitem__", [](const Sliceable &s, const py::slice &slice) {
+ py::ssize_t start = 0, stop = 0, step = 0, slicelength = 0;
+ 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);
+ });
+
+ m.def("make_forward_slice_size_t", []() { return py::slice(0, -1, 1); });
+ m.def("make_reversed_slice_object",
+ []() { return py::slice(py::none(), py::none(), py::int_(-1)); });
+#ifdef PYBIND11_HAS_OPTIONAL
+ m.attr("has_optional") = true;
+ m.def("make_reversed_slice_size_t_optional_verbose",
+ []() { return py::slice(std::nullopt, std::nullopt, -1); });
+ // Warning: The following spelling may still compile if optional<> is not present and give
+ // wrong answers. Please use with caution.
+ m.def("make_reversed_slice_size_t_optional", []() { return py::slice({}, {}, -1); });
+#else
+ m.attr("has_optional") = false;
+#endif
// test_sequence
class Sequence {
public:
- Sequence(size_t size) : m_size(size) {
+ explicit Sequence(size_t size) : m_size(size) {
print_created(this, "of size", m_size);
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
m_data = new float[size];
memset(m_data, 0, sizeof(float) * size);
}
- Sequence(const std::vector<float> &value) : m_size(value.size()) {
+ explicit Sequence(const std::vector<float> &value) : m_size(value.size()) {
print_created(this, "of size", m_size, "from std::vector");
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
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);
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
m_data = new float[m_size];
- memcpy(m_data, s.m_data, sizeof(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) {
+ Sequence(Sequence &&s) noexcept : 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() {
+ 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);
+ memcpy(m_data, s.m_data, sizeof(float) * m_size);
}
print_copy_assigned(this);
return *this;
}
- Sequence &operator=(Sequence &&s) {
+ Sequence &operator=(Sequence &&s) noexcept {
if (&s != this) {
delete[] m_data;
m_size = s.m_size;
@@ -143,10 +216,14 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
}
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])
+ 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); }
@@ -155,23 +232,26 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
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])
+ 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)
+ 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; }
+ const float *end() const { return m_data + m_size; }
private:
size_t m_size;
@@ -179,43 +259,59 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
};
py::class_<Sequence>(m, "Sequence")
.def(py::init<size_t>())
- .def(py::init<const std::vector<float>&>())
+ .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("__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(
+ "__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();
- auto *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;
- }
- })
+ .def("__getitem__",
+ [](const Sequence &s, const py::slice &slice) -> Sequence * {
+ size_t start = 0, stop = 0, step = 0, slicelength = 0;
+ if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) {
+ throw py::error_already_set();
+ }
+ auto *seq = new Sequence(slicelength);
+ for (size_t i = 0; i < slicelength; ++i) {
+ (*seq)[i] = s[start];
+ start += step;
+ }
+ return seq;
+ })
+ .def("__setitem__",
+ [](Sequence &s, const py::slice &slice, const Sequence &value) {
+ size_t start = 0, stop = 0, step = 0, slicelength = 0;
+ 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)
@@ -223,19 +319,21 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
;
// test_map_iterator
- // Interface of a map-like object that isn't (directly) an unordered_map, but provides some basic
- // map-like functionality.
+ // 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)
+ explicit 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); }
+ void set(const std::string &key, std::string val) { map[key] = std::move(val); }
+ std::string get(const 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(); }
@@ -243,38 +341,142 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
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("__getitem__",
+ [](const StringMap &map, const 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>())
- ;
+ .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>())
+ .def(
+ "values",
+ [](const StringMap &map) { return py::make_value_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(); }
+ explicit IntPairs(std::vector<std::pair<int, int>> data) : data_(std::move(data)) {}
+ const std::pair<int, int> *begin() const { return data_.data(); }
+ // .end() only required for py::make_iterator(self) overload
+ const std::pair<int, int> *end() const { return data_.data() + data_.size(); }
+
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>())
- ;
-
+ .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>())
+ .def(
+ "nonzero_values",
+ [](const IntPairs &s) {
+ return py::make_value_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()),
+ NonZeroSentinel());
+ },
+ py::keep_alive<0, 1>())
+
+ // test iterator that returns values instead of references
+ .def(
+ "nonref",
+ [](const IntPairs &s) {
+ return py::make_iterator(NonRefIterator<std::pair<int, int>>(s.begin()),
+ NonRefIterator<std::pair<int, int>>(s.end()));
+ },
+ py::keep_alive<0, 1>())
+ .def(
+ "nonref_keys",
+ [](const IntPairs &s) {
+ return py::make_key_iterator(NonRefIterator<std::pair<int, int>>(s.begin()),
+ NonRefIterator<std::pair<int, int>>(s.end()));
+ },
+ py::keep_alive<0, 1>())
+ .def(
+ "nonref_values",
+ [](const IntPairs &s) {
+ return py::make_value_iterator(NonRefIterator<std::pair<int, int>>(s.begin()),
+ NonRefIterator<std::pair<int, int>>(s.end()));
+ },
+ py::keep_alive<0, 1>())
+
+ // test single-argument make_iterator
+ .def(
+ "simple_iterator",
+ [](IntPairs &self) { return py::make_iterator(self); },
+ py::keep_alive<0, 1>())
+ .def(
+ "simple_keys",
+ [](IntPairs &self) { return py::make_key_iterator(self); },
+ py::keep_alive<0, 1>())
+ .def(
+ "simple_values",
+ [](IntPairs &self) { return py::make_value_iterator(self); },
+ py::keep_alive<0, 1>())
+
+ // Test iterator with an Extra (doesn't do anything useful, so not used
+ // at runtime, but tests need to be able to compile with the correct
+ // overload. See PR #3293.
+ .def(
+ "_make_iterator_extras",
+ [](IntPairs &self) { return py::make_iterator(self, py::call_guard<int>()); },
+ py::keep_alive<0, 1>())
+ .def(
+ "_make_key_extras",
+ [](IntPairs &self) { return py::make_key_iterator(self, py::call_guard<int>()); },
+ py::keep_alive<0, 1>())
+ .def(
+ "_make_value_extras",
+ [](IntPairs &self) { return py::make_value_iterator(self, py::call_guard<int>()); },
+ py::keep_alive<0, 1>());
+
+ // test_iterator_referencing
+ py::class_<NonCopyableInt>(m, "NonCopyableInt")
+ .def(py::init<int>())
+ .def("set", &NonCopyableInt::set)
+ .def("__int__", &NonCopyableInt::get);
+ py::class_<std::vector<NonCopyableInt>>(m, "VectorNonCopyableInt")
+ .def(py::init<>())
+ .def("append",
+ [](std::vector<NonCopyableInt> &vec, int value) { vec.emplace_back(value); })
+ .def("__iter__", [](std::vector<NonCopyableInt> &vec) {
+ return py::make_iterator(vec.begin(), vec.end());
+ });
+ py::class_<std::vector<NonCopyableIntPair>>(m, "VectorNonCopyableIntPair")
+ .def(py::init<>())
+ .def("append",
+ [](std::vector<NonCopyableIntPair> &vec, const std::pair<int, int> &value) {
+ vec.emplace_back(NonCopyableInt(value.first), NonCopyableInt(value.second));
+ })
+ .def("keys",
+ [](std::vector<NonCopyableIntPair> &vec) {
+ return py::make_key_iterator(vec.begin(), vec.end());
+ })
+ .def("values", [](std::vector<NonCopyableIntPair> &vec) {
+ return py::make_value_iterator(vec.begin(), vec.end());
+ });
#if 0
// Obsolete: special data structure for exposing custom iterator types to python
@@ -304,7 +506,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
#endif
// test_python_iterator_in_cpp
- m.def("object_to_list", [](py::object o) {
+ m.def("object_to_list", [](const py::object &o) {
auto l = py::list();
for (auto item : o) {
l.append(item);
@@ -322,22 +524,22 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
});
// test_sequence_length: check that Python sequences can be converted to py::sequence.
- m.def("sequence_length", [](py::sequence seq) { return seq.size(); });
+ m.def("sequence_length", [](const py::sequence &seq) { return seq.size(); });
// Make sure that py::iterator works with std algorithms
- m.def("count_none", [](py::object o) {
+ m.def("count_none", [](const 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) {
+ m.def("find_none", [](const 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("count_nonzeros", [](const 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>);
@@ -352,7 +554,9 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
// 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); });
+ 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
index c3b608c4..062e3b3d 100644
--- a/3rdparty/pybind11/tests/test_sequences_and_iterators.py
+++ b/3rdparty/pybind11/tests/test_sequences_and_iterators.py
@@ -1,18 +1,19 @@
-# -*- coding: utf-8 -*-
import pytest
-from pybind11_tests import sequences_and_iterators as m
+from pytest import approx
+
from pybind11_tests import ConstructorStats
+from pybind11_tests import sequences_and_iterators as m
-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 test_slice_constructors():
+ assert m.make_forward_slice_size_t() == slice(0, -1, 1)
+ assert m.make_reversed_slice_object() == slice(None, None, -1)
-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)
- )
+@pytest.mark.skipif(not m.has_optional, reason="no <optional>")
+def test_slice_constructors_explicit_optional():
+ assert m.make_reversed_slice_size_t_optional() == slice(None, None, -1)
+ assert m.make_reversed_slice_size_t_optional_verbose() == slice(None, None, -1)
def test_generalized_iterators():
@@ -24,6 +25,10 @@ def test_generalized_iterators():
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()) == []
+ assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_values()) == [2, 4]
+ assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_values()) == [2]
+ assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_values()) == []
+
# __next__ must continue to raise StopIteration
it = m.IntPairs([(0, 0)]).nonzero()
for _ in range(3):
@@ -36,6 +41,47 @@ def test_generalized_iterators():
next(it)
+def test_nonref_iterators():
+ pairs = m.IntPairs([(1, 2), (3, 4), (0, 5)])
+ assert list(pairs.nonref()) == [(1, 2), (3, 4), (0, 5)]
+ assert list(pairs.nonref_keys()) == [1, 3, 0]
+ assert list(pairs.nonref_values()) == [2, 4, 5]
+
+
+def test_generalized_iterators_simple():
+ assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).simple_iterator()) == [
+ (1, 2),
+ (3, 4),
+ (0, 5),
+ ]
+ assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).simple_keys()) == [1, 3, 0]
+ assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).simple_values()) == [2, 4, 5]
+
+
+def test_iterator_referencing():
+ """Test that iterators reference rather than copy their referents."""
+ vec = m.VectorNonCopyableInt()
+ vec.append(3)
+ vec.append(5)
+ assert [int(x) for x in vec] == [3, 5]
+ # Increment everything to make sure the referents can be mutated
+ for x in vec:
+ x.set(int(x) + 1)
+ assert [int(x) for x in vec] == [4, 6]
+
+ vec = m.VectorNonCopyableIntPair()
+ vec.append([3, 4])
+ vec.append([5, 7])
+ assert [int(x) for x in vec.keys()] == [3, 5]
+ assert [int(x) for x in vec.values()] == [4, 7]
+ for x in vec.keys():
+ x.set(int(x) + 1)
+ for x in vec.values():
+ x.set(int(x) + 10)
+ assert [int(x) for x in vec.keys()] == [4, 6]
+ assert [int(x) for x in vec.values()] == [14, 17]
+
+
def test_sliceable():
sliceable = m.Sliceable(100)
assert sliceable[::] == (0, 100, 1)
@@ -61,7 +107,8 @@ def test_sequence():
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)
+ assert s[0] == approx(12.34, rel=1e-05)
+ assert s[3] == approx(56.78, rel=1e-05)
rev = reversed(s)
assert cstats.values() == ["of size", "5"]
@@ -76,14 +123,14 @@ def test_sequence():
assert cstats.values() == ["of size", "0"]
expected = [0, 56.78, 0, 0, 12.34]
- assert allclose(rev, expected)
- assert allclose(rev2, expected)
+ assert rev == approx(expected, rel=1e-05)
+ assert rev2 == approx(expected, rel=1e-05)
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 rev == approx([2, 56.78, 2, 0, 2], rel=1e-05)
assert cstats.alive() == 4
del it
@@ -104,7 +151,7 @@ def test_sequence():
def test_sequence_length():
- """#2076: Exception raised by len(arg) should be propagated """
+ """#2076: Exception raised by len(arg) should be propagated"""
class BadLen(RuntimeError):
pass
@@ -139,6 +186,7 @@ def test_map_iterator():
assert sm[k] == expected[k]
for k, v in sm.items():
assert v == expected[k]
+ assert list(sm.values()) == [expected[k] for k in sm]
it = iter(m.StringMap({}))
for _ in range(3): # __next__ must continue to raise StopIteration
@@ -187,7 +235,7 @@ def test_iterator_passthrough():
def test_iterator_rvp():
- """#388: Can't make iterators via make_iterator() with different r/v policies """
+ """#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]
diff --git a/3rdparty/pybind11/tests/test_smart_ptr.cpp b/3rdparty/pybind11/tests/test_smart_ptr.cpp
index 60c2e692..6d9efced 100644
--- a/3rdparty/pybind11/tests/test_smart_ptr.cpp
+++ b/3rdparty/pybind11/tests/test_smart_ptr.cpp
@@ -8,53 +8,34 @@
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"
+#include "pybind11_tests.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(); }
- };
-} // namespace detail
-} // namespace pybind11
-
-// 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>);
+namespace {
// 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 {
+// 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) {};
+ explicit 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(); }
+ explicit 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
@@ -62,13 +43,13 @@ PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
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"); }
+ shared_ptr_with_addressof_operator() = default;
+ explicit 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
@@ -76,17 +57,237 @@ PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>);
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"); }
+ explicit 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"); }
+};
+
+// Custom object with builtin reference counting (see 'object.h' for the implementation)
+class MyObject1 : public Object {
+public:
+ explicit MyObject1(int value) : value(value) { print_created(this, toString()); }
+ std::string toString() const override { return "MyObject1[" + std::to_string(value) + "]"; }
+
+protected:
+ ~MyObject1() override { print_destroyed(this); }
+
+private:
+ int value;
+};
+
+// Object managed by a std::shared_ptr<>
+class MyObject2 {
+public:
+ MyObject2(const MyObject2 &) = default;
+ explicit 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;
+};
+
+// 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;
+ explicit 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;
+};
+
+// test_unique_nodelete
+// Object with a private destructor
+class MyObject4;
+std::unordered_set<MyObject4 *> myobject4_instances;
+class MyObject4 {
+public:
+ explicit MyObject4(int value) : value{value} {
+ print_created(this);
+ myobject4_instances.insert(this);
+ }
+ int value;
+
+ static void cleanupAllInstances() {
+ auto tmp = std::move(myobject4_instances);
+ myobject4_instances.clear();
+ for (auto *o : tmp) {
+ delete o;
+ }
+ }
+
+private:
+ ~MyObject4() {
+ myobject4_instances.erase(this);
+ print_destroyed(this);
+ }
+};
+
+// 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;
+std::unordered_set<MyObject4a *> myobject4a_instances;
+class MyObject4a {
+public:
+ explicit MyObject4a(int i) : value{i} {
+ print_created(this);
+ myobject4a_instances.insert(this);
+ };
+ int value;
+
+ static void cleanupAllInstances() {
+ auto tmp = std::move(myobject4a_instances);
+ myobject4a_instances.clear();
+ for (auto *o : tmp) {
+ delete o;
+ }
+ }
+
+protected:
+ virtual ~MyObject4a() {
+ myobject4a_instances.erase(this);
+ print_destroyed(this);
+ }
+};
+
+// Object derived but with public destructor and no Deleter in default holder
+class MyObject4b : public MyObject4a {
+public:
+ explicit MyObject4b(int i) : MyObject4a(i) { print_created(this); }
+ ~MyObject4b() override { print_destroyed(this); }
+};
+
+// test_large_holder
+class MyObject5 { // managed by huge_unique_ptr
+public:
+ explicit MyObject5(int value) : value{value} { print_created(this); }
+ ~MyObject5() { print_destroyed(this); }
+ int value;
+};
+
+// test_shared_ptr_and_references
+struct SharedPtrRef {
+ struct A {
+ A() { print_created(this); }
+ A(const A &) { print_copy_created(this); }
+ A(A &&) noexcept { print_move_created(this); }
+ ~A() { print_destroyed(this); }
+ };
+
+ A value = {};
+ std::shared_ptr<A> shared = std::make_shared<A>();
};
-PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>);
+// test_shared_ptr_from_this_and_references
+struct SharedFromThisRef {
+ struct B : std::enable_shared_from_this<B> {
+ B() { print_created(this); }
+ // NOLINTNEXTLINE(bugprone-copy-constructor-init)
+ B(const B &) : std::enable_shared_from_this<B>() { print_copy_created(this); }
+ B(B &&) noexcept : 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>();
+};
+
+// 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 {};
+
+// test_move_only_holder
+struct C {
+ C() { print_created(this); }
+ ~C() { print_destroyed(this); }
+};
+
+// test_holder_with_addressof_operator
+struct TypeForHolderWithAddressOf {
+ TypeForHolderWithAddressOf() { print_created(this); }
+ TypeForHolderWithAddressOf(const TypeForHolderWithAddressOf &) { print_copy_created(this); }
+ TypeForHolderWithAddressOf(TypeForHolderWithAddressOf &&) noexcept {
+ print_move_created(this);
+ }
+ ~TypeForHolderWithAddressOf() { print_destroyed(this); }
+ std::string toString() const {
+ return "TypeForHolderWithAddressOf[" + std::to_string(value) + "]";
+ }
+ int value = 42;
+};
+
+// test_move_only_holder_with_addressof_operator
+struct TypeForMoveOnlyHolderWithAddressOf {
+ explicit TypeForMoveOnlyHolderWithAddressOf(int value) : value{value} { print_created(this); }
+ ~TypeForMoveOnlyHolderWithAddressOf() { print_destroyed(this); }
+ std::string toString() const {
+ return "MoveOnlyHolderWithAddressOf[" + std::to_string(value) + "]";
+ }
+ int value;
+};
+
+// test_smart_ptr_from_default
+struct HeldByDefaultHolder {};
+
+// test_shared_ptr_gc
+// #187: issue involving std::shared_ptr<> return value policy & garbage collection
+struct ElementBase {
+ virtual ~ElementBase() = default; /* Force creation of virtual table */
+ ElementBase() = default;
+ ElementBase(const ElementBase &) = delete;
+};
+
+struct ElementA : ElementBase {
+ explicit ElementA(int v) : v(v) {}
+ int value() const { return v; }
+ int v;
+};
+
+struct ElementList {
+ void add(const std::shared_ptr<ElementBase> &e) { l.push_back(e); }
+ std::vector<std::shared_ptr<ElementBase>> l;
+};
+
+} // namespace
+
+// 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.
+// Make pybind11 aware of the non-standard getter member function
+namespace PYBIND11_NAMESPACE {
+namespace detail {
+template <typename T>
+struct holder_helper<ref<T>> {
+ static const T *get(const ref<T> &p) { return p.get_ptr(); }
+};
+} // namespace detail
+} // namespace PYBIND11_NAMESPACE
+
+// Make pybind aware of the ref-counted wrapper type (s):
+PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true);
+// 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>);
+PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>);
+PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
+PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>);
+PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>);
TEST_SUBMODULE(smart_ptr, m) {
+ // Please do not interleave `struct` and `class` definitions with bindings code,
+ // but implement `struct`s and `class`es in the anonymous namespace above.
+ // This helps keeping the smart_holder branch in sync with master.
// test_smart_ptr
@@ -94,24 +295,13 @@ TEST_SUBMODULE(smart_ptr, m) {
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 override { return "MyObject1[" + std::to_string(value) + "]"; }
- protected:
- ~MyObject1() override { print_destroyed(this); }
- private:
- int value;
- };
- py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj)
- .def(py::init<int>());
+ 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_object_2", []() -> ref<Object> { return ref<Object>(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("make_myobject1_2", []() -> ref<MyObject1> { return ref<MyObject1>(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()); });
@@ -124,48 +314,31 @@ TEST_SUBMODULE(smart_ptr, m) {
// 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>());
+ 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()); });
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
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("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()); });
+
+ 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()); });
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
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()); });
+ 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);
+ auto o = ref<MyObject1>(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
@@ -175,196 +348,123 @@ TEST_SUBMODULE(smart_ptr, m) {
});
// 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);
+ .def_readwrite("value", &MyObject4::value)
+ .def_static("cleanup_all_instances", &MyObject4::cleanupAllInstances);
// 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);
+ .def_readwrite("value", &MyObject4a::value)
+ .def_static("cleanup_all_instances", &MyObject4a::cleanupAllInstances);
- // 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() override { print_destroyed(this); }
- };
- py::class_<MyObject4b, MyObject4a>(m, "MyObject4b")
+ py::class_<MyObject4b, MyObject4a, std::unique_ptr<MyObject4b>>(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")
+ py::class_<SharedPtrRef, std::unique_ptr<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_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_property_readonly(
+ "holder_copy",
+ [](const SharedPtrRef &s) { return s.shared; },
+ py::return_value_policy::copy)
.def("set_ref", [](SharedPtrRef &, const A &) { return true; })
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
.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")
+ py::class_<SharedFromThisRef, std::unique_ptr<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_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_property_readonly(
+ "holder_copy",
+ [](const SharedFromThisRef &s) { return s.shared; },
+ py::return_value_policy::copy)
.def("set_ref", [](SharedFromThisRef &, const B &) { return true; })
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
.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); })
.def_static("make_as_object", []() { return py::cast(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_1",
+ [](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); })
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
.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()); });
+ .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)); })
+ 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()); });
+ .def("print_object",
+ [](const TypeForMoveOnlyHolderWithAddressOf *obj) { py::print(obj->toString()); });
// test_smart_ptr_from_default
- struct HeldByDefaultHolder { };
- py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder")
+ py::class_<HeldByDefaultHolder, std::unique_ptr<HeldByDefaultHolder>>(m, "HeldByDefaultHolder")
.def(py::init<>())
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
.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() = default; /* Force creation of virtual table */
- ElementBase() = default;
- ElementBase(const ElementBase&) = delete;
- };
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)
+ 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
index c55bffba..2f204e01 100644
--- a/3rdparty/pybind11/tests/test_smart_ptr.py
+++ b/3rdparty/pybind11/tests/test_smart_ptr.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
import pytest
m = pytest.importorskip("pybind11_tests.smart_ptr")
@@ -16,7 +15,7 @@ def test_smart_ptr(capture):
m.print_object_2(o)
m.print_object_3(o)
m.print_object_4(o)
- assert capture == "MyObject1[{i}]\n".format(i=i) * 4
+ assert capture == f"MyObject1[{i}]\n" * 4
for i, o in enumerate(
[m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], start=4
@@ -34,13 +33,11 @@ def test_smart_ptr(capture):
m.print_myobject1_4(o)
times = 4 if isinstance(o, int) else 8
- assert capture == "MyObject1[{i}]\n".format(i=i) * times
+ assert capture == f"MyObject1[{i}]\n" * times
cstats = ConstructorStats.get(m.MyObject1)
assert cstats.alive() == 0
- expected_values = ["MyObject1[{}]".format(i) for i in range(1, 7)] + [
- "MyObject1[7]"
- ] * 4
+ expected_values = [f"MyObject1[{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
@@ -58,7 +55,7 @@ def test_smart_ptr(capture):
m.print_myobject2_2(o)
m.print_myobject2_3(o)
m.print_myobject2_4(o)
- assert capture == "MyObject2[{i}]\n".format(i=i) * 4
+ assert capture == f"MyObject2[{i}]\n" * 4
cstats = ConstructorStats.get(m.MyObject2)
assert cstats.alive() == 1
@@ -81,7 +78,7 @@ def test_smart_ptr(capture):
m.print_myobject3_2(o)
m.print_myobject3_3(o)
m.print_myobject3_4(o)
- assert capture == "MyObject3[{i}]\n".format(i=i) * 4
+ assert capture == f"MyObject3[{i}]\n" * 4
cstats = ConstructorStats.get(m.MyObject3)
assert cstats.alive() == 1
@@ -125,7 +122,9 @@ def test_unique_nodelete():
cstats = ConstructorStats.get(m.MyObject4)
assert cstats.alive() == 1
del o
- assert cstats.alive() == 1 # Leak, but that's intentional
+ assert cstats.alive() == 1
+ m.MyObject4.cleanup_all_instances()
+ assert cstats.alive() == 0
def test_unique_nodelete4a():
@@ -134,19 +133,25 @@ def test_unique_nodelete4a():
cstats = ConstructorStats.get(m.MyObject4a)
assert cstats.alive() == 1
del o
- assert cstats.alive() == 1 # Leak, but that's intentional
+ assert cstats.alive() == 1
+ m.MyObject4a.cleanup_all_instances()
+ assert cstats.alive() == 0
def test_unique_deleter():
+ m.MyObject4a(0)
o = m.MyObject4b(23)
assert o.value == 23
cstats4a = ConstructorStats.get(m.MyObject4a)
- assert cstats4a.alive() == 2 # Two because of previous test
+ assert cstats4a.alive() == 2
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 cstats4a.alive() == 1 # Should now only be one leftover
assert cstats4b.alive() == 0 # Should be deleted
+ m.MyObject4a.cleanup_all_instances()
+ assert cstats4a.alive() == 0
+ assert cstats4b.alive() == 0
def test_large_holder():
diff --git a/3rdparty/pybind11/tests/test_stl.cpp b/3rdparty/pybind11/tests/test_stl.cpp
index 05901627..d45465d6 100644
--- a/3rdparty/pybind11/tests/test_stl.cpp
+++ b/3rdparty/pybind11/tests/test_stl.cpp
@@ -7,22 +7,44 @@
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 "constructor_stats.h"
+#include "pybind11_tests.h"
+
+#ifndef PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL
+# define PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL
+#endif
+#include <pybind11/stl/filesystem.h>
+
#include <string>
+#include <vector>
+
+#if defined(PYBIND11_TEST_BOOST)
+# include <boost/optional.hpp>
+
+namespace PYBIND11_NAMESPACE {
+namespace detail {
+template <typename T>
+struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {};
+
+template <>
+struct type_caster<boost::none_t> : void_caster<boost::none_t> {};
+} // namespace detail
+} // namespace PYBIND11_NAMESPACE
+#endif
// Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14
#if defined(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
+# define PYBIND11_TEST_VARIANT 1
+#elif defined(PYBIND11_TEST_BOOST)
+# include <boost/variant.hpp>
+# define PYBIND11_TEST_VARIANT 1
using boost::variant;
-namespace pybind11 { namespace detail {
+namespace PYBIND11_NAMESPACE {
+namespace detail {
template <typename... Ts>
struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};
@@ -33,33 +55,117 @@ struct visit_helper<boost::variant> {
return boost::apply_visitor(args...);
}
};
-}} // namespace pybind11::detail
+} // namespace detail
+} // namespace PYBIND11_NAMESPACE
#endif
PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>);
/// Issue #528: templated constructor
struct TplCtorClass {
- template <typename T> TplCtorClass(const T &) { }
+ template <typename T>
+ explicit TplCtorClass(const T &) {}
bool operator==(const TplCtorClass &) const { return true; }
};
namespace std {
- template <>
- struct hash<TplCtorClass> { size_t operator()(const TplCtorClass &) const { return 0; } };
+template <>
+struct hash<TplCtorClass> {
+ size_t operator()(const TplCtorClass &) const { return 0; }
+};
} // namespace std
-
template <template <typename> class OptionalImpl, typename T>
-struct OptionalHolder
-{
- OptionalHolder() = default;
- bool member_initialized() const {
- return member && member->initialized;
- }
+struct OptionalHolder {
+ // NOLINTNEXTLINE(modernize-use-equals-default): breaks GCC 4.8
+ OptionalHolder(){};
+ bool member_initialized() const { return member && member->initialized; }
OptionalImpl<T> member = T{};
};
+enum class EnumType {
+ kSet = 42,
+ kUnset = 85,
+};
+
+// This is used to test that return-by-ref and return-by-copy policies are
+// handled properly for optional types. This is a regression test for a dangling
+// reference issue. The issue seemed to require the enum value type to
+// reproduce - it didn't seem to happen if the value type is just an integer.
+template <template <typename> class OptionalImpl>
+class OptionalProperties {
+public:
+ using OptionalEnumValue = OptionalImpl<EnumType>;
+
+ OptionalProperties() : value(EnumType::kSet) {}
+ ~OptionalProperties() {
+ // Reset value to detect use-after-destruction.
+ // This is set to a specific value rather than nullopt to ensure that
+ // the memory that contains the value gets re-written.
+ value = EnumType::kUnset;
+ }
+
+ OptionalEnumValue &access_by_ref() { return value; }
+ OptionalEnumValue access_by_copy() { return value; }
+
+private:
+ OptionalEnumValue value;
+};
+
+// This type mimics aspects of boost::optional from old versions of Boost,
+// which exposed a dangling reference bug in Pybind11. Recent versions of
+// boost::optional, as well as libstdc++'s std::optional, don't seem to be
+// affected by the same issue. This is meant to be a minimal implementation
+// required to reproduce the issue, not fully standard-compliant.
+// See issue #3330 for more details.
+template <typename T>
+class ReferenceSensitiveOptional {
+public:
+ using value_type = T;
+
+ ReferenceSensitiveOptional() = default;
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ ReferenceSensitiveOptional(const T &value) : storage{value} {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ ReferenceSensitiveOptional(T &&value) : storage{std::move(value)} {}
+ ReferenceSensitiveOptional &operator=(const T &value) {
+ storage = {value};
+ return *this;
+ }
+ ReferenceSensitiveOptional &operator=(T &&value) {
+ storage = {std::move(value)};
+ return *this;
+ }
+
+ template <typename... Args>
+ T &emplace(Args &&...args) {
+ storage.clear();
+ storage.emplace_back(std::forward<Args>(args)...);
+ return storage.back();
+ }
+
+ const T &value() const noexcept {
+ assert(!storage.empty());
+ return storage[0];
+ }
+
+ const T &operator*() const noexcept { return value(); }
+
+ const T *operator->() const noexcept { return &value(); }
+
+ explicit operator bool() const noexcept { return !storage.empty(); }
+
+private:
+ std::vector<T> storage;
+};
+
+namespace PYBIND11_NAMESPACE {
+namespace detail {
+template <typename T>
+struct type_caster<ReferenceSensitiveOptional<T>>
+ : optional_caster<ReferenceSensitiveOptional<T>> {};
+} // namespace detail
+} // namespace PYBIND11_NAMESPACE
TEST_SUBMODULE(stl, m) {
// test_vector
@@ -67,24 +173,29 @@ TEST_SUBMODULE(stl, m) {
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;
- });
+ 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; });
+ m.def(
+ "cast_ptr_vector",
+ []() {
+ // Using no-destructor idiom to side-step warnings from overzealous compilers.
+ static auto *v = new std::vector<RValueCaster>{2};
+ return v;
+ },
+ py::return_value_policy::reference);
// 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("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) {
+ m.def("load_valarray", [](const std::valarray<int> &v) {
return v.size() == 3 && v[0] == 1 && v[1] == 4 && v[2] == 9;
});
@@ -97,7 +208,7 @@ TEST_SUBMODULE(stl, m) {
// 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");
+ return (set.count("key1") != 0u) && (set.count("key2") != 0u) && (set.count("key3") != 0u);
});
// test_recursive_casting
@@ -106,10 +217,12 @@ TEST_SUBMODULE(stl, m) {
// 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_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.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{});
@@ -118,15 +231,18 @@ TEST_SUBMODULE(stl, m) {
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
+ 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"].emplace_back(); // another list
lvn["a"].back().emplace_back(); // add an array
- lvn["b"].emplace_back(); // add a list
+ lvn["b"].emplace_back(); // add a list
lvn["b"].back().emplace_back(); // add an array
lvn["b"].back().emplace_back(); // add another array
+ static std::vector<RValueCaster> lvv{2};
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; });
@@ -139,9 +255,15 @@ TEST_SUBMODULE(stl, m) {
return v;
});
+ pybind11::enum_<EnumType>(m, "EnumType")
+ .value("kSet", EnumType::kSet)
+ .value("kUnset", EnumType::kUnset);
+
// test_move_out_container
struct MoveOutContainer {
- struct Value { int value; };
+ struct Value {
+ int value;
+ };
std::list<Value> move_list() const { return {{0}, {1}, {2}}; }
};
py::class_<MoveOutContainer::Value>(m, "MoveOutContainerValue")
@@ -154,7 +276,7 @@ TEST_SUBMODULE(stl, m) {
struct NoAssign {
int value;
- explicit NoAssign(int value = 0) : value(value) { }
+ explicit NoAssign(int value = 0) : value(value) {}
NoAssign(const NoAssign &) = default;
NoAssign(NoAssign &&) = default;
@@ -165,13 +287,10 @@ TEST_SUBMODULE(stl, m) {
.def(py::init<>())
.def(py::init<int>());
-
- struct MoveOutDetector
- {
+ struct MoveOutDetector {
MoveOutDetector() = default;
- MoveOutDetector(const MoveOutDetector&) = default;
- MoveOutDetector(MoveOutDetector&& other) noexcept
- : initialized(other.initialized) {
+ MoveOutDetector(const MoveOutDetector &) = default;
+ MoveOutDetector(MoveOutDetector &&other) noexcept : initialized(other.initialized) {
// steal underlying resource
other.initialized = false;
}
@@ -181,34 +300,37 @@ TEST_SUBMODULE(stl, m) {
.def(py::init<>())
.def_readonly("initialized", &MoveOutDetector::initialized);
-
#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("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 != 0 ? 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; });
+ m.def("nodefer_none_optional", [](const py::none &) { return false; });
using opt_holder = OptionalHolder<std::optional, MoveOutDetector>;
py::class_<opt_holder>(m, "OptionalHolder", "Class with optional member")
.def(py::init<>())
.def_readonly("member", &opt_holder::member)
.def("member_initialized", &opt_holder::member_initialized);
+
+ using opt_props = OptionalProperties<std::optional>;
+ pybind11::class_<opt_props>(m, "OptionalProperties")
+ .def(pybind11::init<>())
+ .def_property_readonly("access_by_ref", &opt_props::access_by_ref)
+ .def_property_readonly("access_by_copy", &opt_props::access_by_copy);
#endif
#ifdef PYBIND11_HAS_EXP_OPTIONAL
@@ -217,27 +339,100 @@ TEST_SUBMODULE(stl, m) {
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"));
+ 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"));
using opt_exp_holder = OptionalHolder<std::experimental::optional, MoveOutDetector>;
py::class_<opt_exp_holder>(m, "OptionalExpHolder", "Class with optional member")
.def(py::init<>())
.def_readonly("member", &opt_exp_holder::member)
.def("member_initialized", &opt_exp_holder::member_initialized);
+
+ using opt_exp_props = OptionalProperties<std::experimental::optional>;
+ pybind11::class_<opt_exp_props>(m, "OptionalExpProperties")
+ .def(pybind11::init<>())
+ .def_property_readonly("access_by_ref", &opt_exp_props::access_by_ref)
+ .def_property_readonly("access_by_copy", &opt_exp_props::access_by_copy);
+#endif
+
+#if defined(PYBIND11_TEST_BOOST)
+ // test_boost_optional
+ m.attr("has_boost_optional") = true;
+
+ using boost_opt_int = boost::optional<int>;
+ using boost_opt_no_assign = boost::optional<NoAssign>;
+ m.def("double_or_zero_boost", [](const boost_opt_int &x) -> int { return x.value_or(0) * 2; });
+ m.def("half_or_none_boost",
+ [](int x) -> boost_opt_int { return x != 0 ? boost_opt_int(x / 2) : boost_opt_int(); });
+ m.def(
+ "test_nullopt_boost",
+ [](boost_opt_int x) { return x.value_or(42); },
+ py::arg_v("x", boost::none, "None"));
+ m.def(
+ "test_no_assign_boost",
+ [](const boost_opt_no_assign &x) { return x ? x->value : 42; },
+ py::arg_v("x", boost::none, "None"));
+
+ using opt_boost_holder = OptionalHolder<boost::optional, MoveOutDetector>;
+ py::class_<opt_boost_holder>(m, "OptionalBoostHolder", "Class with optional member")
+ .def(py::init<>())
+ .def_readonly("member", &opt_boost_holder::member)
+ .def("member_initialized", &opt_boost_holder::member_initialized);
+
+ using opt_boost_props = OptionalProperties<boost::optional>;
+ pybind11::class_<opt_boost_props>(m, "OptionalBoostProperties")
+ .def(pybind11::init<>())
+ .def_property_readonly("access_by_ref", &opt_boost_props::access_by_ref)
+ .def_property_readonly("access_by_copy", &opt_boost_props::access_by_copy);
+#endif
+
+ // test_refsensitive_optional
+ using refsensitive_opt_int = ReferenceSensitiveOptional<int>;
+ using refsensitive_opt_no_assign = ReferenceSensitiveOptional<NoAssign>;
+ m.def("double_or_zero_refsensitive",
+ [](const refsensitive_opt_int &x) -> int { return (x ? x.value() : 0) * 2; });
+ m.def("half_or_none_refsensitive", [](int x) -> refsensitive_opt_int {
+ return x != 0 ? refsensitive_opt_int(x / 2) : refsensitive_opt_int();
+ });
+ m.def(
+ "test_nullopt_refsensitive",
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
+ [](refsensitive_opt_int x) { return x ? x.value() : 42; },
+ py::arg_v("x", refsensitive_opt_int(), "None"));
+ m.def(
+ "test_no_assign_refsensitive",
+ [](const refsensitive_opt_no_assign &x) { return x ? x->value : 42; },
+ py::arg_v("x", refsensitive_opt_no_assign(), "None"));
+
+ using opt_refsensitive_holder = OptionalHolder<ReferenceSensitiveOptional, MoveOutDetector>;
+ py::class_<opt_refsensitive_holder>(
+ m, "OptionalRefSensitiveHolder", "Class with optional member")
+ .def(py::init<>())
+ .def_readonly("member", &opt_refsensitive_holder::member)
+ .def("member_initialized", &opt_refsensitive_holder::member_initialized);
+
+ using opt_refsensitive_props = OptionalProperties<ReferenceSensitiveOptional>;
+ pybind11::class_<opt_refsensitive_props>(m, "OptionalRefSensitiveProperties")
+ .def(pybind11::init<>())
+ .def_property_readonly("access_by_ref", &opt_refsensitive_props::access_by_ref)
+ .def_property_readonly("access_by_copy", &opt_refsensitive_props::access_by_copy);
+
+#ifdef PYBIND11_HAS_FILESYSTEM
+ // test_fs_path
+ m.attr("has_filesystem") = true;
+ m.def("parent_path", [](const std::filesystem::path &p) { return p.parent_path(); });
#endif
-#ifdef PYBIND11_HAS_VARIANT
+#ifdef PYBIND11_TEST_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");
@@ -245,13 +440,16 @@ TEST_SUBMODULE(stl, m) {
using result_type = const char *;
result_type operator()(int) { return "int"; }
- result_type operator()(std::string) { return "std::string"; }
+ result_type operator()(const std::string &) { return "std::string"; }
result_type operator()(double) { return "double"; }
result_type operator()(std::nullptr_t) { return "std::nullptr_t"; }
+# if defined(PYBIND11_HAS_VARIANT)
+ result_type operator()(std::monostate) { return "std::monostate"; }
+# endif
};
// test_variant
- m.def("load_variant", [](variant<int, std::string, double, std::nullptr_t> v) {
+ m.def("load_variant", [](const 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) {
@@ -261,6 +459,18 @@ TEST_SUBMODULE(stl, m) {
using V = variant<int, std::string>;
return py::make_tuple(V(5), V("Hello"));
});
+
+# if defined(PYBIND11_HAS_VARIANT)
+ // std::monostate tests.
+ m.def("load_monostate_variant",
+ [](const variant<std::monostate, int, std::string> &v) -> const char * {
+ return py::detail::visit_helper<variant>::call(visitor(), v);
+ });
+ m.def("cast_monostate_variant", []() {
+ using V = variant<std::monostate, int, std::string>;
+ return py::make_tuple(V{}, V(5), V("Hello"));
+ });
+# endif
#endif
// #528: templated constructor
@@ -270,26 +480,32 @@ TEST_SUBMODULE(stl, m) {
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
+#if defined(PYBIND11_HAS_EXP_OPTIONAL)
+ m.def("tpl_constr_optional_exp", [](std::experimental::optional<TplCtorClass> &) {});
+#endif
+#if defined(PYBIND11_TEST_BOOST)
+ m.def("tpl_constr_optional_boost", [](boost::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
- };
+ 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);
+ 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; });
+ m.def("func_with_string_or_vector_string_arg_overload",
+ [](const std::vector<std::string> &) { return 1; });
+ m.def("func_with_string_or_vector_string_arg_overload",
+ [](const std::list<std::string> &) { return 2; });
+ m.def("func_with_string_or_vector_string_arg_overload", [](const std::string &) { return 3; });
class Placeholder {
public:
@@ -300,19 +516,24 @@ TEST_SUBMODULE(stl, m) {
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(
+ "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; };
+ struct Issue1561Inner {
+ std::string data;
+ };
+ struct Issue1561Outer {
+ std::vector<Issue1561Inner> list;
+ };
py::class_<Issue1561Inner>(m, "Issue1561Inner")
.def(py::init<std::string>())
@@ -321,4 +542,10 @@ TEST_SUBMODULE(stl, m) {
py::class_<Issue1561Outer>(m, "Issue1561Outer")
.def(py::init<>())
.def_readwrite("list", &Issue1561Outer::list);
+
+ m.def(
+ "return_vector_bool_raw_ptr",
+ []() { return new std::vector<bool>(4513); },
+ // Without explicitly specifying `take_ownership`, this function leaks.
+ py::return_value_policy::take_ownership);
}
diff --git a/3rdparty/pybind11/tests/test_stl.py b/3rdparty/pybind11/tests/test_stl.py
index 33001754..d30c3821 100644
--- a/3rdparty/pybind11/tests/test_stl.py
+++ b/3rdparty/pybind11/tests/test_stl.py
@@ -1,9 +1,7 @@
-# -*- coding: utf-8 -*-
import pytest
+from pybind11_tests import ConstructorStats, UserType
from pybind11_tests import stl as m
-from pybind11_tests import UserType
-from pybind11_tests import ConstructorStats
def test_vector(doc):
@@ -16,6 +14,7 @@ def test_vector(doc):
assert m.cast_bool_vector() == [True, False]
assert m.load_bool_vector([True, False])
+ assert m.load_bool_vector(tuple([True, False]))
assert doc(m.cast_vector) == "cast_vector() -> List[int]"
assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool"
@@ -38,6 +37,7 @@ def test_array(doc):
lst = m.cast_array()
assert lst == [1, 2]
assert m.load_array(lst)
+ assert m.load_array(tuple(lst))
assert doc(m.cast_array) == "cast_array() -> List[int[2]]"
assert doc(m.load_array) == "load_array(arg0: List[int[2]]) -> bool"
@@ -48,6 +48,7 @@ def test_valarray(doc):
lst = m.cast_valarray()
assert lst == [1, 4, 9]
assert m.load_valarray(lst)
+ assert m.load_valarray(tuple(lst))
assert doc(m.cast_valarray) == "cast_valarray() -> List[int]"
assert doc(m.load_valarray) == "load_valarray(arg0: List[int]) -> bool"
@@ -72,6 +73,7 @@ def test_set(doc):
assert s == {"key1", "key2"}
s.add("key3")
assert m.load_set(s)
+ assert m.load_set(frozenset(s))
assert doc(m.cast_set) == "cast_set() -> Set[str]"
assert doc(m.load_set) == "load_set(arg0: Set[str]) -> bool"
@@ -133,6 +135,10 @@ def test_optional():
assert mvalue.initialized
assert holder.member_initialized()
+ props = m.OptionalProperties()
+ assert int(props.access_by_ref) == 42
+ assert int(props.access_by_copy) == 42
+
@pytest.mark.skipif(
not hasattr(m, "has_exp_optional"), reason="no <experimental/optional>"
@@ -161,6 +167,88 @@ def test_exp_optional():
assert mvalue.initialized
assert holder.member_initialized()
+ props = m.OptionalExpProperties()
+ assert int(props.access_by_ref) == 42
+ assert int(props.access_by_copy) == 42
+
+
+@pytest.mark.skipif(not hasattr(m, "has_boost_optional"), reason="no <boost/optional>")
+def test_boost_optional():
+ assert m.double_or_zero_boost(None) == 0
+ assert m.double_or_zero_boost(42) == 84
+ pytest.raises(TypeError, m.double_or_zero_boost, "foo")
+
+ assert m.half_or_none_boost(0) is None
+ assert m.half_or_none_boost(42) == 21
+ pytest.raises(TypeError, m.half_or_none_boost, "foo")
+
+ assert m.test_nullopt_boost() == 42
+ assert m.test_nullopt_boost(None) == 42
+ assert m.test_nullopt_boost(42) == 42
+ assert m.test_nullopt_boost(43) == 43
+
+ assert m.test_no_assign_boost() == 42
+ assert m.test_no_assign_boost(None) == 42
+ assert m.test_no_assign_boost(m.NoAssign(43)) == 43
+ pytest.raises(TypeError, m.test_no_assign_boost, 43)
+
+ holder = m.OptionalBoostHolder()
+ mvalue = holder.member
+ assert mvalue.initialized
+ assert holder.member_initialized()
+
+ props = m.OptionalBoostProperties()
+ assert int(props.access_by_ref) == 42
+ assert int(props.access_by_copy) == 42
+
+
+def test_reference_sensitive_optional():
+ assert m.double_or_zero_refsensitive(None) == 0
+ assert m.double_or_zero_refsensitive(42) == 84
+ pytest.raises(TypeError, m.double_or_zero_refsensitive, "foo")
+
+ assert m.half_or_none_refsensitive(0) is None
+ assert m.half_or_none_refsensitive(42) == 21
+ pytest.raises(TypeError, m.half_or_none_refsensitive, "foo")
+
+ assert m.test_nullopt_refsensitive() == 42
+ assert m.test_nullopt_refsensitive(None) == 42
+ assert m.test_nullopt_refsensitive(42) == 42
+ assert m.test_nullopt_refsensitive(43) == 43
+
+ assert m.test_no_assign_refsensitive() == 42
+ assert m.test_no_assign_refsensitive(None) == 42
+ assert m.test_no_assign_refsensitive(m.NoAssign(43)) == 43
+ pytest.raises(TypeError, m.test_no_assign_refsensitive, 43)
+
+ holder = m.OptionalRefSensitiveHolder()
+ mvalue = holder.member
+ assert mvalue.initialized
+ assert holder.member_initialized()
+
+ props = m.OptionalRefSensitiveProperties()
+ assert int(props.access_by_ref) == 42
+ assert int(props.access_by_copy) == 42
+
+
+@pytest.mark.skipif(not hasattr(m, "has_filesystem"), reason="no <filesystem>")
+def test_fs_path():
+ from pathlib import Path
+
+ class PseudoStrPath:
+ def __fspath__(self):
+ return "foo/bar"
+
+ class PseudoBytesPath:
+ def __fspath__(self):
+ return b"foo/bar"
+
+ assert m.parent_path(Path("foo/bar")) == Path("foo")
+ assert m.parent_path("foo/bar") == Path("foo")
+ assert m.parent_path(b"foo/bar") == Path("foo")
+ assert m.parent_path(PseudoStrPath()) == Path("foo")
+ assert m.parent_path(PseudoBytesPath()) == Path("foo")
+
@pytest.mark.skipif(not hasattr(m, "load_variant"), reason="no <variant>")
def test_variant(doc):
@@ -179,6 +267,22 @@ def test_variant(doc):
)
+@pytest.mark.skipif(
+ not hasattr(m, "load_monostate_variant"), reason="no std::monostate"
+)
+def test_variant_monostate(doc):
+ assert m.load_monostate_variant(None) == "std::monostate"
+ assert m.load_monostate_variant(1) == "int"
+ assert m.load_monostate_variant("1") == "std::string"
+
+ assert m.cast_monostate_variant() == (None, 5, "Hello")
+
+ assert (
+ doc(m.load_monostate_variant)
+ == "load_monostate_variant(arg0: Union[None, int, str]) -> str"
+ )
+
+
def test_vec_of_reference_wrapper():
"""#171: Can't return reference wrappers (or STL structures containing them)"""
assert (
@@ -198,7 +302,7 @@ def test_stl_pass_by_pointer(msg):
1. (v: List[int] = None) -> List[int]
Invoked with:
- """ # noqa: E501 line too long
+ """
)
with pytest.raises(TypeError) as excinfo:
@@ -210,7 +314,7 @@ def test_stl_pass_by_pointer(msg):
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]
@@ -259,8 +363,15 @@ def test_array_cast_sequence():
def test_issue_1561():
- """ check fix for issue #1561 """
+ """check fix for issue #1561"""
bar = m.Issue1561Outer()
bar.list = [m.Issue1561Inner("bar")]
bar.list
assert bar.list[0].data == "bar"
+
+
+def test_return_vector_bool_raw_ptr():
+ # Add `while True:` for manual leak checking.
+ v = m.return_vector_bool_raw_ptr()
+ assert isinstance(v, list)
+ assert len(v) == 4513
diff --git a/3rdparty/pybind11/tests/test_stl_binders.cpp b/3rdparty/pybind11/tests/test_stl_binders.cpp
index 1c0df984..ca9630bd 100644
--- a/3rdparty/pybind11/tests/test_stl_binders.cpp
+++ b/3rdparty/pybind11/tests/test_stl_binders.cpp
@@ -7,23 +7,24 @@
BSD-style license that can be found in the LICENSE file.
*/
+#include <pybind11/numpy.h>
+#include <pybind11/stl_bind.h>
+
#include "pybind11_tests.h"
-#include <pybind11/stl_bind.h>
-#include <pybind11/numpy.h>
-#include <map>
#include <deque>
+#include <map>
#include <unordered_map>
class El {
public:
El() = delete;
- El(int v) : a(v) { }
+ explicit El(int v) : a(v) {}
int a;
};
-std::ostream & operator<<(std::ostream &s, El const&v) {
+std::ostream &operator<<(std::ostream &s, El const &v) {
s << "El{" << v.a << '}';
return s;
}
@@ -40,25 +41,32 @@ public:
int value;
};
-template <class Container> Container *one_to_n(int n) {
- auto v = new Container();
- for (int i = 1; i <= n; i++)
+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));
+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));
+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;
}
@@ -67,8 +75,7 @@ TEST_SUBMODULE(stl_binders, m) {
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::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");
@@ -78,52 +85,68 @@ TEST_SUBMODULE(stl_binders, m) {
// 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::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);
+ 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);
+ m.def("get_vnc", &one_to_n<std::vector<E_nc>>);
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);
+ m.def("get_dnc", &one_to_n<std::deque<E_nc>>);
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);
+ m.def("get_mnc", &times_ten<std::map<int, E_nc>>);
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);
+ m.def("get_umnc", &times_ten<std::unordered_map<int, E_nc>>);
// 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);
+ 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::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);
+ m.def("get_nmnc", &times_hundred<std::map<int, std::map<int, E_nc>>>);
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);
+ m.def("get_numnc", &times_hundred<std::unordered_map<int, std::unordered_map<int, E_nc>>>);
// 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());
+ 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; }
+ try {
+ py::module_::import("numpy");
+ } catch (...) {
+ return;
+ }
// test_vector_buffer_numpy
- struct VStruct { bool w; uint32_t x; double y; bool z; };
+ 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}};});
+ m.def("get_vectorstruct", [] {
+ return std::vector<VStruct>{{false, 5, 3.0, true}, {true, 30, -1e4, false}};
+ });
}
diff --git a/3rdparty/pybind11/tests/test_stl_binders.py b/3rdparty/pybind11/tests/test_stl_binders.py
index 84132a2b..d5e9ccce 100644
--- a/3rdparty/pybind11/tests/test_stl_binders.py
+++ b/3rdparty/pybind11/tests/test_stl_binders.py
@@ -1,8 +1,5 @@
-# -*- coding: utf-8 -*-
import pytest
-import env # noqa: F401
-
from pybind11_tests import stl_binders as m
@@ -75,18 +72,13 @@ def test_vector_buffer():
assert v[1] == 2
v[2] = 5
mv = memoryview(v) # We expose the buffer interface
- if not env.PY2:
- assert mv[2] == 5
- mv[2] = 6
- else:
- assert mv[2] == "\x05"
- mv[2] = "\x06"
+ assert mv[2] == 5
+ mv[2] = 6
assert v[2] == 6
- if not env.PY2:
- mv = memoryview(b)
- v = m.VectorUChar(mv[::2])
- assert v[1] == 3
+ mv = memoryview(b)
+ v = m.VectorUChar(mv[::2])
+ assert v[1] == 3
with pytest.raises(RuntimeError) as excinfo:
m.create_undeclstruct() # Undeclared struct contents, no buffer interface
@@ -161,15 +153,43 @@ def test_map_string_double():
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}"
+ assert "b" in mm
+ assert "c" not in mm
+ assert 123 not in mm
+
+ # Check that keys, values, items are views, not merely iterable
+ keys = mm.keys()
+ values = mm.values()
+ items = mm.items()
+ assert list(keys) == ["a", "b"]
+ assert len(keys) == 2
+ assert "a" in keys
+ assert "c" not in keys
+ assert 123 not in keys
+ assert list(items) == [("a", 1), ("b", 2.5)]
+ assert len(items) == 2
+ assert ("b", 2.5) in items
+ assert "hello" not in items
+ assert ("b", 2.5, None) not in items
+ assert list(values) == [1, 2.5]
+ assert len(values) == 2
+ assert 1 in values
+ assert 2 not in values
+ # Check that views update when the map is updated
+ mm["c"] = -1
+ assert list(keys) == ["a", "b", "c"]
+ assert list(values) == [1, 2.5, -1]
+ assert list(items) == [("a", 1), ("b", 2.5), ("c", -1)]
um = m.UnorderedMapStringDouble()
um["ua"] = 1.1
um["ub"] = 2.6
assert sorted(list(um)) == ["ua", "ub"]
+ assert list(um.keys()) == list(um)
assert sorted(list(um.items())) == [("ua", 1.1), ("ub", 2.6)]
+ assert list(zip(um.keys(), um.values())) == list(um.items())
assert "UnorderedMapStringDouble" in str(um)
diff --git a/3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp b/3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp
index 838a168d..12ba6532 100644
--- a/3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp
+++ b/3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp
@@ -7,11 +7,11 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
#include <pybind11/stl.h>
-struct Animal
-{
+#include "pybind11_tests.h"
+
+struct Animal {
// Make this type also a "standard" polymorphic type, to confirm that
// specializing polymorphic_type_hook using enable_if_t still works
// (https://github.com/pybind/pybind11/pull/2016/).
@@ -20,55 +20,54 @@ struct Animal
// Enum for tag-based polymorphism.
enum class Kind {
Unknown = 0,
- Dog = 100, Labrador, Chihuahua, LastDog = 199,
- Cat = 200, Panther, LastCat = 299
+ Dog = 100,
+ Labrador,
+ Chihuahua,
+ LastDog = 199,
+ Cat = 200,
+ Panther,
+ LastCat = 299
};
- static const std::type_info* type_of_kind(Kind kind);
+ 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)
- {}
+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) {}
+struct Dog : Animal {
+ explicit 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)
+struct Labrador : Dog {
+ explicit 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"; }
+struct Chihuahua : Dog {
+ explicit 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) {}
+struct Cat : Animal {
+ explicit 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) {}
+struct Panther : Cat {
+ explicit 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>> create_zoo() {
std::vector<std::unique_ptr<Animal>> ret;
ret.emplace_back(new Labrador("Fido", 15000));
@@ -83,45 +82,53 @@ std::vector<std::unique_ptr<Animal>> create_zoo()
return ret;
}
-const std::type_info* Animal::type_of_kind(Kind kind)
-{
+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;
+ case Kind::Unknown:
+ case Kind::Dog:
+ break;
+
+ case Kind::Labrador:
+ return &typeid(Labrador);
+ case Kind::Chihuahua:
+ return &typeid(Chihuahua);
+
+ case Kind::LastDog:
+ 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);
+ 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 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; }
- };
-} // namespace pybind11
+namespace PYBIND11_NAMESPACE {
+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;
+ }
+};
+} // namespace PYBIND11_NAMESPACE
TEST_SUBMODULE(tagbased_polymorphic, m) {
- py::class_<Animal>(m, "Animal")
- .def_readonly("name", &Animal::name);
+ 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)
@@ -132,9 +139,7 @@ TEST_SUBMODULE(tagbased_polymorphic, m) {
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_<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);
diff --git a/3rdparty/pybind11/tests/test_tagbased_polymorphic.py b/3rdparty/pybind11/tests/test_tagbased_polymorphic.py
index 64eb8a3c..84f0ea71 100644
--- a/3rdparty/pybind11/tests/test_tagbased_polymorphic.py
+++ b/3rdparty/pybind11/tests/test_tagbased_polymorphic.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
from pybind11_tests import tagbased_polymorphic as m
diff --git a/3rdparty/pybind11/tests/test_thread.cpp b/3rdparty/pybind11/tests/test_thread.cpp
new file mode 100644
index 00000000..1536503b
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_thread.cpp
@@ -0,0 +1,66 @@
+/*
+ tests/test_thread.cpp -- call pybind11 bound methods in threads
+
+ Copyright (c) 2021 Laramie Leavitt (Google LLC) <lar@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/cast.h>
+#include <pybind11/pybind11.h>
+
+#include "pybind11_tests.h"
+
+#include <chrono>
+#include <thread>
+
+namespace py = pybind11;
+
+namespace {
+
+struct IntStruct {
+ explicit IntStruct(int v) : value(v){};
+ ~IntStruct() { value = -value; }
+ IntStruct(const IntStruct &) = default;
+ IntStruct &operator=(const IntStruct &) = default;
+
+ int value;
+};
+
+} // namespace
+
+TEST_SUBMODULE(thread, m) {
+
+ py::class_<IntStruct>(m, "IntStruct").def(py::init([](const int i) { return IntStruct(i); }));
+
+ // implicitly_convertible uses loader_life_support when an implicit
+ // conversion is required in order to lifetime extend the reference.
+ //
+ // This test should be run with ASAN for better effectiveness.
+ py::implicitly_convertible<int, IntStruct>();
+
+ m.def("test", [](int expected, const IntStruct &in) {
+ {
+ py::gil_scoped_release release;
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+ }
+
+ if (in.value != expected) {
+ throw std::runtime_error("Value changed!!");
+ }
+ });
+
+ m.def(
+ "test_no_gil",
+ [](int expected, const IntStruct &in) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+ if (in.value != expected) {
+ throw std::runtime_error("Value changed!!");
+ }
+ },
+ py::call_guard<py::gil_scoped_release>());
+
+ // NOTE: std::string_view also uses loader_life_support to ensure that
+ // the string contents remain alive, but that's a C++ 17 feature.
+}
diff --git a/3rdparty/pybind11/tests/test_thread.py b/3rdparty/pybind11/tests/test_thread.py
new file mode 100644
index 00000000..e89991f9
--- /dev/null
+++ b/3rdparty/pybind11/tests/test_thread.py
@@ -0,0 +1,42 @@
+import threading
+
+from pybind11_tests import thread as m
+
+
+class Thread(threading.Thread):
+ def __init__(self, fn):
+ super().__init__()
+ self.fn = fn
+ self.e = None
+
+ def run(self):
+ try:
+ for i in range(10):
+ self.fn(i, i)
+ except Exception as e:
+ self.e = e
+
+ def join(self):
+ super().join()
+ if self.e:
+ raise self.e
+
+
+def test_implicit_conversion():
+ a = Thread(m.test)
+ b = Thread(m.test)
+ c = Thread(m.test)
+ for x in [a, b, c]:
+ x.start()
+ for x in [c, b, a]:
+ x.join()
+
+
+def test_implicit_conversion_no_gil():
+ a = Thread(m.test_no_gil)
+ b = Thread(m.test_no_gil)
+ c = Thread(m.test_no_gil)
+ for x in [a, b, c]:
+ x.start()
+ for x in [c, b, a]:
+ x.join()
diff --git a/3rdparty/pybind11/tests/test_union.py b/3rdparty/pybind11/tests/test_union.py
index 2a2c12fb..e1866e70 100644
--- a/3rdparty/pybind11/tests/test_union.py
+++ b/3rdparty/pybind11/tests/test_union.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
from pybind11_tests import union_ as m
diff --git a/3rdparty/pybind11/tests/test_virtual_functions.cpp b/3rdparty/pybind11/tests/test_virtual_functions.cpp
index 685d64a7..323aa0d2 100644
--- a/3rdparty/pybind11/tests/test_virtual_functions.cpp
+++ b/3rdparty/pybind11/tests/test_virtual_functions.cpp
@@ -7,22 +7,28 @@
BSD-style license that can be found in the LICENSE file.
*/
-#include "pybind11_tests.h"
-#include "constructor_stats.h"
#include <pybind11/functional.h>
+
+#include "constructor_stats.h"
+#include "pybind11_tests.h"
+
#include <thread>
/* This is an example class that we'll want to be able to extend from Python */
-class ExampleVirt {
+class ExampleVirt {
public:
- ExampleVirt(int state) : state(state) { print_created(this, state); }
+ explicit 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; }
+ ExampleVirt(ExampleVirt &&e) noexcept : 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()));
+ "ExampleVirt::run(state={}, value={}, str1={}, str2={})"_s.format(
+ state, value, get_string1(), *get_string2()));
return state + value;
}
@@ -30,8 +36,8 @@ public:
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).
+ // 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; }
@@ -47,66 +53,63 @@ public:
int run(int value) override {
/* Generate wrapping code that enables native function overloading */
- PYBIND11_OVERRIDE(
- int, /* Return type */
- ExampleVirt, /* Parent class */
- run, /* Name of function */
- value /* Argument(s) */
+ PYBIND11_OVERRIDE(int, /* Return type */
+ ExampleVirt, /* Parent class */
+ run, /* Name of function */
+ value /* Argument(s) */
);
}
bool run_bool() override {
- PYBIND11_OVERRIDE_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 */
+ PYBIND11_OVERRIDE_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_OVERRIDE_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 */
+ PYBIND11_OVERRIDE_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_OVERRIDE(
- const std::string &, /* Return type */
- ExampleVirt, /* Parent class */
- get_string1, /* Name of function */
- /* (no arguments) */
+ PYBIND11_OVERRIDE(const std::string &, /* Return type */
+ ExampleVirt, /* Parent class */
+ get_string1, /* Name of function */
+ /* (no arguments) */
);
}
const std::string *get_string2() override {
- PYBIND11_OVERRIDE(
- const std::string *, /* Return type */
- ExampleVirt, /* Parent class */
- get_string2, /* Name of function */
- /* (no arguments) */
+ PYBIND11_OVERRIDE(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(int a, int b) : value{new int(a * b)} { print_created(this, a, b); }
+ NonCopyable(NonCopyable &&o) noexcept : 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)";
+ if (value) {
+ return std::to_string(*value);
+ }
+ return "(null)";
}
~NonCopyable() { print_destroyed(this); }
@@ -118,11 +121,12 @@ private:
// 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); }
+ 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) noexcept : value{m.value} { print_move_created(this); }
std::string get_value() const { return std::to_string(value); }
~Movable() { print_destroyed(this); }
+
private:
int value;
};
@@ -131,7 +135,7 @@ class NCVirt {
public:
virtual ~NCVirt() = default;
NCVirt() = default;
- NCVirt(const NCVirt&) = delete;
+ NCVirt(const NCVirt &) = delete;
virtual NonCopyable get_noncopyable(int a, int b) { return NonCopyable(a, b); }
virtual Movable get_movable(int a, int b) = 0;
@@ -150,11 +154,10 @@ class NCVirtTrampoline : public NCVirt {
};
struct Base {
- /* for some reason MSVC2015 can't compile this if the function is pure virtual */
- virtual std::string dispatch() const { return {}; };
+ virtual std::string dispatch() const = 0;
virtual ~Base() = default;
Base() = default;
- Base(const Base&) = delete;
+ Base(const Base &) = delete;
};
struct DispatchIssue : Base {
@@ -163,18 +166,37 @@ struct DispatchIssue : Base {
}
};
+// An abstract adder class that uses visitor pattern to add two data
+// objects and send the result to the visitor functor
+struct AdderBase {
+ struct Data {};
+ using DataVisitor = std::function<void(const Data &)>;
+
+ virtual void
+ operator()(const Data &first, const Data &second, const DataVisitor &visitor) const = 0;
+ virtual ~AdderBase() = default;
+ AdderBase() = default;
+ AdderBase(const AdderBase &) = delete;
+};
+
+struct Adder : AdderBase {
+ void
+ operator()(const Data &first, const Data &second, const DataVisitor &visitor) const override {
+ PYBIND11_OVERRIDE_PURE_NAME(
+ void, AdderBase, "__call__", operator(), first, second, visitor);
+ }
+};
+
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() {
@@ -184,9 +206,28 @@ static void test_gil_from_thread() {
t.join();
}
+class test_override_cache_helper {
+
+public:
+ virtual int func() { return 0; }
+
+ test_override_cache_helper() = default;
+ virtual ~test_override_cache_helper() = default;
+ // Non-copyable
+ test_override_cache_helper &operator=(test_override_cache_helper const &Right) = delete;
+ test_override_cache_helper(test_override_cache_helper const &Copy) = delete;
+};
+
+class test_override_cache_helper_trampoline : public test_override_cache_helper {
+ int func() override { PYBIND11_OVERRIDE(int, test_override_cache_helper, func); }
+};
-// Forward declaration (so that we can put the main tests here; the inherited virtual approaches are
-// rather long).
+inline int test_override_cache(std::shared_ptr<test_override_cache_helper> const &instance) {
+ return instance->func();
+}
+
+// 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) {
@@ -198,11 +239,9 @@ TEST_SUBMODULE(virtual_functions, m) {
.def("run_bool", &ExampleVirt::run_bool)
.def("pure_virtual", &ExampleVirt::pure_virtual);
- py::class_<NonCopyable>(m, "NonCopyable")
- .def(py::init<int, int>());
+ py::class_<NonCopyable>(m, "NonCopyable").def(py::init<int, int>());
- py::class_<Movable>(m, "Movable")
- .def(py::init<int, int>());
+ py::class_<Movable>(m, "Movable").def(py::init<int, int>());
// test_move_support
#if !defined(__INTEL_COMPILER) && !defined(__CUDACC__) && !defined(__PGIC__)
@@ -215,7 +254,7 @@ TEST_SUBMODULE(virtual_functions, m) {
#endif
m.def("runExampleVirt", [](ExampleVirt *ex, int value) { return ex->run(value); });
- m.def("runExampleVirtBool", [](ExampleVirt* ex) { return ex->run_bool(); });
+ m.def("runExampleVirtBool", [](ExampleVirt *ex) { return ex->run_bool(); });
m.def("runExampleVirtVirtual", [](ExampleVirt *ex) { ex->pure_virtual(); });
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
@@ -226,27 +265,25 @@ TEST_SUBMODULE(virtual_functions, m) {
// that were not extended on the Python side
struct A {
A() = default;
- A(const A&) = delete;
+ A(const A &) = delete;
virtual ~A() = default;
virtual void f() { py::print("A.f()"); }
};
struct PyA : A {
PyA() { py::print("PyA.PyA()"); }
- PyA(const PyA&) = delete;
+ PyA(const PyA &) = delete;
~PyA() override { 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 ,
+ // This convolution just gives a `void`, but tests that PYBIND11_TYPE() works to
+ // protect a type containing a ,
PYBIND11_OVERRIDE(PYBIND11_TYPE(typename std::enable_if<true, void>::type), A, f);
}
};
- py::class_<A, PyA>(m, "A")
- .def(py::init<>())
- .def("f", &A::f);
+ py::class_<A, PyA>(m, "A").def(py::init<>()).def("f", &A::f);
m.def("call_f", [](A *a) { a->f(); });
@@ -254,14 +291,14 @@ TEST_SUBMODULE(virtual_functions, m) {
// ... unless we explicitly request it, as in this example:
struct A2 {
A2() = default;
- A2(const A2&) = delete;
+ A2(const A2 &) = delete;
virtual ~A2() = default;
virtual void f() { py::print("A2.f()"); }
};
struct PyA2 : A2 {
PyA2() { py::print("PyA2.PyA2()"); }
- PyA2(const PyA2&) = delete;
+ PyA2(const PyA2 &) = delete;
~PyA2() override { py::print("PyA2.~PyA2()"); }
void f() override {
py::print("PyA2.f()");
@@ -282,18 +319,46 @@ TEST_SUBMODULE(virtual_functions, m) {
.def(py::init<>())
.def("dispatch", &Base::dispatch);
- m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
+ m.def("dispatch_issue_go", [](const Base *b) { return b->dispatch(); });
+
+ // test_recursive_dispatch_issue
+ // #3357: Recursive dispatch fails to find python function override
+ pybind11::class_<AdderBase, Adder>(m, "Adder")
+ .def(pybind11::init<>())
+ .def("__call__", &AdderBase::operator());
+
+ pybind11::class_<AdderBase::Data>(m, "Data").def(pybind11::init<>());
+
+ m.def("add2",
+ [](const AdderBase::Data &first,
+ const AdderBase::Data &second,
+ const AdderBase &adder,
+ const AdderBase::DataVisitor &visitor) { adder(first, second, visitor); });
+
+ m.def("add3",
+ [](const AdderBase::Data &first,
+ const AdderBase::Data &second,
+ const AdderBase::Data &third,
+ const AdderBase &adder,
+ const AdderBase::DataVisitor &visitor) {
+ adder(first, second, [&](const AdderBase::Data &first_plus_second) {
+ // NOLINTNEXTLINE(readability-suspicious-call-argument)
+ adder(first_plus_second, third, visitor);
+ });
+ });
// test_override_ref
// #392/397: overriding reference-returning functions
class OverrideTest {
public:
- struct A { std::string value = "hi"; };
+ struct A {
+ std::string value = "hi";
+ };
std::string v;
A a;
explicit OverrideTest(const std::string &v) : v{v} {}
OverrideTest() = default;
- OverrideTest(const OverrideTest&) = delete;
+ OverrideTest(const OverrideTest &) = delete;
virtual std::string str_value() { return v; }
virtual std::string &str_ref() { return v; }
virtual A A_value() { return a; }
@@ -304,14 +369,22 @@ TEST_SUBMODULE(virtual_functions, m) {
class PyOverrideTest : public OverrideTest {
public:
using OverrideTest::OverrideTest;
- std::string str_value() override { PYBIND11_OVERRIDE(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_OVERRIDE(std::string &, OverrideTest, str_ref); }
+ std::string str_value() override {
+ PYBIND11_OVERRIDE(std::string, OverrideTest, str_value);
+ }
+ // Not allowed (enabling the below 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:
+#ifdef PYBIND11_NEVER_DEFINED_EVER
+ std::string &str_ref() override {
+ PYBIND11_OVERRIDE(std::string &, OverrideTest, str_ref);
+ }
+#endif
// But we can work around it like this:
private:
std::string _tmp;
std::string str_ref_helper() { PYBIND11_OVERRIDE(std::string, OverrideTest, str_ref); }
+
public:
std::string &str_ref() override { return _tmp = str_ref_helper(); }
@@ -324,11 +397,20 @@ TEST_SUBMODULE(virtual_functions, m) {
py::class_<OverrideTest, PyOverrideTest>(m, "OverrideTest")
.def(py::init<const std::string &>())
.def("str_value", &OverrideTest::str_value)
-// .def("str_ref", &OverrideTest::str_ref)
+#ifdef PYBIND11_NEVER_DEFINED_EVER
+ .def("str_ref", &OverrideTest::str_ref)
+#endif
.def("A_value", &OverrideTest::A_value)
.def("A_ref", &OverrideTest::A_ref);
-}
+ py::class_<test_override_cache_helper,
+ test_override_cache_helper_trampoline,
+ std::shared_ptr<test_override_cache_helper>>(m, "test_override_cache_helper")
+ .def(py::init_alias<>())
+ .def("func", &test_override_cache_helper::func);
+
+ m.def("test_override_cache", test_override_cache);
+}
// Inheriting virtual methods. We do two versions here: the repeat-everything version and the
// templated trampoline versions mentioned in docs/advanced.rst.
@@ -338,94 +420,107 @@ TEST_SUBMODULE(virtual_functions, m) {
// 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()); \
+#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
+ A_METHODS
A_Repeat() = default;
- A_Repeat(const A_Repeat&) = delete;
+ A_Repeat(const A_Repeat &) = delete;
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"; \
- } \
+#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
+ B_METHODS
};
class C_Repeat : public B_Repeat {
-#define C_METHODS \
-public: \
- int unlucky_number() override { return 4444; } \
+#define C_METHODS \
+public: \
+ int unlucky_number() override { return 4444; } \
double lucky_number() override { return 888; }
-C_METHODS
+ C_METHODS
};
class D_Repeat : public C_Repeat {
#define D_METHODS // Nothing overridden.
-D_METHODS
+ D_METHODS
};
// Base classes for templated inheritance trampolines. Identical to the repeat-everything version:
class A_Tpl {
A_METHODS;
A_Tpl() = default;
- A_Tpl(const A_Tpl&) = delete;
+ A_Tpl(const A_Tpl &) = delete;
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 };
-
+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_OVERRIDE_PURE(int, A_Repeat, unlucky_number, ); }
- std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, A_Repeat, say_something, times); }
+ std::string say_something(unsigned times) override {
+ PYBIND11_OVERRIDE(std::string, A_Repeat, say_something, times);
+ }
};
class PyB_Repeat : public B_Repeat {
public:
using B_Repeat::B_Repeat;
int unlucky_number() override { PYBIND11_OVERRIDE(int, B_Repeat, unlucky_number, ); }
- std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, B_Repeat, say_something, times); }
+ std::string say_something(unsigned times) override {
+ PYBIND11_OVERRIDE(std::string, B_Repeat, say_something, times);
+ }
double lucky_number() override { PYBIND11_OVERRIDE(double, B_Repeat, lucky_number, ); }
};
class PyC_Repeat : public C_Repeat {
public:
using C_Repeat::C_Repeat;
int unlucky_number() override { PYBIND11_OVERRIDE(int, C_Repeat, unlucky_number, ); }
- std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, C_Repeat, say_something, times); }
+ std::string say_something(unsigned times) override {
+ PYBIND11_OVERRIDE(std::string, C_Repeat, say_something, times);
+ }
double lucky_number() override { PYBIND11_OVERRIDE(double, C_Repeat, lucky_number, ); }
};
class PyD_Repeat : public D_Repeat {
public:
using D_Repeat::D_Repeat;
int unlucky_number() override { PYBIND11_OVERRIDE(int, D_Repeat, unlucky_number, ); }
- std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, D_Repeat, say_something, times); }
+ std::string say_something(unsigned times) override {
+ PYBIND11_OVERRIDE(std::string, D_Repeat, say_something, times);
+ }
double lucky_number() override { PYBIND11_OVERRIDE(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.
+// - 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
@@ -437,17 +532,20 @@ class PyA_Tpl : public Base {
public:
using Base::Base; // Inherit constructors
int unlucky_number() override { PYBIND11_OVERRIDE_PURE(int, Base, unlucky_number, ); }
- std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, Base, say_something, times); }
+ std::string say_something(unsigned times) override {
+ PYBIND11_OVERRIDE(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)
+ // NOLINTNEXTLINE(bugprone-parent-virtual-call)
int unlucky_number() override { PYBIND11_OVERRIDE(int, Base, unlucky_number, ); }
double lucky_number() override { PYBIND11_OVERRIDE(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):
+// 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:
@@ -471,10 +569,8 @@ void initialize_inherited_virtuals(py::module_ &m) {
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<>());
+ 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
@@ -486,11 +582,8 @@ void initialize_inherited_virtuals(py::module_ &m) {
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<>());
-
+ 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);
diff --git a/3rdparty/pybind11/tests/test_virtual_functions.py b/3rdparty/pybind11/tests/test_virtual_functions.py
index ae199301..4d00d369 100644
--- a/3rdparty/pybind11/tests/test_virtual_functions.py
+++ b/3rdparty/pybind11/tests/test_virtual_functions.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
import pytest
import env # noqa: F401
@@ -10,12 +9,12 @@ from pybind11_tests import ConstructorStats # noqa: E402
def test_override(capture, msg):
class ExtendedExampleVirt(m.ExampleVirt):
def __init__(self, state):
- super(ExtendedExampleVirt, self).__init__(state + 1)
+ super().__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)
+ print(f"ExtendedExampleVirt::run({value}), calling parent..")
+ return super().run(value + 1)
def run_bool(self):
print("ExtendedExampleVirt::run_bool()")
@@ -25,11 +24,11 @@ def test_override(capture, msg):
return "override1"
def pure_virtual(self):
- print("ExtendedExampleVirt::pure_virtual(): %s" % self.data)
+ print(f"ExtendedExampleVirt::pure_virtual(): {self.data}")
class ExtendedExampleVirt2(ExtendedExampleVirt):
def __init__(self, state):
- super(ExtendedExampleVirt2, self).__init__(state + 1)
+ super().__init__(state + 1)
def get_string2(self):
return "override2"
@@ -41,7 +40,7 @@ def test_override(capture, msg):
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:
@@ -59,7 +58,7 @@ def test_override(capture, msg):
== """
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
@@ -76,7 +75,7 @@ def test_override(capture, msg):
== """
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)
@@ -97,7 +96,7 @@ def test_alias_delay_initialization1(capture):
class B(m.A):
def __init__(self):
- super(B, self).__init__()
+ super().__init__()
def f(self):
print("In python f()")
@@ -137,7 +136,7 @@ def test_alias_delay_initialization2(capture):
class B2(m.A2):
def __init__(self):
- super(B2, self).__init__()
+ super().__init__()
def f(self):
print("In python B2.f()")
@@ -245,19 +244,51 @@ def test_dispatch_issue(msg):
class PyClass2(m.DispatchIssue):
def dispatch(self):
with pytest.raises(RuntimeError) as excinfo:
- super(PyClass2, self).dispatch()
+ super().dispatch()
assert (
msg(excinfo.value)
== 'Tried to call pure virtual function "Base::dispatch"'
)
- p = PyClass1()
- return m.dispatch_issue_go(p)
+ return m.dispatch_issue_go(PyClass1())
b = PyClass2()
assert m.dispatch_issue_go(b) == "Yay.."
+def test_recursive_dispatch_issue(msg):
+ """#3357: Recursive dispatch fails to find python function override"""
+
+ class Data(m.Data):
+ def __init__(self, value):
+ super().__init__()
+ self.value = value
+
+ class Adder(m.Adder):
+ def __call__(self, first, second, visitor):
+ # lambda is a workaround, which adds extra frame to the
+ # current CPython thread. Removing lambda reveals the bug
+ # [https://github.com/pybind/pybind11/issues/3357]
+ (lambda: visitor(Data(first.value + second.value)))()
+
+ class StoreResultVisitor:
+ def __init__(self):
+ self.result = None
+
+ def __call__(self, data):
+ self.result = data.value
+
+ store = StoreResultVisitor()
+
+ m.add2(Data(1), Data(2), Adder(), store)
+ assert store.result == 3
+
+ # without lambda in Adder class, this function fails with
+ # RuntimeError: Tried to call pure virtual function "AdderBase::__call__"
+ m.add3(Data(1), Data(2), Data(3), Adder(), store)
+ assert store.result == 6
+
+
def test_override_ref():
"""#392/397: overriding reference-returning functions"""
o = m.OverrideTest("asdf")
@@ -407,3 +438,22 @@ 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()
+
+
+def test_python_override():
+ def func():
+ class Test(m.test_override_cache_helper):
+ def func(self):
+ return 42
+
+ return Test()
+
+ def func2():
+ class Test(m.test_override_cache_helper):
+ pass
+
+ return Test()
+
+ for _ in range(1500):
+ assert m.test_override_cache(func()) == 42
+ assert m.test_override_cache(func2()) == 0
diff --git a/3rdparty/pybind11/tests/valgrind-numpy-scipy.supp b/3rdparty/pybind11/tests/valgrind-numpy-scipy.supp
new file mode 100644
index 00000000..16db302c
--- /dev/null
+++ b/3rdparty/pybind11/tests/valgrind-numpy-scipy.supp
@@ -0,0 +1,140 @@
+# Valgrind suppression file for NumPy & SciPy errors and leaks in pybind11 tests
+#
+# On updating a dependency, to get a list of "default" leaks in e.g. NumPy, run
+# `PYTHONMALLOC=malloc valgrind --leak-check=full --show-leak-kinds=definite,indirect python3.9-dbg -c "import numpy"`
+# To use these suppression files, add e.g. `--suppressions=valgrind-numpy-scipy.supp`
+
+{
+ Leaks when importing NumPy
+ Memcheck:Leak
+ fun:malloc
+ fun:_PyMem_RawMalloc
+ fun:PyObject_Malloc
+ fun:_PyObject_GC_Alloc
+ fun:_PyObject_GC_Malloc
+ fun:_PyObject_GC_NewVar
+ fun:tuple_alloc
+ fun:PyTuple_Pack
+ ...
+ fun:__pyx_pymod_exec_*
+}
+
+{
+ Leaks when importing NumPy (bis)
+ Memcheck:Leak
+ fun:malloc
+ fun:_PyMem_RawMalloc
+ fun:PyObject_Malloc
+ fun:_PyObject_New
+ fun:PyCode_NewWithPosOnlyArgs
+ fun:PyCode_New
+ ...
+ fun:__pyx_pymod_exec_*
+}
+
+{
+ Leaks when importing NumPy (ter)
+ Memcheck:Leak
+ fun:malloc
+ fun:_PyMem_RawMalloc
+ fun:PyObject_Malloc
+ fun:_PyObject_GC_Alloc
+ fun:_PyObject_GC_Malloc
+ fun:_PyObject_GC_NewVar
+ fun:tuple_alloc
+ fun:_PyTuple_FromArray
+ fun:_PyObject_MakeTpCall
+ fun:_PyObject_VectorcallTstate
+ fun:PyObject_Vectorcall
+ fun:call_function
+ fun:_PyEval_EvalFrameDefault
+ fun:_PyEval_EvalFrame
+ fun:function_code_fastcall
+ fun:_PyFunction_Vectorcall
+}
+
+{
+ Leaks when importing NumPy (quater)
+ Memcheck:Leak
+ fun:malloc
+ fun:_PyMem_RawMalloc
+ fun:PyObject_Malloc
+ fun:_PyObject_GC_Alloc
+ fun:_PyObject_GC_Malloc
+ fun:_PyObject_GC_NewVar
+ fun:tuple_alloc
+ fun:_PyTuple_FromArray
+ fun:_PyObject_MakeTpCall
+ fun:_PyObject_VectorcallTstate
+ fun:_PyObject_CallFunctionVa
+ fun:PyObject_CallFunction
+ fun:PyImport_Import
+}
+
+{
+ Leaks when importing NumPy (quinquies)
+ Memcheck:Leak
+ fun:malloc
+ fun:_PyMem_RawMalloc
+ fun:PyObject_Malloc
+ fun:_PyObject_GC_Alloc
+ fun:_PyObject_GC_Malloc
+ fun:_PyObject_GC_NewVar
+ fun:tuple_alloc
+ fun:PyTuple_New
+ fun:r_object
+ fun:r_object
+ fun:r_object
+ fun:r_object
+}
+
+{
+ Leaks when importing NumPy (sexies)
+ Memcheck:Leak
+ fun:malloc
+ fun:_PyMem_RawMalloc
+ fun:PyObject_Malloc
+ fun:_PyObject_GC_Alloc
+ fun:_PyObject_GC_Malloc
+ fun:_PyObject_GC_NewVar
+ fun:tuple_alloc
+ fun:PyTuple_New
+ fun:dictiter_iternextitem
+ fun:list_extend
+ fun:_PyList_Extend
+ fun:PySequence_List
+}
+
+{
+ Leak when importing scipy.fft
+ Memcheck:Leak
+ fun:_Znwm
+ fun:PyInit_pypocketfft
+ fun:_PyImport_LoadDynamicModuleWithSpec
+ fun:_imp_create_dynamic_impl*
+ fun:_imp_create_dynamic
+ fun:cfunction_vectorcall_FASTCALL
+ fun:PyVectorcall_Call
+ fun:_PyObject_Call
+ fun:PyObject_Call
+ fun:do_call_core
+ fun:_PyEval_EvalFrameDefault
+ fun:_PyEval_EvalFrame
+ fun:_PyEval_EvalCode
+}
+
+{
+ NumPy leaks when spawning a subprocess
+ Memcheck:Leak
+ fun:malloc
+ ...
+ fun:_buffer_get_info
+ fun:array_getbuffer
+ fun:PyObject_GetBuffer
+ fun:__Pyx__GetBufferAndValidate*
+ fun:__pyx_f_5numpy_6random_13bit_generator_12SeedSequence_mix_entropy
+ fun:__pyx_pw_5numpy_6random_13bit_generator_12SeedSequence_1__init__
+ fun:type_call
+ fun:__Pyx__PyObject_CallOneArg
+ fun:__pyx_pw_5numpy_6random_13bit_generator_12BitGenerator_1__init__
+}
diff --git a/3rdparty/pybind11/tests/valgrind-python.supp b/3rdparty/pybind11/tests/valgrind-python.supp
new file mode 100644
index 00000000..d77d5e5c
--- /dev/null
+++ b/3rdparty/pybind11/tests/valgrind-python.supp
@@ -0,0 +1,117 @@
+# Valgrind suppression file for CPython errors and leaks in pybind11 tests
+
+# Taken verbatim from https://github.com/python/cpython/blob/3.9/Misc/valgrind-python.supp#L266-L272
+{
+ Uninitialised byte(s) false alarm, see bpo-35561
+ Memcheck:Param
+ epoll_ctl(event)
+ fun:epoll_ctl
+ fun:pyepoll_internal_ctl
+}
+
+{
+ Python leaks when spawning a subprocess
+ Memcheck:Leak
+ fun:malloc
+ fun:_PyMem_RawMalloc
+ fun:PyMem_RawMalloc
+ fun:PyThread_allocate_lock
+ fun:_PyEval_InitState
+ fun:PyInterpreterState_New
+ ...
+ fun:pyinit_core*
+ fun:Py_InitializeFromConfig
+ fun:pymain_init
+ fun:pymain_main
+}
+
+{
+ Python leaks when spawning a subprocess
+ Memcheck:Leak
+ fun:malloc
+ fun:_PyMem_RawMalloc
+ fun:_PyMem_DebugRawAlloc
+ fun:_PyMem_DebugRawMalloc
+ fun:PyMem_RawMalloc
+ fun:PyThread_allocate_lock
+ fun:_PyRuntimeState_Init_impl
+ fun:_PyRuntimeState_Init
+ fun:_PyRuntime_Initialize
+ fun:pymain_init
+ fun:pymain_main
+ fun:Py_BytesMain
+}
+
+{
+ Python leaks when spawning a subprocess
+ Memcheck:Leak
+ fun:malloc
+ fun:_PyMem_RawMalloc
+ fun:PyMem_RawMalloc
+ fun:PyThread_allocate_lock
+ fun:_PyImport_AcquireLock
+ fun:_imp_acquire_lock_impl*
+ fun:_imp_acquire_lock
+ fun:cfunction_vectorcall_NOARGS
+ fun:_PyObject_VectorcallTstate
+ fun:PyObject_Vectorcall
+ fun:call_function
+ fun:_PyEval_EvalFrameDefault
+ fun:_PyEval_EvalFrame
+ fun:function_code_fastcall
+}
+
+{
+ Python leaks when spawning a subprocess
+ Memcheck:Leak
+ fun:malloc
+ fun:_PyMem_RawMalloc
+ fun:PyMem_RawMalloc
+ fun:PyThread_allocate_lock
+ fun:newlockobject
+ ...
+ fun:cfunction_vectorcall_NOARGS
+ fun:_PyObject_VectorcallTstate
+ fun:PyObject_Vectorcall
+ fun:call_function
+ fun:_PyEval_EvalFrameDefault
+ fun:_PyEval_EvalFrame
+ fun:function_code_fastcall
+ fun:_PyFunction_Vectorcall
+}
+
+{
+ Python leaks when spawning a subprocess
+ Memcheck:Leak
+ fun:malloc
+ fun:_PyMem_RawMalloc
+ fun:PyMem_RawMalloc
+ fun:PyThread_allocate_lock
+ fun:rlock_new
+ fun:type_call
+ fun:_PyObject_Call
+ fun:PyObject_Call
+ fun:do_call_core
+ fun:_PyEval_EvalFrameDefault
+ fun:_PyEval_EvalFrame
+ fun:_PyEval_EvalCode
+ fun:_PyFunction_Vectorcall
+}
+
+# Not really CPython-specific, see link
+{
+ dlopen leak (https://stackoverflow.com/questions/1542457/memory-leak-reported-by-valgrind-in-dlopen)
+ Memcheck:Leak
+ fun:malloc
+ ...
+ fun:dl_open_worker
+ fun:_dl_catch_exception
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_exception
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_PyImport_FindSharedFuncptr
+ fun:_PyImport_LoadDynamicModuleWithSpec
+}