diff options
Diffstat (limited to '3rdparty/pybind11/tests')
96 files changed, 4431 insertions, 1554 deletions
| diff --git a/3rdparty/pybind11/tests/CMakeLists.txt b/3rdparty/pybind11/tests/CMakeLists.txt index 765c47ad..dae8b5ad 100644 --- a/3rdparty/pybind11/tests/CMakeLists.txt +++ b/3rdparty/pybind11/tests/CMakeLists.txt @@ -5,78 +5,150 @@  # All rights reserved. Use of this source code is governed by a  # BSD-style license that can be found in the LICENSE file. -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.4) -option(PYBIND11_WERROR  "Report all warnings as errors"  OFF) +# 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) +  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +else() +  cmake_policy(VERSION 3.18) +endif() + +# Only needed for CMake < 3.5 support +include(CMakeParseArguments) + +# Filter out items; print an optional message if any items filtered +# +# Usage: +#   pybind11_filter_tests(LISTNAME file1.cpp file2.cpp ... MESSAGE "") +# +macro(PYBIND11_FILTER_TESTS LISTNAME) +  cmake_parse_arguments(ARG "" "MESSAGE" "" ${ARGN}) +  set(PYBIND11_FILTER_TESTS_FOUND OFF) +  foreach(filename IN LISTS ARG_UNPARSED_ARGUMENTS) +    list(FIND ${LISTNAME} ${filename} _FILE_FOUND) +    if(_FILE_FOUND GREATER -1) +      list(REMOVE_AT ${LISTNAME} ${_FILE_FOUND}) +      set(PYBIND11_FILTER_TESTS_FOUND ON) +    endif() +  endforeach() +  if(PYBIND11_FILTER_TESTS_FOUND AND ARG_MESSAGE) +    message(STATUS "${ARG_MESSAGE}") +  endif() +endmacro() -if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) -    # We're being loaded directly, i.e. not via add_subdirectory, so make this -    # work as its own project and load the pybind11Config to get the tools we need -    project(pybind11_tests CXX) +# New Python support +if(DEFINED Python_EXECUTABLE) +  set(PYTHON_EXECUTABLE "${Python_EXECUTABLE}") +  set(PYTHON_VERSION "${Python_VERSION}") +endif() -    find_package(pybind11 REQUIRED CONFIG) +# There's no harm in including a project in a project +project(pybind11_tests CXX) + +# Access FindCatch and more +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../tools") + +option(PYBIND11_WERROR "Report all warnings as errors" OFF) +option(DOWNLOAD_EIGEN "Download EIGEN (requires CMake 3.11+)" OFF) +option(PYBIND11_CUDA_TESTS "Enable building CUDA tests (requires CMake 3.12+)" OFF) +set(PYBIND11_TEST_OVERRIDE +    "" +    CACHE STRING "Tests from ;-separated list of *.cpp files will be built instead of all tests") +set(PYBIND11_TEST_FILTER +    "" +    CACHE STRING "Tests from ;-separated list of *.cpp files will be removed from all tests") + +if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) +  # We're being loaded directly, i.e. not via add_subdirectory, so make this +  # work as its own project and load the pybind11Config to get the tools we need +  find_package(pybind11 REQUIRED CONFIG)  endif()  if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)    message(STATUS "Setting tests build type to MinSizeRel as none was specified") -  set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE) -  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" -    "MinSizeRel" "RelWithDebInfo") +  set(CMAKE_BUILD_TYPE +      MinSizeRel +      CACHE STRING "Choose the type of build." FORCE) +  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" +                                               "RelWithDebInfo") +endif() + +if(PYBIND11_CUDA_TESTS) +  enable_language(CUDA) +  if(DEFINED CMAKE_CXX_STANDARD) +    set(CMAKE_CUDA_STANDARD ${CMAKE_CXX_STANDARD}) +  endif() +  set(CMAKE_CUDA_STANDARD_REQUIRED ON)  endif()  # Full set of test files (you can override these; see below)  set(PYBIND11_TEST_FILES -  test_async.cpp -  test_buffers.cpp -  test_builtin_casters.cpp -  test_call_policies.cpp -  test_callbacks.cpp -  test_chrono.cpp -  test_class.cpp -  test_constants_and_functions.cpp -  test_copy_move.cpp -  test_docstring_options.cpp -  test_eigen.cpp -  test_enum.cpp -  test_eval.cpp -  test_exceptions.cpp -  test_factory_constructors.cpp -  test_gil_scoped.cpp -  test_iostream.cpp -  test_kwargs_and_defaults.cpp -  test_local_bindings.cpp -  test_methods_and_attributes.cpp -  test_modules.cpp -  test_multiple_inheritance.cpp -  test_numpy_array.cpp -  test_numpy_dtypes.cpp -  test_numpy_vectorize.cpp -  test_opaque_types.cpp -  test_operator_overloading.cpp -  test_pickling.cpp -  test_pytypes.cpp -  test_sequences_and_iterators.cpp -  test_smart_ptr.cpp -  test_stl.cpp -  test_stl_binders.cpp -  test_tagbased_polymorphic.cpp -  test_union.cpp -  test_virtual_functions.cpp -) +    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)  # Invoking cmake with something like: -#     cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_picking.cpp" .. +#     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) +if(PYBIND11_TEST_OVERRIDE)    set(PYBIND11_TEST_FILES ${PYBIND11_TEST_OVERRIDE})  endif() -# Skip test_async for Python < 3.5 -list(FIND PYBIND11_TEST_FILES test_async.cpp PYBIND11_TEST_FILES_ASYNC_I) -if((PYBIND11_TEST_FILES_ASYNC_I GREATER -1) AND ("${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" VERSION_LESS 3.5)) -  message(STATUS "Skipping test_async because Python version ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} < 3.5") -  list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_ASYNC_I}) +# You can also filter tests: +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 +if(PYBIND11_CUDA_TESTS) +  pybind11_filter_tests( +    PYBIND11_TEST_FILES test_constants_and_functions.cpp MESSAGE +    "Skipping test_constants_and_functions due to incompatible exception specifications")  endif()  string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}") @@ -84,16 +156,10 @@ string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")  # Contains the set of test files that require pybind11_cross_module_tests to be  # built; if none of these are built (i.e. because TEST_OVERRIDE is used and  # doesn't include them) the second module doesn't get built. -set(PYBIND11_CROSS_MODULE_TESTS -  test_exceptions.py -  test_local_bindings.py -  test_stl.py -  test_stl_binders.py -) +set(PYBIND11_CROSS_MODULE_TESTS test_exceptions.py test_local_bindings.py test_stl.py +                                test_stl_binders.py) -set(PYBIND11_CROSS_MODULE_GIL_TESTS -  test_gil_scoped.py -) +set(PYBIND11_CROSS_MODULE_GIL_TESTS test_gil_scoped.py)  # Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but  # keep it in PYBIND11_PYTEST_FILES, so that we get the "eigen is not installed" @@ -103,21 +169,45 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)    # Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake).    # Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also    # produces a fatal error if loaded from a pre-3.0 cmake. -  if (NOT CMAKE_VERSION VERSION_LESS 3.0) +  if(DOWNLOAD_EIGEN) +    if(CMAKE_VERSION VERSION_LESS 3.11) +      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}) + +    FetchContent_GetProperties(eigen) +    if(NOT eigen_POPULATED) +      message(STATUS "Downloading Eigen") +      FetchContent_Populate(eigen) +    endif() + +    set(EIGEN3_INCLUDE_DIR ${eigen_SOURCE_DIR}) +    set(EIGEN3_FOUND TRUE) + +  else()      find_package(Eigen3 3.2.7 QUIET CONFIG) -    if (EIGEN3_FOUND) -      if (EIGEN3_VERSION_STRING AND NOT EIGEN3_VERSION_STRING VERSION_LESS 3.3.1) -        set(PYBIND11_EIGEN_VIA_TARGET 1) -      endif() + +    if(NOT EIGEN3_FOUND) +      # Couldn't load via target, so fall back to allowing module mode finding, which will pick up +      # tools/FindEigen3.cmake +      find_package(Eigen3 3.2.7 QUIET)      endif()    endif() -  if (NOT EIGEN3_FOUND) -    # Couldn't load via target, so fall back to allowing module mode finding, which will pick up -    # tools/FindEigen3.cmake -    find_package(Eigen3 3.2.7 QUIET) -  endif()    if(EIGEN3_FOUND) +    if(NOT TARGET Eigen3::Eigen) +      add_library(Eigen3::Eigen IMPORTED INTERFACE) +      set_property(TARGET Eigen3::Eigen PROPERTY INTERFACE_INCLUDE_DIRECTORIES +                                                 "${EIGEN3_INCLUDE_DIR}") +    endif() +      # Eigen 3.3.1+ cmake sets EIGEN3_VERSION_STRING (and hard codes the version when installed      # rather than looking it up in the cmake script); older versions, and the      # tools/FindEigen3.cmake, set EIGEN3_VERSION instead. @@ -127,28 +217,63 @@ 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") +    message(STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN on CMake 3.11+ to download")    endif()  endif()  # Optional dependency for some tests (boost::variant is only supported with version >= 1.56)  find_package(Boost 1.56) +if(Boost_FOUND) +  if(NOT TARGET Boost::headers) +    add_library(Boost::headers IMPORTED INTERFACE) +    if(TARGET Boost::boost) +      # Classic FindBoost +      set_property(TARGET Boost::boost PROPERTY INTERFACE_LINK_LIBRARIES Boost::boost) +    else() +      # Very old FindBoost, or newer Boost than CMake in older CMakes +      set_property(TARGET Boost::headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES +                                                  ${Boost_INCLUDE_DIRS}) +    endif() +  endif() +endif() +  # Compile with compiler warnings turned on  function(pybind11_enable_warnings target_name)    if(MSVC)      target_compile_options(${target_name} PRIVATE /W4) -  elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)") -      target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual -Wdeprecated) +  elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)" AND NOT PYBIND11_CUDA_TESTS) +    target_compile_options( +      ${target_name} +      PRIVATE -Wall +              -Wextra +              -Wconversion +              -Wcast-qual +              -Wdeprecated +              -Wundef +              -Wnon-virtual-dtor)    endif()    if(PYBIND11_WERROR)      if(MSVC)        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)")        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) +    endif() +  endif()  endfunction()  set(test_targets pybind11_tests) @@ -156,7 +281,7 @@ 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) +  if(i GREATER -1)      list(APPEND test_targets pybind11_cross_module_tests)      break()    endif() @@ -164,78 +289,101 @@ endforeach()  foreach(t ${PYBIND11_CROSS_MODULE_GIL_TESTS})    list(FIND PYBIND11_PYTEST_FILES ${t} i) -  if (i GREATER -1) +  if(i GREATER -1)      list(APPEND test_targets cross_module_gil_utils)      break()    endif()  endforeach() -set(testdir ${CMAKE_CURRENT_SOURCE_DIR}) +# Support CUDA testing by forcing the target file to compile with NVCC +if(PYBIND11_CUDA_TESTS) +  set_property(SOURCE ${PYBIND11_TEST_FILES} PROPERTY LANGUAGE CUDA) +endif() +  foreach(target ${test_targets})    set(test_files ${PYBIND11_TEST_FILES}) -  if(NOT target STREQUAL "pybind11_tests") +  if(NOT "${target}" STREQUAL "pybind11_tests")      set(test_files "")    endif() +  # Support CUDA testing by forcing the target file to compile with NVCC +  if(PYBIND11_CUDA_TESTS) +    set_property(SOURCE ${target}.cpp PROPERTY LANGUAGE CUDA) +  endif() +    # Create the binding library    pybind11_add_module(${target} THIN_LTO ${target}.cpp ${test_files} ${PYBIND11_HEADERS})    pybind11_enable_warnings(${target}) +  if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) +    get_property( +      suffix +      TARGET ${target} +      PROPERTY SUFFIX) +    set(source_output "${CMAKE_CURRENT_SOURCE_DIR}/${target}${suffix}") +    if(suffix AND EXISTS "${source_output}") +      message(WARNING "Output file also in source directory; " +                      "please remove to avoid confusion: ${source_output}") +    endif() +  endif() +    if(MSVC)      target_compile_options(${target} PRIVATE /utf-8)    endif()    if(EIGEN3_FOUND) -    if (PYBIND11_EIGEN_VIA_TARGET) -      target_link_libraries(${target} PRIVATE Eigen3::Eigen) -    else() -      target_include_directories(${target} PRIVATE ${EIGEN3_INCLUDE_DIR}) -    endif() +    target_link_libraries(${target} PRIVATE Eigen3::Eigen)      target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_EIGEN)    endif()    if(Boost_FOUND) -    target_include_directories(${target} PRIVATE ${Boost_INCLUDE_DIRS}) +    target_link_libraries(${target} PRIVATE Boost::headers)      target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST)    endif()    # Always write the output file directly into the 'tests' directory (even on MSVC)    if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) -    set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${testdir}) +    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} ${testdir}) +      set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} +                                                 "${CMAKE_CURRENT_BINARY_DIR}")      endforeach()    endif()  endforeach() -# Make sure pytest is found or produce a fatal error -if(NOT PYBIND11_PYTEST_FOUND) -  execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import pytest; print(pytest.__version__)" -                  RESULT_VARIABLE pytest_not_found OUTPUT_VARIABLE pytest_version ERROR_QUIET) -  if(pytest_not_found) -    message(FATAL_ERROR "Running the tests requires pytest. Please install it manually" -                        " (try: ${PYTHON_EXECUTABLE} -m pip install pytest)") -  elseif(pytest_version VERSION_LESS 3.0) -    message(FATAL_ERROR "Running the tests requires pytest >= 3.0. Found: ${pytest_version}" -                        "Please update it (try: ${PYTHON_EXECUTABLE} -m pip install -U pytest)") -  endif() -  set(PYBIND11_PYTEST_FOUND TRUE CACHE INTERNAL "") -endif() +# Make sure pytest is found or produce a warning +pybind11_find_import(pytest VERSION 3.1) + +if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) +  # This is not used later in the build, so it's okay to regenerate each time. +  configure_file("${CMAKE_CURRENT_SOURCE_DIR}/pytest.ini" "${CMAKE_CURRENT_BINARY_DIR}/pytest.ini" +                 COPYONLY) +  file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/pytest.ini" +       "\ntestpaths = \"${CMAKE_CURRENT_SOURCE_DIR}\"") -if(CMAKE_VERSION VERSION_LESS 3.2) -  set(PYBIND11_USES_TERMINAL "") -else() -  set(PYBIND11_USES_TERMINAL "USES_TERMINAL")  endif() +# cmake 3.12 added list(transform <list> prepend +# but we can't use it yet +string(REPLACE "test_" "${CMAKE_CURRENT_SOURCE_DIR}/test_" PYBIND11_ABS_PYTEST_FILES +               "${PYBIND11_PYTEST_FILES}") +  # A single command to compile and run the tests -add_custom_target(pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_PYTEST_FILES} -                  DEPENDS ${test_targets} WORKING_DIRECTORY ${testdir} ${PYBIND11_USES_TERMINAL}) +add_custom_target( +  pytest +  COMMAND ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_ABS_PYTEST_FILES} +  DEPENDS ${test_targets} +  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +  USES_TERMINAL)  if(PYBIND11_TEST_OVERRIDE) -  add_custom_command(TARGET pytest POST_BUILD -    COMMAND ${CMAKE_COMMAND} -E echo "Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect") +  add_custom_command( +    TARGET pytest +    POST_BUILD +    COMMAND ${CMAKE_COMMAND} -E echo +            "Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect")  endif()  # Add a check target to run all the tests, starting with pytest (we add dependencies to this below) @@ -243,17 +391,23 @@ add_custom_target(check DEPENDS pytest)  # The remaining tests only apply when being built as part of the pybind11 project, but not if the  # tests are being built independently. -if (NOT PROJECT_NAME STREQUAL "pybind11") +if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)    return()  endif()  # Add a post-build comment to show the primary test suite .so size and, if a previous size, compare it: -add_custom_command(TARGET pybind11_tests POST_BUILD -  COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/libsize.py -  $<TARGET_FILE:pybind11_tests> ${CMAKE_CURRENT_BINARY_DIR}/sosize-$<TARGET_FILE_NAME:pybind11_tests>.txt) - -# Test embedding the interpreter. Provides the `cpptest` target. -add_subdirectory(test_embed) - -# Test CMake build using functions and targets from subdirectory or installed location -add_subdirectory(test_cmake_build) +add_custom_command( +  TARGET pybind11_tests +  POST_BUILD +  COMMAND +    ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../tools/libsize.py +    $<TARGET_FILE:pybind11_tests> +    ${CMAKE_CURRENT_BINARY_DIR}/sosize-$<TARGET_FILE_NAME:pybind11_tests>.txt) + +if(NOT PYBIND11_CUDA_TESTS) +  # Test embedding the interpreter. Provides the `cpptest` target. +  add_subdirectory(test_embed) + +  # Test CMake build using functions and targets from subdirectory or installed location +  add_subdirectory(test_cmake_build) +endif() diff --git a/3rdparty/pybind11/tests/conftest.py b/3rdparty/pybind11/tests/conftest.py index 57f681c6..362eb806 100644 --- a/3rdparty/pybind11/tests/conftest.py +++ b/3rdparty/pybind11/tests/conftest.py @@ -1,31 +1,36 @@ +# -*- 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.  """ -import pytest -import textwrap -import difflib -import re -import sys  import contextlib -import platform +import difflib  import gc +import re +import textwrap + +import pytest -_unicode_marker = re.compile(r'u(\'[^\']*\')') -_long_marker = re.compile(r'([0-9])L') -_hexadecimal = re.compile(r'0x[0-9a-fA-F]+') +import env -# test_async.py requires support for async and await +# Early diagnostic for failed imports +import pybind11_tests  # noqa: F401 + +_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 sys.version_info[:2] < (3, 5): +if env.PY2:      collect_ignore.append("test_async.py")  def _strip_and_dedent(s):      """For triple-quote strings""" -    return textwrap.dedent(s.lstrip('\n').rstrip()) +    return textwrap.dedent(s.lstrip("\n").rstrip())  def _split_and_sort(s): @@ -35,11 +40,14 @@ def _split_and_sort(s):  def _make_explanation(a, b):      """Explanation for a failed assert -- the a and b arguments are List[str]""" -    return ["--- actual / +++ expected"] + [line.strip('\n') for line in difflib.ndiff(a, b)] +    return ["--- actual / +++ expected"] + [ +        line.strip("\n") for line in difflib.ndiff(a, b) +    ]  class Output(object):      """Basic output post-processing and comparison""" +      def __init__(self, string):          self.string = string          self.explanation = [] @@ -49,7 +57,11 @@ class Output(object):      def __eq__(self, other):          # Ignore constructor/destructor output which is prefixed with "###" -        a = [line for line in self.string.strip().splitlines() if not line.startswith("###")] +        a = [ +            line +            for line in self.string.strip().splitlines() +            if not line.startswith("###") +        ]          b = _strip_and_dedent(other).splitlines()          if a == b:              return True @@ -60,6 +72,7 @@ class Output(object):  class Unordered(Output):      """Custom comparison for output without strict line ordering""" +      def __eq__(self, other):          a = _split_and_sort(self.string)          b = _split_and_sort(other) @@ -170,7 +183,7 @@ def msg():  # noinspection PyUnusedLocal  def pytest_assertrepr_compare(op, left, right):      """Hook to insert custom failure explanation""" -    if hasattr(left, 'explanation'): +    if hasattr(left, "explanation"):          return left.explanation @@ -184,61 +197,12 @@ def suppress(exception):  def gc_collect(): -    ''' Run the garbage collector twice (needed when running -    reference counting tests with PyPy) ''' +    """Run the garbage collector twice (needed when running +    reference counting tests with PyPy)"""      gc.collect()      gc.collect()  def pytest_configure(): -    """Add import suppression and test requirements to `pytest` namespace""" -    try: -        import numpy as np -    except ImportError: -        np = None -    try: -        import scipy -    except ImportError: -        scipy = None -    try: -        from pybind11_tests.eigen import have_eigen -    except ImportError: -        have_eigen = False -    pypy = platform.python_implementation() == "PyPy" - -    skipif = pytest.mark.skipif      pytest.suppress = suppress -    pytest.requires_numpy = skipif(not np, reason="numpy is not installed") -    pytest.requires_scipy = skipif(not np, reason="scipy is not installed") -    pytest.requires_eigen_and_numpy = skipif(not have_eigen or not np, -                                             reason="eigen and/or numpy are not installed") -    pytest.requires_eigen_and_scipy = skipif( -        not have_eigen or not scipy, reason="eigen and/or scipy are not installed") -    pytest.unsupported_on_pypy = skipif(pypy, reason="unsupported on PyPy") -    pytest.unsupported_on_py2 = skipif(sys.version_info.major < 3, -                                       reason="unsupported on Python 2.x")      pytest.gc_collect = gc_collect - - -def _test_import_pybind11(): -    """Early diagnostic for test module initialization errors - -    When there is an error during initialization, the first import will report the -    real error while all subsequent imports will report nonsense. This import test -    is done early (in the pytest configuration file, before any tests) in order to -    avoid the noise of having all tests fail with identical error messages. - -    Any possible exception is caught here and reported manually *without* the stack -    trace. This further reduces noise since the trace would only show pytest internals -    which are not useful for debugging pybind11 module issues. -    """ -    # noinspection PyBroadException -    try: -        import pybind11_tests  # noqa: F401 imported but unused -    except Exception as e: -        print("Failed to import pybind11_tests from pytest:") -        print("  {}: {}".format(type(e).__name__, e)) -        sys.exit(1) - - -_test_import_pybind11() diff --git a/3rdparty/pybind11/tests/constructor_stats.h b/3rdparty/pybind11/tests/constructor_stats.h index 431e5ace..805968a0 100644 --- a/3rdparty/pybind11/tests/constructor_stats.h +++ b/3rdparty/pybind11/tests/constructor_stats.h @@ -120,7 +120,7 @@ public:              throw py::error_already_set();          Py_DECREF(result);  #else -        py::module::import("gc").attr("collect")(); +        py::module_::import("gc").attr("collect")();  #endif      } @@ -273,4 +273,3 @@ template <class T, typename... Values> void print_values(T *inst, Values &&...va      print_constr_details(inst, ":", values...);      track_values(inst, values...);  } - diff --git a/3rdparty/pybind11/tests/env.py b/3rdparty/pybind11/tests/env.py new file mode 100644 index 00000000..5cded441 --- /dev/null +++ b/3rdparty/pybind11/tests/env.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +import platform +import sys + +LINUX = sys.platform.startswith("linux") +MACOS = sys.platform.startswith("darwin") +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 diff --git a/3rdparty/pybind11/tests/extra_python_package/pytest.ini b/3rdparty/pybind11/tests/extra_python_package/pytest.ini new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/3rdparty/pybind11/tests/extra_python_package/pytest.ini diff --git a/3rdparty/pybind11/tests/extra_python_package/test_files.py b/3rdparty/pybind11/tests/extra_python_package/test_files.py new file mode 100644 index 00000000..cbd4bff1 --- /dev/null +++ b/3rdparty/pybind11/tests/extra_python_package/test_files.py @@ -0,0 +1,262 @@ +# -*- coding: utf-8 -*- +import contextlib +import os +import string +import subprocess +import sys +import tarfile +import zipfile + +# These tests must be run explicitly +# They require CMake 3.15+ (--install) + +DIR = os.path.abspath(os.path.dirname(__file__)) +MAIN_DIR = os.path.dirname(os.path.dirname(DIR)) + + +main_headers = { +    "include/pybind11/attr.h", +    "include/pybind11/buffer_info.h", +    "include/pybind11/cast.h", +    "include/pybind11/chrono.h", +    "include/pybind11/common.h", +    "include/pybind11/complex.h", +    "include/pybind11/eigen.h", +    "include/pybind11/embed.h", +    "include/pybind11/eval.h", +    "include/pybind11/functional.h", +    "include/pybind11/iostream.h", +    "include/pybind11/numpy.h", +    "include/pybind11/operators.h", +    "include/pybind11/options.h", +    "include/pybind11/pybind11.h", +    "include/pybind11/pytypes.h", +    "include/pybind11/stl.h", +    "include/pybind11/stl_bind.h", +} + +detail_headers = { +    "include/pybind11/detail/class.h", +    "include/pybind11/detail/common.h", +    "include/pybind11/detail/descr.h", +    "include/pybind11/detail/init.h", +    "include/pybind11/detail/internals.h", +    "include/pybind11/detail/typeid.h", +} + +cmake_files = { +    "share/cmake/pybind11/FindPythonLibsNew.cmake", +    "share/cmake/pybind11/pybind11Common.cmake", +    "share/cmake/pybind11/pybind11Config.cmake", +    "share/cmake/pybind11/pybind11ConfigVersion.cmake", +    "share/cmake/pybind11/pybind11NewTools.cmake", +    "share/cmake/pybind11/pybind11Targets.cmake", +    "share/cmake/pybind11/pybind11Tools.cmake", +} + +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 +all_files = src_files | py_files + + +sdist_files = { +    "pybind11", +    "pybind11/include", +    "pybind11/include/pybind11", +    "pybind11/include/pybind11/detail", +    "pybind11/share", +    "pybind11/share/cmake", +    "pybind11/share/cmake/pybind11", +    "pyproject.toml", +    "setup.cfg", +    "setup.py", +    "LICENSE", +    "MANIFEST.in", +    "README.rst", +    "PKG-INFO", +} + +local_sdist_files = { +    ".egg-info", +    ".egg-info/PKG-INFO", +    ".egg-info/SOURCES.txt", +    ".egg-info/dependency_links.txt", +    ".egg-info/not-zip-safe", +    ".egg-info/top_level.txt", +} + + +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), +        ] +    ) +    if hasattr(out, "decode"): +        out = out.decode() + +    (sdist,) = tmpdir.visit("*.tar") + +    with tarfile.open(str(sdist)) as tar: +        start = tar.getnames()[0] + "/" +        version = start[9:-1] +        simpler = set(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() + +        with contextlib.closing( +            tar.extractfile(tar.getmember(start + "pyproject.toml")) +        ) as f: +            pyproject_toml = f.read() + +    files = set("pybind11/{}".format(n) for n in all_files) +    files |= sdist_files +    files |= set("pybind11{}".format(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()) +            .substitute(version=version, extra_cmd="") +            .encode() +        ) +        assert setup_py == contents + +    with open(os.path.join(MAIN_DIR, "tools", "pyproject.toml"), "rb") as f: +        contents = f.read() +        assert pyproject_toml == contents + + +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), +        ] +    ) +    if hasattr(out, "decode"): +        out = out.decode() + +    (sdist,) = tmpdir.visit("*.tar") + +    with tarfile.open(str(sdist)) as tar: +        start = tar.getnames()[0] + "/" +        version = start[16:-1] +        simpler = set(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() + +        with contextlib.closing( +            tar.extractfile(tar.getmember(start + "pyproject.toml")) +        ) as f: +            pyproject_toml = f.read() + +    files = set("pybind11/{}".format(n) for n in all_files) +    files |= sdist_files +    files |= set("pybind11_global{}".format(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() +        ) +        assert setup_py == contents + +    with open(os.path.join(MAIN_DIR, "tools", "pyproject.toml"), "rb") as f: +        contents = f.read() +        assert pyproject_toml == contents + + +def tests_build_wheel(monkeypatch, tmpdir): +    monkeypatch.chdir(MAIN_DIR) + +    subprocess.check_output( +        [sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)] +    ) + +    (wheel,) = tmpdir.visit("*.whl") + +    files = set("pybind11/{}".format(n) for n in all_files) +    files |= { +        "dist-info/LICENSE", +        "dist-info/METADATA", +        "dist-info/RECORD", +        "dist-info/WHEEL", +        "dist-info/entry_points.txt", +        "dist-info/top_level.txt", +    } + +    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 +    ) +    assert files == trimmed + + +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)] +    ) + +    (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 |= { +        "dist-info/LICENSE", +        "dist-info/METADATA", +        "dist-info/WHEEL", +        "dist-info/top_level.txt", +        "dist-info/RECORD", +    } + +    with zipfile.ZipFile(str(wheel)) as z: +        names = z.namelist() + +    beginning = names[0].split("/", 1)[0].rsplit(".", 1)[0] +    trimmed = set(n[len(beginning) + 1 :] for n in names) + +    assert files == trimmed diff --git a/3rdparty/pybind11/tests/extra_setuptools/pytest.ini b/3rdparty/pybind11/tests/extra_setuptools/pytest.ini new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/3rdparty/pybind11/tests/extra_setuptools/pytest.ini diff --git a/3rdparty/pybind11/tests/extra_setuptools/test_setuphelper.py b/3rdparty/pybind11/tests/extra_setuptools/test_setuphelper.py new file mode 100644 index 00000000..0d8bd0e4 --- /dev/null +++ b/3rdparty/pybind11/tests/extra_setuptools/test_setuphelper.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +import os +import sys +import subprocess +from textwrap import dedent + +import pytest + +DIR = os.path.abspath(os.path.dirname(__file__)) +MAIN_DIR = os.path.dirname(os.path.dirname(DIR)) + + +@pytest.mark.parametrize("parallel", [False, True]) +@pytest.mark.parametrize("std", [11, 0]) +def test_simple_setup_py(monkeypatch, tmpdir, parallel, std): +    monkeypatch.chdir(tmpdir) +    monkeypatch.syspath_prepend(MAIN_DIR) + +    (tmpdir / "setup.py").write_text( +        dedent( +            u"""\ +            import sys +            sys.path.append({MAIN_DIR!r}) + +            from setuptools import setup, Extension +            from pybind11.setup_helpers import build_ext, Pybind11Extension + +            std = {std} + +            ext_modules = [ +                Pybind11Extension( +                    "simple_setup", +                    sorted(["main.cpp"]), +                    cxx_std=std, +                ), +            ] + +            cmdclass = dict() +            if std == 0: +                cmdclass["build_ext"] = build_ext + + +            parallel = {parallel} +            if parallel: +                from pybind11.setup_helpers import ParallelCompile +                ParallelCompile().install() + +            setup( +                name="simple_setup_package", +                cmdclass=cmdclass, +                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) { +                return x * 3; +            } +            PYBIND11_MODULE(simple_setup, m) { +                m.def("f", &f); +            } +            """ +        ), +        encoding="ascii", +    ) + +    subprocess.check_call( +        [sys.executable, "setup.py", "build_ext", "--inplace"], +        stdout=sys.stdout, +        stderr=sys.stderr, +    ) + +    # Debug helper printout, normally hidden +    for item in tmpdir.listdir(): +        print(item.basename) + +    assert ( +        len([f for f in tmpdir.listdir() if f.basename.startswith("simple_setup")]) == 1 +    ) +    assert len(list(tmpdir.listdir())) == 4  # two files + output + build_dir + +    (tmpdir / "test.py").write_text( +        dedent( +            u"""\ +            import simple_setup +            assert simple_setup.f(3) == 9 +            """ +        ), +        encoding="ascii", +    ) + +    subprocess.check_call( +        [sys.executable, "test.py"], stdout=sys.stdout, stderr=sys.stderr +    ) diff --git a/3rdparty/pybind11/tests/local_bindings.h b/3rdparty/pybind11/tests/local_bindings.h index b6afb808..22537b13 100644 --- a/3rdparty/pybind11/tests/local_bindings.h +++ b/3rdparty/pybind11/tests/local_bindings.h @@ -58,7 +58,7 @@ public:      std::string name_;      const std::string &name() { return name_; }  }; -} +} // namespace pets  struct MixGL { int i; MixGL(int i) : i{i} {} };  struct MixGL2 { int i; MixGL2(int i) : i{i} {} }; diff --git a/3rdparty/pybind11/tests/pybind11_tests.cpp b/3rdparty/pybind11/tests/pybind11_tests.cpp index bc7d2c3e..439cd401 100644 --- a/3rdparty/pybind11/tests/pybind11_tests.cpp +++ b/3rdparty/pybind11/tests/pybind11_tests.cpp @@ -26,23 +26,23 @@ productively.  Instead, see the "How can I reduce the build time?" question in the "Frequently asked questions"  section of the documentation for good practice on splitting binding code over multiple files.  */ -std::list<std::function<void(py::module &)>> &initializers() { -    static std::list<std::function<void(py::module &)>> inits; +std::list<std::function<void(py::module_ &)>> &initializers() { +    static std::list<std::function<void(py::module_ &)>> inits;      return inits;  }  test_initializer::test_initializer(Initializer init) { -    initializers().push_back(init); +    initializers().emplace_back(init);  }  test_initializer::test_initializer(const char *submodule_name, Initializer init) { -    initializers().push_back([=](py::module &parent) { +    initializers().emplace_back([=](py::module_ &parent) {          auto m = parent.def_submodule(submodule_name);          init(m);      });  } -void bind_ConstructorStats(py::module &m) { +void bind_ConstructorStats(py::module_ &m) {      py::class_<ConstructorStats>(m, "ConstructorStats")          .def("alive", &ConstructorStats::alive)          .def("values", &ConstructorStats::values) @@ -88,6 +88,4 @@ PYBIND11_MODULE(pybind11_tests, m) {      for (const auto &initializer : initializers())          initializer(m); - -    if (!py::hasattr(m, "have_eigen")) m.attr("have_eigen") = false;  } diff --git a/3rdparty/pybind11/tests/pybind11_tests.h b/3rdparty/pybind11/tests/pybind11_tests.h index 90963a5d..4ff56c07 100644 --- a/3rdparty/pybind11/tests/pybind11_tests.h +++ b/3rdparty/pybind11/tests/pybind11_tests.h @@ -10,7 +10,7 @@ namespace py = pybind11;  using namespace pybind11::literals;  class test_initializer { -    using Initializer = void (*)(py::module &); +    using Initializer = void (*)(py::module_ &);  public:      test_initializer(Initializer init); @@ -18,9 +18,9 @@ public:  };  #define TEST_SUBMODULE(name, variable)                   \ -    void test_submodule_##name(py::module &);            \ +    void test_submodule_##name(py::module_ &);            \      test_initializer name(#name, test_submodule_##name); \ -    void test_submodule_##name(py::module &variable) +    void test_submodule_##name(py::module_ &variable)  /// Dummy type which is not exported anywhere -- something to trigger a conversion error @@ -50,16 +50,22 @@ public:      IncType &operator=(IncType &&) = delete;  }; +/// A simple union for basic testing +union IntFloat { +    int i; +    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).  struct RValueCaster {}; -NAMESPACE_BEGIN(pybind11) -NAMESPACE_BEGIN(detail) +PYBIND11_NAMESPACE_BEGIN(pybind11) +PYBIND11_NAMESPACE_BEGIN(detail)  template<> class type_caster<RValueCaster> {  public:      PYBIND11_TYPE_CASTER(RValueCaster, _("RValueCaster"));      static handle cast(RValueCaster &&, return_value_policy, handle) { return py::str("rvalue").release(); }      static handle cast(const RValueCaster &, return_value_policy, handle) { return py::str("lvalue").release(); }  }; -NAMESPACE_END(detail) -NAMESPACE_END(pybind11) +PYBIND11_NAMESPACE_END(detail) +PYBIND11_NAMESPACE_END(pybind11) diff --git a/3rdparty/pybind11/tests/pytest.ini b/3rdparty/pybind11/tests/pytest.ini index f209964a..c47cbe9c 100644 --- a/3rdparty/pybind11/tests/pytest.ini +++ b/3rdparty/pybind11/tests/pytest.ini @@ -1,11 +1,14 @@  [pytest] -minversion = 3.0 -norecursedirs = test_cmake_build test_embed +minversion = 3.1 +norecursedirs = test_* extra_* +xfail_strict = True  addopts =      # show summary of skipped tests      -rs      # capture only Python print and C++ py::print, but not C output (low-level Python errors)      --capture=sys +    # enable all warnings +    -Wa  filterwarnings =      # make warnings into errors but ignore certain third-party extension issues      error diff --git a/3rdparty/pybind11/tests/requirements.txt b/3rdparty/pybind11/tests/requirements.txt new file mode 100644 index 00000000..80ed6171 --- /dev/null +++ b/3rdparty/pybind11/tests/requirements.txt @@ -0,0 +1,8 @@ +--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" diff --git a/3rdparty/pybind11/tests/test_async.cpp b/3rdparty/pybind11/tests/test_async.cpp index f0ad0d53..e6e01d72 100644 --- a/3rdparty/pybind11/tests/test_async.cpp +++ b/3rdparty/pybind11/tests/test_async.cpp @@ -18,7 +18,7 @@ TEST_SUBMODULE(async_module, m) {          .def(py::init<>())          .def("__await__", [](const SupportsAsync& self) -> py::object {              static_cast<void>(self); -            py::object loop = py::module::import("asyncio.events").attr("get_event_loop")(); +            py::object loop = py::module_::import("asyncio.events").attr("get_event_loop")();              py::object f = loop.attr("create_future")();              f.attr("set_result")(5);              return f.attr("__await__")(); diff --git a/3rdparty/pybind11/tests/test_async.py b/3rdparty/pybind11/tests/test_async.py index e1c959d6..df4489c4 100644 --- a/3rdparty/pybind11/tests/test_async.py +++ b/3rdparty/pybind11/tests/test_async.py @@ -1,6 +1,8 @@ -import asyncio +# -*- coding: utf-8 -*-  import pytest -from pybind11_tests import async_module as m + +asyncio = pytest.importorskip("asyncio") +m = pytest.importorskip("pybind11_tests.async_module")  @pytest.fixture diff --git a/3rdparty/pybind11/tests/test_buffers.cpp b/3rdparty/pybind11/tests/test_buffers.cpp index 1bc67ff7..46eabf39 100644 --- a/3rdparty/pybind11/tests/test_buffers.cpp +++ b/3rdparty/pybind11/tests/test_buffers.cpp @@ -9,12 +9,13 @@  #include "pybind11_tests.h"  #include "constructor_stats.h" +#include <pybind11/stl.h>  TEST_SUBMODULE(buffers, m) {      // test_from_python / test_to_python:      class Matrix {      public: -        Matrix(ssize_t rows, ssize_t cols) : m_rows(rows), m_cols(cols) { +        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)];              memset(m_data, 0, sizeof(float) * (size_t) (rows * cols)); @@ -58,25 +59,25 @@ TEST_SUBMODULE(buffers, m) {              return *this;          } -        float operator()(ssize_t i, ssize_t j) const { +        float operator()(py::ssize_t i, py::ssize_t j) const {              return m_data[(size_t) (i*m_cols + j)];          } -        float &operator()(ssize_t i, ssize_t j) { +        float &operator()(py::ssize_t i, py::ssize_t j) {              return m_data[(size_t) (i*m_cols + j)];          }          float *data() { return m_data; } -        ssize_t rows() const { return m_rows; } -        ssize_t cols() const { return m_cols; } +        py::ssize_t rows() const { return m_rows; } +        py::ssize_t cols() const { return m_cols; }      private: -        ssize_t m_rows; -        ssize_t m_cols; +        py::ssize_t m_rows; +        py::ssize_t m_cols;          float *m_data;      };      py::class_<Matrix>(m, "Matrix", py::buffer_protocol()) -        .def(py::init<ssize_t, ssize_t>()) +        .def(py::init<py::ssize_t, py::ssize_t>())          /// Construct from a buffer          .def(py::init([](py::buffer const b) {              py::buffer_info info = b.request(); @@ -92,12 +93,12 @@ TEST_SUBMODULE(buffers, m) {         .def("cols", &Matrix::cols)          /// Bare bones interface -       .def("__getitem__", [](const Matrix &m, std::pair<ssize_t, ssize_t> i) { +       .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<ssize_t, ssize_t> i, float v) { +       .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; @@ -117,11 +118,11 @@ TEST_SUBMODULE(buffers, m) {      // test_inherited_protocol      class SquareMatrix : public Matrix {      public: -        SquareMatrix(ssize_t n) : Matrix(n, n) { } +        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<ssize_t>()); +        .def(py::init<py::ssize_t>());      // test_pointer_to_member_fn @@ -192,4 +193,22 @@ TEST_SUBMODULE(buffers, m) {          .def_readwrite("readonly", &BufferReadOnlySelect::readonly)          .def_buffer(&BufferReadOnlySelect::get_buffer_info); +    // Expose buffer_info for testing. +    py::class_<py::buffer_info>(m, "buffer_info") +        .def(py::init<>()) +        .def_readonly("itemsize", &py::buffer_info::itemsize) +        .def_readonly("size", &py::buffer_info::size) +        .def_readonly("format", &py::buffer_info::format) +        .def_readonly("ndim", &py::buffer_info::ndim) +        .def_readonly("shape", &py::buffer_info::shape) +        .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); +        }) +        ; + +    m.def("get_buffer_info", [](py::buffer buffer) { +        return buffer.request(); +    });  } diff --git a/3rdparty/pybind11/tests/test_buffers.py b/3rdparty/pybind11/tests/test_buffers.py index bf7aaed7..f0f37084 100644 --- a/3rdparty/pybind11/tests/test_buffers.py +++ b/3rdparty/pybind11/tests/test_buffers.py @@ -1,18 +1,16 @@ +# -*- coding: utf-8 -*-  import io  import struct -import sys +import ctypes  import pytest +import env  # noqa: F401 +  from pybind11_tests import buffers as m  from pybind11_tests import ConstructorStats -PY3 = sys.version_info[0] >= 3 - -pytestmark = pytest.requires_numpy - -with pytest.suppress(ImportError): -    import numpy as np +np = pytest.importorskip("numpy")  def test_from_python(): @@ -38,9 +36,7 @@ def test_from_python():      assert cstats.move_assignments == 0 -# PyPy: Memory leak in the "np.array(m, copy=False)" call -# https://bitbucket.org/pypy/pypy/issues/2444 -@pytest.unsupported_on_pypy +# https://foss.heptapod.net/pypy/pypy/-/issues/2444  def test_to_python():      mat = m.Matrix(5, 4)      assert memoryview(mat).shape == (5, 4) @@ -50,8 +46,8 @@ def test_to_python():      mat[3, 2] = 7.0      assert mat[2, 3] == 4      assert mat[3, 2] == 7 -    assert struct.unpack_from('f', mat, (3 * 4 + 2) * 4) == (7, ) -    assert struct.unpack_from('f', mat, (2 * 4 + 3) * 4) == (4, ) +    assert struct.unpack_from("f", mat, (3 * 4 + 2) * 4) == (7,) +    assert struct.unpack_from("f", mat, (2 * 4 + 3) * 4) == (4,)      mat2 = np.array(mat, copy=False)      assert mat2.shape == (5, 4) @@ -75,7 +71,6 @@ def test_to_python():      assert cstats.move_assignments == 0 -@pytest.unsupported_on_pypy  def test_inherited_protocol():      """SquareMatrix is derived from Matrix and inherits the buffer protocol""" @@ -84,35 +79,84 @@ def test_inherited_protocol():      assert np.asarray(matrix).shape == (5, 5) -@pytest.unsupported_on_pypy  def test_pointer_to_member_fn():      for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]:          buf = cls()          buf.value = 0x12345678 -        value = struct.unpack('i', bytearray(buf))[0] +        value = struct.unpack("i", bytearray(buf))[0]          assert value == 0x12345678 -@pytest.unsupported_on_pypy  def test_readonly_buffer():      buf = m.BufferReadOnly(0x64)      view = memoryview(buf) -    assert view[0] == 0x64 if PY3 else b'd' +    assert view[0] == b"d" if env.PY2 else 0x64      assert view.readonly -@pytest.unsupported_on_pypy  def test_selective_readonly_buffer():      buf = m.BufferReadOnlySelect() -    memoryview(buf)[0] = 0x64 if PY3 else b'd' +    memoryview(buf)[0] = b"d" if env.PY2 else 0x64      assert buf.value == 0x64 -    io.BytesIO(b'A').readinto(buf) -    assert buf.value == ord(b'A') +    io.BytesIO(b"A").readinto(buf) +    assert buf.value == ord(b"A")      buf.readonly = True      with pytest.raises(TypeError): -        memoryview(buf)[0] = 0 if PY3 else b'\0' +        memoryview(buf)[0] = b"\0" if env.PY2 else 0      with pytest.raises(TypeError): -        io.BytesIO(b'1').readinto(buf) +        io.BytesIO(b"1").readinto(buf) + + +def test_ctypes_array_1d(): +    char1d = (ctypes.c_char * 10)() +    int1d = (ctypes.c_int * 15)() +    long1d = (ctypes.c_long * 7)() + +    for carray in (char1d, int1d, long1d): +        info = m.get_buffer_info(carray) +        assert info.itemsize == ctypes.sizeof(carray._type_) +        assert info.size == len(carray) +        assert info.ndim == 1 +        assert info.shape == [info.size] +        assert info.strides == [info.itemsize] +        assert not info.readonly + + +def test_ctypes_array_2d(): +    char2d = ((ctypes.c_char * 10) * 4)() +    int2d = ((ctypes.c_int * 15) * 3)() +    long2d = ((ctypes.c_long * 7) * 2)() + +    for carray in (char2d, int2d, long2d): +        info = m.get_buffer_info(carray) +        assert info.itemsize == ctypes.sizeof(carray[0]._type_) +        assert info.size == len(carray) * len(carray[0]) +        assert info.ndim == 2 +        assert info.shape == [len(carray), len(carray[0])] +        assert info.strides == [info.itemsize * len(carray[0]), info.itemsize] +        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)): +        pyinfo = m.get_buffer_info(pyarray) + +        if pyinfo.readonly: +            cbytes = (ctypes.c_char * len(pyarray)).from_buffer_copy(pyarray) +            cinfo = m.get_buffer_info(cbytes) +        else: +            cbytes = (ctypes.c_char * len(pyarray)).from_buffer(pyarray) +            cinfo = m.get_buffer_info(cbytes) + +        assert cinfo.size == pyinfo.size +        assert cinfo.ndim == pyinfo.ndim +        assert cinfo.shape == pyinfo.shape +        assert cinfo.strides == pyinfo.strides +        assert not cinfo.readonly diff --git a/3rdparty/pybind11/tests/test_builtin_casters.cpp b/3rdparty/pybind11/tests/test_builtin_casters.cpp index acb24469..acc9f8fb 100644 --- a/3rdparty/pybind11/tests/test_builtin_casters.cpp +++ b/3rdparty/pybind11/tests/test_builtin_casters.cpp @@ -117,12 +117,16 @@ TEST_SUBMODULE(builtin_casters, m) {          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; }); +      // 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; });      // test_none_deferred      m.def("defer_none_cstring", [](char *) { return false; }); diff --git a/3rdparty/pybind11/tests/test_builtin_casters.py b/3rdparty/pybind11/tests/test_builtin_casters.py index 91422588..bd7996b6 100644 --- a/3rdparty/pybind11/tests/test_builtin_casters.py +++ b/3rdparty/pybind11/tests/test_builtin_casters.py @@ -1,6 +1,8 @@ -# Python < 3 needs this: coding=utf-8 +# -*- coding: utf-8 -*-  import pytest +import env  # noqa: F401 +  from pybind11_tests import builtin_casters as m  from pybind11_tests import UserType, IncType @@ -35,79 +37,85 @@ def test_unicode_conversion():          with pytest.raises(UnicodeDecodeError):              m.bad_utf8_u8string() -    assert m.u8_Z() == 'Z' -    assert m.u8_eacute() == u'é' -    assert m.u16_ibang() == u'‽' -    assert m.u32_mathbfA() == u'𝐀' -    assert m.wchar_heart() == u'♥' +    assert m.u8_Z() == "Z" +    assert m.u8_eacute() == u"é" +    assert m.u16_ibang() == u"‽" +    assert m.u32_mathbfA() == u"𝐀" +    assert m.wchar_heart() == u"♥"      if hasattr(m, "has_u8string"): -        assert m.u8_char8_Z() == 'Z' +        assert m.u8_char8_Z() == "Z"  def test_single_char_arguments():      """Tests failures for passing invalid inputs to char-accepting functions""" +      def toobig_message(r):          return "Character code point not in range({0:#x})".format(r) +      toolong_message = "Expected a character, but multi-character string found" -    assert m.ord_char(u'a') == 0x61  # simple ASCII -    assert m.ord_char_lv(u'b') == 0x62 -    assert m.ord_char(u'é') == 0xE9  # requires 2 bytes in utf-8, but can be stuffed in a char +    assert m.ord_char(u"a") == 0x61  # simple ASCII +    assert m.ord_char_lv(u"b") == 0x62 +    assert ( +        m.ord_char(u"é") == 0xE9 +    )  # requires 2 bytes in utf-8, but can be stuffed in a char      with pytest.raises(ValueError) as excinfo: -        assert m.ord_char(u'Ā') == 0x100  # requires 2 bytes, doesn't fit in a char +        assert m.ord_char(u"Ā") == 0x100  # requires 2 bytes, doesn't fit in a char      assert str(excinfo.value) == toobig_message(0x100)      with pytest.raises(ValueError) as excinfo: -        assert m.ord_char(u'ab') +        assert m.ord_char(u"ab")      assert str(excinfo.value) == toolong_message -    assert m.ord_char16(u'a') == 0x61 -    assert m.ord_char16(u'é') == 0xE9 -    assert m.ord_char16_lv(u'ê') == 0xEA -    assert m.ord_char16(u'Ā') == 0x100 -    assert m.ord_char16(u'‽') == 0x203d -    assert m.ord_char16(u'♥') == 0x2665 -    assert m.ord_char16_lv(u'♡') == 0x2661 +    assert m.ord_char16(u"a") == 0x61 +    assert m.ord_char16(u"é") == 0xE9 +    assert m.ord_char16_lv(u"ê") == 0xEA +    assert m.ord_char16(u"Ā") == 0x100 +    assert m.ord_char16(u"‽") == 0x203D +    assert m.ord_char16(u"♥") == 0x2665 +    assert m.ord_char16_lv(u"♡") == 0x2661      with pytest.raises(ValueError) as excinfo: -        assert m.ord_char16(u'🎂') == 0x1F382  # requires surrogate pair +        assert m.ord_char16(u"🎂") == 0x1F382  # requires surrogate pair      assert str(excinfo.value) == toobig_message(0x10000)      with pytest.raises(ValueError) as excinfo: -        assert m.ord_char16(u'aa') +        assert m.ord_char16(u"aa")      assert str(excinfo.value) == toolong_message -    assert m.ord_char32(u'a') == 0x61 -    assert m.ord_char32(u'é') == 0xE9 -    assert m.ord_char32(u'Ā') == 0x100 -    assert m.ord_char32(u'‽') == 0x203d -    assert m.ord_char32(u'♥') == 0x2665 -    assert m.ord_char32(u'🎂') == 0x1F382 +    assert m.ord_char32(u"a") == 0x61 +    assert m.ord_char32(u"é") == 0xE9 +    assert m.ord_char32(u"Ā") == 0x100 +    assert m.ord_char32(u"‽") == 0x203D +    assert m.ord_char32(u"♥") == 0x2665 +    assert m.ord_char32(u"🎂") == 0x1F382      with pytest.raises(ValueError) as excinfo: -        assert m.ord_char32(u'aa') +        assert m.ord_char32(u"aa")      assert str(excinfo.value) == toolong_message -    assert m.ord_wchar(u'a') == 0x61 -    assert m.ord_wchar(u'é') == 0xE9 -    assert m.ord_wchar(u'Ā') == 0x100 -    assert m.ord_wchar(u'‽') == 0x203d -    assert m.ord_wchar(u'♥') == 0x2665 +    assert m.ord_wchar(u"a") == 0x61 +    assert m.ord_wchar(u"é") == 0xE9 +    assert m.ord_wchar(u"Ā") == 0x100 +    assert m.ord_wchar(u"‽") == 0x203D +    assert m.ord_wchar(u"♥") == 0x2665      if m.wchar_size == 2:          with pytest.raises(ValueError) as excinfo: -            assert m.ord_wchar(u'🎂') == 0x1F382  # requires surrogate pair +            assert m.ord_wchar(u"🎂") == 0x1F382  # requires surrogate pair          assert str(excinfo.value) == toobig_message(0x10000)      else: -        assert m.ord_wchar(u'🎂') == 0x1F382 +        assert m.ord_wchar(u"🎂") == 0x1F382      with pytest.raises(ValueError) as excinfo: -        assert m.ord_wchar(u'aa') +        assert m.ord_wchar(u"aa")      assert str(excinfo.value) == toolong_message      if hasattr(m, "has_u8string"): -        assert m.ord_char8(u'a') == 0x61  # simple ASCII -        assert m.ord_char8_lv(u'b') == 0x62 -        assert m.ord_char8(u'é') == 0xE9  # requires 2 bytes in utf-8, but can be stuffed in a char +        assert m.ord_char8(u"a") == 0x61  # simple ASCII +        assert m.ord_char8_lv(u"b") == 0x62 +        assert ( +            m.ord_char8(u"é") == 0xE9 +        )  # requires 2 bytes in utf-8, but can be stuffed in a char          with pytest.raises(ValueError) as excinfo: -            assert m.ord_char8(u'Ā') == 0x100  # requires 2 bytes, doesn't fit in a char +            assert m.ord_char8(u"Ā") == 0x100  # requires 2 bytes, doesn't fit in a char          assert str(excinfo.value) == toobig_message(0x100)          with pytest.raises(ValueError) as excinfo: -            assert m.ord_char8(u'ab') +            assert m.ord_char8(u"ab")          assert str(excinfo.value) == toolong_message @@ -115,88 +123,108 @@ def test_bytes_to_string():      """Tests the ability to pass bytes to C++ string-accepting functions.  Note that this is      one-way: the only way to return bytes to Python is via the pybind11::bytes class."""      # Issue #816 -    import sys -    byte = bytes if sys.version_info[0] < 3 else str -    assert m.strlen(byte("hi")) == 2 -    assert m.string_length(byte("world")) == 5 -    assert m.string_length(byte("a\x00b")) == 3 -    assert m.strlen(byte("a\x00b")) == 1  # C-string limitation +    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      # passing in a utf8 encoded string should work -    assert m.string_length(u'💩'.encode("utf8")) == 4 +    assert m.string_length(u"💩".encode("utf8")) == 4  @pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")  def test_string_view(capture):      """Tests support for C++17 string_view arguments and return values"""      assert m.string_view_chars("Hi") == [72, 105] -    assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xf0, 0x9f, 0x8e, 0x82] -    assert m.string_view16_chars("Hi 🎂") == [72, 105, 32, 0xd83c, 0xdf82] -    assert m.string_view32_chars("Hi 🎂") == [72, 105, 32, 127874] +    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]      if hasattr(m, "has_u8string"):          assert m.string_view8_chars("Hi") == [72, 105] -        assert m.string_view8_chars("Hi 🎂") == [72, 105, 32, 0xf0, 0x9f, 0x8e, 0x82] +        assert m.string_view8_chars(u"Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82] -    assert m.string_view_return() == "utf8 secret 🎂" -    assert m.string_view16_return() == "utf16 secret 🎂" -    assert m.string_view32_return() == "utf32 secret 🎂" +    assert m.string_view_return() == u"utf8 secret 🎂" +    assert m.string_view16_return() == u"utf16 secret 🎂" +    assert m.string_view32_return() == u"utf32 secret 🎂"      if hasattr(m, "has_u8string"): -        assert m.string_view8_return() == "utf8 secret 🎂" +        assert m.string_view8_return() == u"utf8 secret 🎂"      with capture:          m.string_view_print("Hi")          m.string_view_print("utf8 🎂") -        m.string_view16_print("utf16 🎂") -        m.string_view32_print("utf32 🎂") -    assert capture == """ +        m.string_view16_print(u"utf16 🎂") +        m.string_view32_print(u"utf32 🎂") +    assert ( +        capture +        == u"""          Hi 2          utf8 🎂 9          utf16 🎂 8          utf32 🎂 7      """ +    )      if hasattr(m, "has_u8string"):          with capture:              m.string_view8_print("Hi") -            m.string_view8_print("utf8 🎂") -        assert capture == """ +            m.string_view8_print(u"utf8 🎂") +        assert ( +            capture +            == u"""              Hi 2              utf8 🎂 9          """ +        )      with capture:          m.string_view_print("Hi, ascii")          m.string_view_print("Hi, utf8 🎂") -        m.string_view16_print("Hi, utf16 🎂") -        m.string_view32_print("Hi, utf32 🎂") -    assert capture == """ +        m.string_view16_print(u"Hi, utf16 🎂") +        m.string_view32_print(u"Hi, utf32 🎂") +    assert ( +        capture +        == u"""          Hi, ascii 9          Hi, utf8 🎂 13          Hi, utf16 🎂 12          Hi, utf32 🎂 11      """ +    )      if hasattr(m, "has_u8string"):          with capture:              m.string_view8_print("Hi, ascii") -            m.string_view8_print("Hi, utf8 🎂") -        assert capture == """ +            m.string_view8_print(u"Hi, utf8 🎂") +        assert ( +            capture +            == u"""              Hi, ascii 9              Hi, utf8 🎂 13          """ +        )  def test_integer_casting():      """Issue #929 - out-of-range integer values shouldn't be accepted""" -    import sys      assert m.i32_str(-1) == "-1"      assert m.i64_str(-1) == "-1"      assert m.i32_str(2000000000) == "2000000000"      assert m.u32_str(2000000000) == "2000000000" -    if sys.version_info < (3,): +    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)) == "-999999999999"  # noqa: F821 undefined name -        assert m.u64_str(long(999999999999)) == "999999999999"  # 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" @@ -214,7 +242,7 @@ def test_integer_casting():          m.i32_str(3000000000)      assert "incompatible function arguments" in str(excinfo.value) -    if sys.version_info < (3,): +    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) @@ -232,16 +260,22 @@ def test_tuple(doc):      assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True)      assert m.empty_tuple() == () -    assert doc(m.pair_passthrough) == """ +    assert ( +        doc(m.pair_passthrough) +        == """          pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool]          Return a pair in reversed order      """ -    assert doc(m.tuple_passthrough) == """ +    ) +    assert ( +        doc(m.tuple_passthrough) +        == """          tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool]          Return a triple in reversed order      """ +    )      assert m.rvalue_pair() == ("rvalue", "rvalue")      assert m.lvalue_pair() == ("lvalue", "lvalue") @@ -250,6 +284,8 @@ def test_tuple(doc):      assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue")))      assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue"))) +    assert m.int_string_pair() == (2, "items") +  def test_builtins_cast_return_none():      """Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None""" @@ -258,6 +294,7 @@ def test_builtins_cast_return_none():      assert m.return_none_bool() is None      assert m.return_none_int() is None      assert m.return_none_float() is None +    assert m.return_none_pair() is None  def test_none_deferred(): @@ -352,9 +389,9 @@ def test_bool_caster():      assert convert(A(False)) is False -@pytest.requires_numpy  def test_numpy_bool(): -    import numpy as np +    np = pytest.importorskip("numpy") +      convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert      def cant_convert(v): @@ -365,7 +402,7 @@ def test_numpy_bool():      assert convert(np.bool_(False)) is False      assert noconvert(np.bool_(True)) is True      assert noconvert(np.bool_(False)) is False -    cant_convert(np.zeros(2, dtype='int')) +    cant_convert(np.zeros(2, dtype="int"))  def test_int_long(): @@ -375,7 +412,8 @@ def test_int_long():      long."""      import sys -    must_be_long = type(getattr(sys, 'maxint', 1) + 1) + +    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) diff --git a/3rdparty/pybind11/tests/test_call_policies.cpp b/3rdparty/pybind11/tests/test_call_policies.cpp index fd245578..26c83f81 100644 --- a/3rdparty/pybind11/tests/test_call_policies.cpp +++ b/3rdparty/pybind11/tests/test_call_policies.cpp @@ -46,6 +46,7 @@ TEST_SUBMODULE(call_policies, m) {      class Parent {      public:          Parent() { py::print("Allocating parent."); } +        Parent(const Parent& parent) = default;          ~Parent() { py::print("Releasing parent."); }          void addChild(Child *) { }          Child *returnChild() { return new Child(); } diff --git a/3rdparty/pybind11/tests/test_call_policies.py b/3rdparty/pybind11/tests/test_call_policies.py index 7c835599..e0413d14 100644 --- a/3rdparty/pybind11/tests/test_call_policies.py +++ b/3rdparty/pybind11/tests/test_call_policies.py @@ -1,8 +1,13 @@ +# -*- coding: utf-8 -*-  import pytest + +import env  # noqa: F401 +  from pybind11_tests import call_policies as m  from pybind11_tests import ConstructorStats +@pytest.mark.xfail("env.PYPY", reason="sometimes comes out 1 off on PyPy", strict=False)  def test_keep_alive_argument(capture):      n_inst = ConstructorStats.detail_reg_inst()      with capture: @@ -11,10 +16,13 @@ def test_keep_alive_argument(capture):      with capture:          p.addChild(m.Child())          assert ConstructorStats.detail_reg_inst() == n_inst + 1 -    assert capture == """ +    assert ( +        capture +        == """          Allocating child.          Releasing child.      """ +    )      with capture:          del p          assert ConstructorStats.detail_reg_inst() == n_inst @@ -30,10 +38,13 @@ def test_keep_alive_argument(capture):      with capture:          del p          assert ConstructorStats.detail_reg_inst() == n_inst -    assert capture == """ +    assert ( +        capture +        == """          Releasing parent.          Releasing child.      """ +    )  def test_keep_alive_return_value(capture): @@ -44,10 +55,13 @@ def test_keep_alive_return_value(capture):      with capture:          p.returnChild()          assert ConstructorStats.detail_reg_inst() == n_inst + 1 -    assert capture == """ +    assert ( +        capture +        == """          Allocating child.          Releasing child.      """ +    )      with capture:          del p          assert ConstructorStats.detail_reg_inst() == n_inst @@ -63,28 +77,34 @@ def test_keep_alive_return_value(capture):      with capture:          del p          assert ConstructorStats.detail_reg_inst() == n_inst -    assert capture == """ +    assert ( +        capture +        == """          Releasing parent.          Releasing child.      """ +    ) -# https://bitbucket.org/pypy/pypy/issues/2447 -@pytest.unsupported_on_pypy +# https://foss.heptapod.net/pypy/pypy/-/issues/2447 +@pytest.mark.xfail("env.PYPY", reason="_PyObject_GetDictPtr is unimplemented")  def test_alive_gc(capture):      n_inst = ConstructorStats.detail_reg_inst()      p = m.ParentGC()      p.addChildKeepAlive(m.Child())      assert ConstructorStats.detail_reg_inst() == n_inst + 2      lst = [p] -    lst.append(lst)   # creates a circular reference +    lst.append(lst)  # creates a circular reference      with capture:          del p, lst          assert ConstructorStats.detail_reg_inst() == n_inst -    assert capture == """ +    assert ( +        capture +        == """          Releasing parent.          Releasing child.      """ +    )  def test_alive_gc_derived(capture): @@ -96,14 +116,17 @@ def test_alive_gc_derived(capture):      p.addChildKeepAlive(m.Child())      assert ConstructorStats.detail_reg_inst() == n_inst + 2      lst = [p] -    lst.append(lst)   # creates a circular reference +    lst.append(lst)  # creates a circular reference      with capture:          del p, lst          assert ConstructorStats.detail_reg_inst() == n_inst -    assert capture == """ +    assert ( +        capture +        == """          Releasing parent.          Releasing child.      """ +    )  def test_alive_gc_multi_derived(capture): @@ -118,15 +141,18 @@ def test_alive_gc_multi_derived(capture):      # +3 rather than +2 because Derived corresponds to two registered instances      assert ConstructorStats.detail_reg_inst() == n_inst + 3      lst = [p] -    lst.append(lst)   # creates a circular reference +    lst.append(lst)  # creates a circular reference      with capture:          del p, lst          assert ConstructorStats.detail_reg_inst() == n_inst -    assert capture == """ +    assert ( +        capture +        == """          Releasing parent.          Releasing child.          Releasing child.      """ +    )  def test_return_none(capture): @@ -162,17 +188,23 @@ def test_keep_alive_constructor(capture):      with capture:          p = m.Parent(m.Child())          assert ConstructorStats.detail_reg_inst() == n_inst + 2 -    assert capture == """ +    assert ( +        capture +        == """          Allocating child.          Allocating parent.      """ +    )      with capture:          del p          assert ConstructorStats.detail_reg_inst() == n_inst -    assert capture == """ +    assert ( +        capture +        == """          Releasing parent.          Releasing child.      """ +    )  def test_call_guard(): diff --git a/3rdparty/pybind11/tests/test_callbacks.cpp b/3rdparty/pybind11/tests/test_callbacks.cpp index 71b88c44..683dfb3e 100644 --- a/3rdparty/pybind11/tests/test_callbacks.cpp +++ b/3rdparty/pybind11/tests/test_callbacks.cpp @@ -117,7 +117,11 @@ TEST_SUBMODULE(callbacks, m) {          }      }); -    class AbstractBase { public: virtual unsigned int func() = 0; }; +    class AbstractBase { +    public: +        virtual ~AbstractBase() = default; +        virtual unsigned int func() = 0; +    };      m.def("func_accepting_func_accepting_base", [](std::function<double(AbstractBase&)>) { });      struct MovableObject { diff --git a/3rdparty/pybind11/tests/test_callbacks.py b/3rdparty/pybind11/tests/test_callbacks.py index 6439c8e7..039b877c 100644 --- a/3rdparty/pybind11/tests/test_callbacks.py +++ b/3rdparty/pybind11/tests/test_callbacks.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*-  import pytest  from pybind11_tests import callbacks as m  from threading import Thread @@ -41,17 +42,19 @@ def test_bound_method_callback():  def test_keyword_args_and_generalized_unpacking(): -      def f(*args, **kwargs):          return args, kwargs      assert m.test_tuple_unpacking(f) == (("positional", 1, 2, 3, 4, 5, 6), {}) -    assert m.test_dict_unpacking(f) == (("positional", 1), {"key": "value", "a": 1, "b": 2}) +    assert m.test_dict_unpacking(f) == ( +        ("positional", 1), +        {"key": "value", "a": 1, "b": 2}, +    )      assert m.test_keyword_args(f) == ((), {"x": 10, "y": 20})      assert m.test_unpacking_and_keywords1(f) == ((1, 2), {"c": 3, "d": 4})      assert m.test_unpacking_and_keywords2(f) == (          ("positional", 1, 2, 3, 4, 5), -        {"key": "value", "a": 1, "b": 2, "c": 3, "d": 4, "e": 5} +        {"key": "value", "a": 1, "b": 2, "c": 3, "d": 4, "e": 5},      )      with pytest.raises(TypeError) as excinfo: @@ -82,12 +85,18 @@ def test_lambda_closure_cleanup():  def test_cpp_function_roundtrip():      """Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer""" -    assert m.test_dummy_function(m.dummy_function) == "matches dummy_function: eval(1) = 2" -    assert (m.test_dummy_function(m.roundtrip(m.dummy_function)) == -            "matches dummy_function: eval(1) = 2") +    assert ( +        m.test_dummy_function(m.dummy_function) == "matches dummy_function: eval(1) = 2" +    ) +    assert ( +        m.test_dummy_function(m.roundtrip(m.dummy_function)) +        == "matches dummy_function: eval(1) = 2" +    )      assert m.roundtrip(None, expect_none=True) is None -    assert (m.test_dummy_function(lambda x: x + 2) == -            "can't convert to function pointer: eval(1) = 3") +    assert ( +        m.test_dummy_function(lambda x: x + 2) +        == "can't convert to function pointer: eval(1) = 3" +    )      with pytest.raises(TypeError) as excinfo:          m.test_dummy_function(m.dummy_function2) @@ -95,8 +104,10 @@ def test_cpp_function_roundtrip():      with pytest.raises(TypeError) as excinfo:          m.test_dummy_function(lambda x, y: x + y) -    assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument", -                                                 "takes exactly 2 arguments")) +    assert any( +        s in str(excinfo.value) +        for s in ("missing 1 required positional argument", "takes exactly 2 arguments") +    )  def test_function_signatures(doc): @@ -126,6 +137,7 @@ def test_async_callbacks():      m.test_async_callback(gen_f(), work)      # wait until work is done      from time import sleep +      sleep(0.5)      assert sum(res) == sum([x + 3 for x in work]) diff --git a/3rdparty/pybind11/tests/test_chrono.cpp b/3rdparty/pybind11/tests/test_chrono.cpp index 899d08d8..65370508 100644 --- a/3rdparty/pybind11/tests/test_chrono.cpp +++ b/3rdparty/pybind11/tests/test_chrono.cpp @@ -10,6 +10,25 @@  #include "pybind11_tests.h"  #include <pybind11/chrono.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>; +    time_point_h timestamp_h; +    time_point_m timestamp_m; +    time_point_s timestamp_s; +    time_point_ms timestamp_ms; +    time_point_us timestamp_us; +};  TEST_SUBMODULE(chrono, m) {      using system_time = std::chrono::system_clock::time_point; @@ -52,4 +71,14 @@ TEST_SUBMODULE(chrono, m) {      m.def("test_nano_timepoint", [](timestamp start, timespan delta) -> timestamp {          return start + delta;      }); + +    // Test different resolutions +    py::class_<different_resolutions>(m, "different_resolutions") +        .def(py::init<>()) +        .def_readwrite("timestamp_h", &different_resolutions::timestamp_h) +        .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) +        ;  } diff --git a/3rdparty/pybind11/tests/test_chrono.py b/3rdparty/pybind11/tests/test_chrono.py index 55c95440..e9e24e08 100644 --- a/3rdparty/pybind11/tests/test_chrono.py +++ b/3rdparty/pybind11/tests/test_chrono.py @@ -1,10 +1,15 @@ +# -*- coding: utf-8 -*-  from pybind11_tests import chrono as m  import datetime +import pytest + +import env  # noqa: F401  def test_chrono_system_clock():      # Get the time from both c++ and datetime +    date0 = datetime.datetime.today()      date1 = m.test_chrono1()      date2 = datetime.datetime.today() @@ -12,16 +17,15 @@ def test_chrono_system_clock():      assert isinstance(date1, datetime.datetime)      # The numbers should vary by a very small amount (time it took to execute) +    diff_python = abs(date2 - date0)      diff = abs(date1 - date2) -    # There should never be a days/seconds difference +    # There should never be a days difference      assert diff.days == 0 -    assert diff.seconds == 0 -    # We test that no more than about 0.5 seconds passes here -    # This makes sure that the dates created are very close to the same -    # but if the testing system is incredibly overloaded this should still pass -    assert diff.microseconds < 500000 +    # Since datetime.datetime.today() calls time.time(), and on some platforms +    # that has 1 second accuracy, we compare this way +    assert diff.seconds <= diff_python.seconds  def test_chrono_system_clock_roundtrip(): @@ -71,8 +75,36 @@ def test_chrono_system_clock_roundtrip_date():      assert time2.microsecond == 0 -def test_chrono_system_clock_roundtrip_time(): -    time1 = datetime.datetime.today().time() +SKIP_TZ_ENV_ON_WIN = pytest.mark.skipif( +    "env.WIN", reason="TZ environment variable only supported on POSIX" +) + + +@pytest.mark.parametrize( +    "time1", +    [ +        datetime.datetime.today().time(), +        datetime.time(0, 0, 0), +        datetime.time(0, 0, 0, 1), +        datetime.time(0, 28, 45, 109827), +        datetime.time(0, 59, 59, 999999), +        datetime.time(1, 0, 0), +        datetime.time(5, 59, 59, 0), +        datetime.time(5, 59, 59, 1), +    ], +) +@pytest.mark.parametrize( +    "tz", +    [ +        None, +        pytest.param("Europe/Brussels", marks=SKIP_TZ_ENV_ON_WIN), +        pytest.param("Asia/Pyongyang", marks=SKIP_TZ_ENV_ON_WIN), +        pytest.param("America/New_York", marks=SKIP_TZ_ENV_ON_WIN), +    ], +) +def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch): +    if tz is not None: +        monkeypatch.setenv("TZ", "/usr/share/zoneinfo/{}".format(tz))      # Roundtrip the time      datetime2 = m.test_chrono2(time1) @@ -173,4 +205,14 @@ def test_floating_point_duration():  def test_nano_timepoint():      time = datetime.datetime.now()      time1 = m.test_nano_timepoint(time, datetime.timedelta(seconds=60)) -    assert(time1 == time + datetime.timedelta(seconds=60)) +    assert time1 == time + datetime.timedelta(seconds=60) + + +def test_chrono_different_resolutions(): +    resolutions = m.different_resolutions() +    time = datetime.datetime.now() +    resolutions.timestamp_h = time +    resolutions.timestamp_m = time +    resolutions.timestamp_s = time +    resolutions.timestamp_ms = time +    resolutions.timestamp_us = time diff --git a/3rdparty/pybind11/tests/test_class.cpp b/3rdparty/pybind11/tests/test_class.cpp index 499d0cc5..890fab73 100644 --- a/3rdparty/pybind11/tests/test_class.cpp +++ b/3rdparty/pybind11/tests/test_class.cpp @@ -103,7 +103,7 @@ TEST_SUBMODULE(class_, m) {          BaseClass() = default;          BaseClass(const BaseClass &) = default;          BaseClass(BaseClass &&) = default; -        virtual ~BaseClass() {} +        virtual ~BaseClass() = default;      };      struct DerivedClass1 : BaseClass { };      struct DerivedClass2 : BaseClass { }; @@ -134,6 +134,32 @@ TEST_SUBMODULE(class_, m) {          );      }); +    struct Invalid {}; + +    // test_type +    m.def("check_type", [](int category) { +        // Currently not supported (via a fail at compile time) +        // See https://github.com/pybind/pybind11/issues/2486 +        // if (category == 2) +        //     return py::type::of<int>(); +        if (category == 1) +            return py::type::of<DerivedClass1>(); +        else +            return py::type::of<Invalid>(); +    }); + +    m.def("get_type_of", [](py::object ob) { +        return py::type::of(ob); +    }); + +    m.def("get_type_classic", [](py::handle h) { +        return h.get_type(); +    }); + +    m.def("as_type", [](py::object ob) { +        return py::type(ob); +    }); +      // test_mismatched_holder      struct MismatchBase1 { };      struct MismatchDerived1 : MismatchBase1 { }; @@ -142,12 +168,12 @@ TEST_SUBMODULE(class_, m) {      struct MismatchDerived2 : MismatchBase2 { };      m.def("mismatched_holder_1", []() { -        auto mod = py::module::import("__main__"); +        auto mod = py::module_::import("__main__");          py::class_<MismatchBase1, std::shared_ptr<MismatchBase1>>(mod, "MismatchBase1");          py::class_<MismatchDerived1, MismatchBase1>(mod, "MismatchDerived1");      });      m.def("mismatched_holder_2", []() { -        auto mod = py::module::import("__main__"); +        auto mod = py::module_::import("__main__");          py::class_<MismatchBase2>(mod, "MismatchBase2");          py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>,                     MismatchBase2>(mod, "MismatchDerived2"); @@ -227,6 +253,8 @@ TEST_SUBMODULE(class_, m) {          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;      };      struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize {          PyAliasedHasOpNewDelSize() = default; @@ -277,6 +305,8 @@ TEST_SUBMODULE(class_, m) {      class ProtectedB {      public:          virtual ~ProtectedB() = default; +        ProtectedB() = default; +        ProtectedB(const ProtectedB &) = delete;      protected:          virtual int foo() const { return value; } @@ -287,7 +317,7 @@ TEST_SUBMODULE(class_, m) {      class TrampolineB : public ProtectedB {      public: -        int foo() const override { PYBIND11_OVERLOAD(int, ProtectedB, foo, ); } +        int foo() const override { PYBIND11_OVERRIDE(int, ProtectedB, foo, ); }      };      class PublicistB : public ProtectedB { @@ -323,7 +353,7 @@ TEST_SUBMODULE(class_, m) {      // test_reentrant_implicit_conversion_failure      // #1035: issue with runaway reentrant implicit conversion      struct BogusImplicitConversion { -        BogusImplicitConversion(const BogusImplicitConversion &) { } +        BogusImplicitConversion(const BogusImplicitConversion &) = default;      };      py::class_<BogusImplicitConversion>(m, "BogusImplicitConversion") @@ -367,19 +397,92 @@ TEST_SUBMODULE(class_, m) {              .def(py::init<>())              .def("ptr", &Aligned::ptr);      #endif + +    // test_final +    struct IsFinal final {}; +    py::class_<IsFinal>(m, "IsFinal", py::is_final()); + +    // test_non_final_final +    struct IsNonFinalFinal {}; +    py::class_<IsNonFinalFinal>(m, "IsNonFinalFinal", py::is_final()); + +    // test_exception_rvalue_abort +    struct PyPrintDestructor { +        PyPrintDestructor() = default; +        ~PyPrintDestructor() { +            py::print("Print from destructor"); +        } +        void throw_something() { throw std::runtime_error("error"); } +    }; +    py::class_<PyPrintDestructor>(m, "PyPrintDestructor") +        .def(py::init<>()) +        .def("throw_something", &PyPrintDestructor::throw_something); + +    // test_multiple_instances_with_same_pointer +    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"); }); + +    struct Empty {}; +    py::class_<Empty>(m, "Empty") +        .def(py::init<>()); + +    // test_base_and_derived_nested_scope +    struct BaseWithNested { +        struct Nested {}; +    }; + +    struct DerivedWithNested : BaseWithNested { +        struct Nested {}; +    }; + +    py::class_<BaseWithNested> baseWithNested_class(m, "BaseWithNested"); +    py::class_<DerivedWithNested, BaseWithNested> derivedWithNested_class(m, "DerivedWithNested"); +    py::class_<BaseWithNested::Nested>(baseWithNested_class, "Nested") +        .def_static("get_name", []() { return "BaseWithNested::Nested"; }); +    py::class_<DerivedWithNested::Nested>(derivedWithNested_class, "Nested") +        .def_static("get_name", []() { return "DerivedWithNested::Nested"; }); + +    // test_register_duplicate_class +    struct Duplicate {}; +    struct OtherDuplicate {}; +    struct DuplicateNested {}; +    struct OtherDuplicateNested {}; +    m.def("register_duplicate_class_name", [](py::module_ m) { +        py::class_<Duplicate>(m, "Duplicate"); +        py::class_<OtherDuplicate>(m, "Duplicate"); +    }); +    m.def("register_duplicate_class_type", [](py::module_ m) { +        py::class_<OtherDuplicate>(m, "OtherDuplicate"); +        py::class_<OtherDuplicate>(m, "YetAnotherDuplicate"); +    }); +    m.def("register_duplicate_nested_class_name", [](py::object gt) { +        py::class_<DuplicateNested>(gt, "DuplicateNested"); +        py::class_<OtherDuplicateNested>(gt, "DuplicateNested"); +    }); +    m.def("register_duplicate_nested_class_type", [](py::object gt) { +        py::class_<OtherDuplicateNested>(gt, "OtherDuplicateNested"); +        py::class_<OtherDuplicateNested>(gt, "YetAnotherDuplicateNested"); +    });  } -template <int N> class BreaksBase { public: virtual ~BreaksBase() = default; }; +template <int N> class BreaksBase { public: +    virtual ~BreaksBase() = default; +    BreaksBase() = default; +    BreaksBase(const BreaksBase&) = delete; +};  template <int N> class BreaksTramp : public BreaksBase<N> {};  // These should all compile just fine: -typedef py::class_<BreaksBase<1>, std::unique_ptr<BreaksBase<1>>, BreaksTramp<1>> DoesntBreak1; -typedef py::class_<BreaksBase<2>, BreaksTramp<2>, std::unique_ptr<BreaksBase<2>>> DoesntBreak2; -typedef py::class_<BreaksBase<3>, std::unique_ptr<BreaksBase<3>>> DoesntBreak3; -typedef py::class_<BreaksBase<4>, BreaksTramp<4>> DoesntBreak4; -typedef py::class_<BreaksBase<5>> DoesntBreak5; -typedef py::class_<BreaksBase<6>, std::shared_ptr<BreaksBase<6>>, BreaksTramp<6>> DoesntBreak6; -typedef py::class_<BreaksBase<7>, BreaksTramp<7>, std::shared_ptr<BreaksBase<7>>> DoesntBreak7; -typedef py::class_<BreaksBase<8>, std::shared_ptr<BreaksBase<8>>> DoesntBreak8; +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>>>; +using DoesntBreak3 = py::class_<BreaksBase<3>, std::unique_ptr<BreaksBase<3>>>; +using DoesntBreak4 = py::class_<BreaksBase<4>, BreaksTramp<4>>; +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); diff --git a/3rdparty/pybind11/tests/test_class.py b/3rdparty/pybind11/tests/test_class.py index ed63ca85..bdcced96 100644 --- a/3rdparty/pybind11/tests/test_class.py +++ b/3rdparty/pybind11/tests/test_class.py @@ -1,5 +1,8 @@ +# -*- coding: utf-8 -*-  import pytest +import env  # noqa: F401 +  from pybind11_tests import class_ as m  from pybind11_tests import UserType, ConstructorStats @@ -23,6 +26,48 @@ def test_instance(msg):      assert cstats.alive() == 0 +def test_type(): +    assert m.check_type(1) == m.DerivedClass1 +    with pytest.raises(RuntimeError) as execinfo: +        m.check_type(0) + +    assert "pybind11::detail::get_type_info: unable to find type info" in str( +        execinfo.value +    ) +    assert "Invalid" in str(execinfo.value) + +    # Currently not supported +    # See https://github.com/pybind/pybind11/issues/2486 +    # assert m.check_type(2) == int + + +def test_type_of_py(): +    assert m.get_type_of(1) == int +    assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1 +    assert m.get_type_of(int) == type + + +def test_type_of_classic(): +    assert m.get_type_classic(1) == int +    assert m.get_type_classic(m.DerivedClass1()) == m.DerivedClass1 +    assert m.get_type_classic(int) == type + + +def test_type_of_py_nodelete(): +    # If the above test deleted the class, this will segfault +    assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1 + + +def test_as_type_py(): +    assert m.as_type(int) == int + +    with pytest.raises(TypeError): +        assert m.as_type(1) == int + +    with pytest.raises(TypeError): +        assert m.as_type(m.DerivedClass1()) == m.DerivedClass1 + +  def test_docstrings(doc):      assert doc(UserType) == "A `py::class_` type for testing"      assert UserType.__name__ == "UserType" @@ -30,18 +75,24 @@ def test_docstrings(doc):      assert UserType.get_value.__name__ == "get_value"      assert UserType.get_value.__module__ == "pybind11_tests" -    assert doc(UserType.get_value) == """ +    assert ( +        doc(UserType.get_value) +        == """          get_value(self: m.UserType) -> int          Get value using a method      """ +    )      assert doc(UserType.value) == "Get/set value using a property" -    assert doc(m.NoConstructor.new_instance) == """ +    assert ( +        doc(m.NoConstructor.new_instance) +        == """          new_instance() -> m.class_.NoConstructor          Return an instance      """ +    )  def test_qualname(doc): @@ -50,57 +101,98 @@ def test_qualname(doc):      assert m.NestBase.__qualname__ == "NestBase"      assert m.NestBase.Nested.__qualname__ == "NestBase.Nested" -    assert doc(m.NestBase.__init__) == """ +    assert ( +        doc(m.NestBase.__init__) +        == """          __init__(self: m.class_.NestBase) -> None      """ -    assert doc(m.NestBase.g) == """ +    ) +    assert ( +        doc(m.NestBase.g) +        == """          g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None      """ -    assert doc(m.NestBase.Nested.__init__) == """ +    ) +    assert ( +        doc(m.NestBase.Nested.__init__) +        == """          __init__(self: m.class_.NestBase.Nested) -> None      """ -    assert doc(m.NestBase.Nested.fn) == """ +    ) +    assert ( +        doc(m.NestBase.Nested.fn) +        == """          fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None      """  # noqa: E501 line too long -    assert doc(m.NestBase.Nested.fa) == """ +    ) +    assert ( +        doc(m.NestBase.Nested.fa) +        == """          fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None      """  # noqa: E501 line too long +    )      assert m.NestBase.__module__ == "pybind11_tests.class_"      assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"  def test_inheritance(msg): -    roger = m.Rabbit('Rabbit') +    roger = m.Rabbit("Rabbit")      assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"      assert m.pet_name_species(roger) == "Rabbit is a parrot" -    polly = m.Pet('Polly', 'parrot') +    polly = m.Pet("Polly", "parrot")      assert polly.name() + " is a " + polly.species() == "Polly is a parrot"      assert m.pet_name_species(polly) == "Polly is a parrot" -    molly = m.Dog('Molly') +    molly = m.Dog("Molly")      assert molly.name() + " is a " + molly.species() == "Molly is a dog"      assert m.pet_name_species(molly) == "Molly is a dog" -    fred = m.Hamster('Fred') +    fred = m.Hamster("Fred")      assert fred.name() + " is a " + fred.species() == "Fred is a rodent"      assert m.dog_bark(molly) == "Woof!"      with pytest.raises(TypeError) as excinfo:          m.dog_bark(polly) -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          dog_bark(): incompatible function arguments. The following argument types are supported:              1. (arg0: m.class_.Dog) -> str          Invoked with: <m.class_.Pet object at 0>      """ +    )      with pytest.raises(TypeError) as excinfo:          m.Chimera("lion", "goat")      assert "No constructor defined!" in str(excinfo.value) +def test_inheritance_init(msg): + +    # Single base +    class Python(m.Pet): +        def __init__(self): +            pass + +    with pytest.raises(TypeError) as exc_info: +        Python() +    expected = "m.class_.Pet.__init__() must be called when overriding __init__" +    assert msg(exc_info.value) == expected + +    # Multiple bases +    class RabbitHamster(m.Rabbit, m.Hamster): +        def __init__(self): +            m.Rabbit.__init__(self, "RabbitHamster") + +    with pytest.raises(TypeError) as exc_info: +        RabbitHamster() +    expected = "m.class_.Hamster.__init__() must be called when overriding __init__" +    assert msg(exc_info.value) == expected + +  def test_automatic_upcasting():      assert type(m.return_class_1()).__name__ == "DerivedClass1"      assert type(m.return_class_2()).__name__ == "DerivedClass2" @@ -126,13 +218,19 @@ def test_mismatched_holder():      with pytest.raises(RuntimeError) as excinfo:          m.mismatched_holder_1() -    assert re.match('generic_type: type ".*MismatchDerived1" does not have a non-default ' -                    'holder type while its base ".*MismatchBase1" does', str(excinfo.value)) +    assert re.match( +        'generic_type: type ".*MismatchDerived1" does not have a non-default ' +        'holder type while its base ".*MismatchBase1" does', +        str(excinfo.value), +    )      with pytest.raises(RuntimeError) as excinfo:          m.mismatched_holder_2() -    assert re.match('generic_type: type ".*MismatchDerived2" has a non-default holder type ' -                    'while its base ".*MismatchBase2" does not', str(excinfo.value)) +    assert re.match( +        'generic_type: type ".*MismatchDerived2" has a non-default holder type ' +        'while its base ".*MismatchBase2" does not', +        str(excinfo.value), +    )  def test_override_static(): @@ -164,20 +262,20 @@ def test_operator_new_delete(capture):          a = m.HasOpNewDel()          b = m.HasOpNewDelSize()          d = m.HasOpNewDelBoth() -    assert capture == """ +    assert ( +        capture +        == """          A new 8          B new 4          D new 32      """ +    )      sz_alias = str(m.AliasedHasOpNewDelSize.size_alias)      sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias)      with capture:          c = m.AliasedHasOpNewDelSize()          c2 = SubAliased() -    assert capture == ( -        "C new " + sz_noalias + "\n" + -        "C new " + sz_alias + "\n" -    ) +    assert capture == ("C new " + sz_noalias + "\n" + "C new " + sz_alias + "\n")      with capture:          del a @@ -186,21 +284,21 @@ def test_operator_new_delete(capture):          pytest.gc_collect()          del d          pytest.gc_collect() -    assert capture == """ +    assert ( +        capture +        == """          A delete          B delete 4          D delete      """ +    )      with capture:          del c          pytest.gc_collect()          del c2          pytest.gc_collect() -    assert capture == ( -        "C delete " + sz_noalias + "\n" + -        "C delete " + sz_alias + "\n" -    ) +    assert capture == ("C delete " + sz_noalias + "\n" + "C delete " + sz_alias + "\n")  def test_bind_protected_functions(): @@ -235,7 +333,7 @@ def test_brace_initialization():      assert b.vec == [123, 456] -@pytest.unsupported_on_pypy +@pytest.mark.xfail("env.PYPY")  def test_class_refcount():      """Instances must correctly increase/decrease the reference count of their types (#1029)"""      from sys import getrefcount @@ -260,22 +358,109 @@ def test_reentrant_implicit_conversion_failure(msg):      # ensure that there is no runaway reentrant implicit conversion (#1035)      with pytest.raises(TypeError) as excinfo:          m.BogusImplicitConversion(0) -    assert msg(excinfo.value) == ''' +    assert ( +        msg(excinfo.value) +        == """          __init__(): incompatible constructor arguments. The following argument types are supported:              1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)          Invoked with: 0 -    ''' +    """ +    )  def test_error_after_conversions():      with pytest.raises(TypeError) as exc_info:          m.test_error_after_conversions("hello")      assert str(exc_info.value).startswith( -        "Unable to convert function return value to a Python type!") +        "Unable to convert function return value to a Python type!" +    )  def test_aligned():      if hasattr(m, "Aligned"):          p = m.Aligned().ptr()          assert p % 1024 == 0 + + +# https://foss.heptapod.net/pypy/pypy/-/issues/2742 +@pytest.mark.xfail("env.PYPY") +def test_final(): +    with pytest.raises(TypeError) as exc_info: + +        class PyFinalChild(m.IsFinal): +            pass + +    assert str(exc_info.value).endswith("is not an acceptable base type") + + +# https://foss.heptapod.net/pypy/pypy/-/issues/2742 +@pytest.mark.xfail("env.PYPY") +def test_non_final_final(): +    with pytest.raises(TypeError) as exc_info: + +        class PyNonFinalFinalChild(m.IsNonFinalFinal): +            pass + +    assert str(exc_info.value).endswith("is not an acceptable base type") + + +# https://github.com/pybind/pybind11/issues/1878 +def test_exception_rvalue_abort(): +    with pytest.raises(RuntimeError): +        m.PyPrintDestructor().throw_something() + + +# https://github.com/pybind/pybind11/issues/1568 +def test_multiple_instances_with_same_pointer(capture): +    n = 100 +    instances = [m.SamePointer() for _ in range(n)] +    for i in range(n): +        # We need to reuse the same allocated memory for with a different type, +        # to ensure the bug in `deregister_instance_impl` is detected. Otherwise +        # `Py_TYPE(self) == Py_TYPE(it->second)` will still succeed, even though +        # the `instance` is already deleted. +        instances[i] = m.Empty() +    # No assert: if this does not trigger the error +    #   pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!"); +    # and just completes without crashing, we're good. + + +# https://github.com/pybind/pybind11/issues/1624 +def test_base_and_derived_nested_scope(): +    assert issubclass(m.DerivedWithNested, m.BaseWithNested) +    assert m.BaseWithNested.Nested != m.DerivedWithNested.Nested +    assert m.BaseWithNested.Nested.get_name() == "BaseWithNested::Nested" +    assert m.DerivedWithNested.Nested.get_name() == "DerivedWithNested::Nested" + + +def test_register_duplicate_class(): +    import types + +    module_scope = types.ModuleType("module_scope") +    with pytest.raises(RuntimeError) as exc_info: +        m.register_duplicate_class_name(module_scope) +    expected = ( +        'generic_type: cannot initialize type "Duplicate": ' +        "an object with that name is already defined" +    ) +    assert str(exc_info.value) == expected +    with pytest.raises(RuntimeError) as exc_info: +        m.register_duplicate_class_type(module_scope) +    expected = 'generic_type: type "YetAnotherDuplicate" is already registered!' +    assert str(exc_info.value) == expected + +    class ClassScope: +        pass + +    with pytest.raises(RuntimeError) as exc_info: +        m.register_duplicate_nested_class_name(ClassScope) +    expected = ( +        'generic_type: cannot initialize type "DuplicateNested": ' +        "an object with that name is already defined" +    ) +    assert str(exc_info.value) == expected +    with pytest.raises(RuntimeError) as exc_info: +        m.register_duplicate_nested_class_type(ClassScope) +    expected = 'generic_type: type "YetAnotherDuplicateNested" is already registered!' +    assert str(exc_info.value) == expected diff --git a/3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt index c9b5fcb2..0c0578ad 100644 --- a/3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt +++ b/3rdparty/pybind11/tests/test_cmake_build/CMakeLists.txt @@ -1,56 +1,77 @@ -add_custom_target(test_cmake_build) +# Built-in in CMake 3.5+ +include(CMakeParseArguments) -if(CMAKE_VERSION VERSION_LESS 3.1) -  # 3.0 needed for interface library for subdirectory_target/installed_target -  # 3.1 needed for cmake -E env for testing -  return() -endif() +add_custom_target(test_cmake_build) -include(CMakeParseArguments)  function(pybind11_add_build_test name)    cmake_parse_arguments(ARG "INSTALL" "" "" ${ARGN}) -  set(build_options "-DCMAKE_PREFIX_PATH=${PROJECT_BINARY_DIR}/mock_install" -                    "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" -                    "-DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE}" -                    "-DPYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}") +  set(build_options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}") + +  if(PYBIND11_FINDPYTHON) +    list(APPEND build_options "-DPYBIND11_FINDPYTHON=${PYBIND11_FINDPYTHON}") + +    if(DEFINED Python_ROOT_DIR) +      list(APPEND build_options "-DPython_ROOT_DIR=${Python_ROOT_DIR}") +    endif() + +    list(APPEND build_options "-DPython_EXECUTABLE=${Python_EXECUTABLE}") +  else() +    list(APPEND build_options "-DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}") +  endif() + +  if(DEFINED CMAKE_CXX_STANDARD) +    list(APPEND build_options "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}") +  endif() +    if(NOT ARG_INSTALL) -    list(APPEND build_options "-DPYBIND11_PROJECT_DIR=${PROJECT_SOURCE_DIR}") +    list(APPEND build_options "-DPYBIND11_PROJECT_DIR=${pybind11_SOURCE_DIR}") +  else() +    list(APPEND build_options "-DCMAKE_PREFIX_PATH=${pybind11_BINARY_DIR}/mock_install")    endif() -  add_custom_target(test_${name} ${CMAKE_CTEST_COMMAND} -    --quiet --output-log ${name}.log -    --build-and-test "${CMAKE_CURRENT_SOURCE_DIR}/${name}" -                     "${CMAKE_CURRENT_BINARY_DIR}/${name}" -    --build-config Release +  add_custom_target( +    test_build_${name} +    ${CMAKE_CTEST_COMMAND} +    --build-and-test +    "${CMAKE_CURRENT_SOURCE_DIR}/${name}" +    "${CMAKE_CURRENT_BINARY_DIR}/${name}" +    --build-config +    Release      --build-noclean -    --build-generator ${CMAKE_GENERATOR} -    $<$<BOOL:${CMAKE_GENERATOR_PLATFORM}>:--build-generator-platform> ${CMAKE_GENERATOR_PLATFORM} -    --build-makeprogram ${CMAKE_MAKE_PROGRAM} -    --build-target check -    --build-options ${build_options} -  ) +    --build-generator +    ${CMAKE_GENERATOR} +    $<$<BOOL:${CMAKE_GENERATOR_PLATFORM}>:--build-generator-platform> +    ${CMAKE_GENERATOR_PLATFORM} +    --build-makeprogram +    ${CMAKE_MAKE_PROGRAM} +    --build-target +    check_${name} +    --build-options +    ${build_options})    if(ARG_INSTALL) -    add_dependencies(test_${name} mock_install) +    add_dependencies(test_build_${name} mock_install)    endif() -  add_dependencies(test_cmake_build test_${name}) +  add_dependencies(test_cmake_build test_build_${name})  endfunction()  pybind11_add_build_test(subdirectory_function)  pybind11_add_build_test(subdirectory_target) -if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy") +if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy") +  message(STATUS "Skipping embed test on PyPy") +else()    pybind11_add_build_test(subdirectory_embed)  endif()  if(PYBIND11_INSTALL) -  add_custom_target(mock_install ${CMAKE_COMMAND} -    "-DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}/mock_install" -    -P "${PROJECT_BINARY_DIR}/cmake_install.cmake" -  ) +  add_custom_target( +    mock_install ${CMAKE_COMMAND} "-DCMAKE_INSTALL_PREFIX=${pybind11_BINARY_DIR}/mock_install" -P +                 "${pybind11_BINARY_DIR}/cmake_install.cmake")    pybind11_add_build_test(installed_function INSTALL)    pybind11_add_build_test(installed_target INSTALL) -  if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy") +  if(NOT ("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy" +         ))      pybind11_add_build_test(installed_embed INSTALL)    endif()  endif() diff --git a/3rdparty/pybind11/tests/test_cmake_build/embed.cpp b/3rdparty/pybind11/tests/test_cmake_build/embed.cpp index b9581d2f..a3abc8a8 100644 --- a/3rdparty/pybind11/tests/test_cmake_build/embed.cpp +++ b/3rdparty/pybind11/tests/test_cmake_build/embed.cpp @@ -12,10 +12,10 @@ int main(int argc, char *argv[]) {      py::scoped_interpreter guard{}; -    auto m = py::module::import("test_cmake_build"); +    auto m = py::module_::import("test_cmake_build");      if (m.attr("add")(1, 2).cast<int>() != 3)          throw std::runtime_error("embed.cpp failed"); -    py::module::import("sys").attr("argv") = py::make_tuple("test.py", "embed.cpp"); +    py::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 f7fc09c2..64ae5c4b 100644 --- a/3rdparty/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt +++ b/3rdparty/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt @@ -1,15 +1,26 @@ -cmake_minimum_required(VERSION 3.0) +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) +  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +else() +  cmake_policy(VERSION 3.18) +endif() +  project(test_installed_embed CXX) -set(CMAKE_MODULE_PATH "")  find_package(pybind11 CONFIG REQUIRED)  message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") -add_executable(test_cmake_build ../embed.cpp) -target_link_libraries(test_cmake_build PRIVATE pybind11::embed) +add_executable(test_installed_embed ../embed.cpp) +target_link_libraries(test_installed_embed PRIVATE pybind11::embed) +set_target_properties(test_installed_embed PROPERTIES OUTPUT_NAME test_cmake_build)  # Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::embed).  # This may be needed to resolve header conflicts, e.g. between Python release and debug headers. -set_target_properties(test_cmake_build PROPERTIES NO_SYSTEM_FROM_IMPORTED ON) +set_target_properties(test_installed_embed PROPERTIES NO_SYSTEM_FROM_IMPORTED ON) -add_custom_target(check $<TARGET_FILE:test_cmake_build> ${PROJECT_SOURCE_DIR}/../test.py) +add_custom_target(check_installed_embed $<TARGET_FILE:test_installed_embed> +                                        ${PROJECT_SOURCE_DIR}/../test.py) diff --git a/3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt index e0c20a8a..1a502863 100644 --- a/3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt +++ b/3rdparty/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt @@ -1,12 +1,38 @@ -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.4)  project(test_installed_module CXX) -set(CMAKE_MODULE_PATH "") +# 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) +  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +else() +  cmake_policy(VERSION 3.18) +endif() + +project(test_installed_function CXX)  find_package(pybind11 CONFIG REQUIRED) -message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") +message( +  STATUS "Found pybind11 v${pybind11_VERSION} ${pybind11_VERSION_TYPE}: ${pybind11_INCLUDE_DIRS}") + +pybind11_add_module(test_installed_function SHARED NO_EXTRAS ../main.cpp) +set_target_properties(test_installed_function PROPERTIES OUTPUT_NAME test_cmake_build) -pybind11_add_module(test_cmake_build SHARED NO_EXTRAS ../main.cpp) +if(DEFINED Python_EXECUTABLE) +  set(_Python_EXECUTABLE "${Python_EXECUTABLE}") +elseif(DEFINED PYTHON_EXECUTABLE) +  set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}") +else() +  message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)") +endif() -add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:test_cmake_build> -                  ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) +add_custom_target( +  check_installed_function +  ${CMAKE_COMMAND} +  -E +  env +  PYTHONPATH=$<TARGET_FILE_DIR:test_installed_function> +  ${_Python_EXECUTABLE} +  ${PROJECT_SOURCE_DIR}/../test.py +  ${PROJECT_NAME}) diff --git a/3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt index cd3ae6f7..b38eb774 100644 --- a/3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt +++ b/3rdparty/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt @@ -1,22 +1,45 @@ -cmake_minimum_required(VERSION 3.0) -project(test_installed_target CXX) +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) +  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +else() +  cmake_policy(VERSION 3.18) +endif() -set(CMAKE_MODULE_PATH "") +project(test_installed_target CXX)  find_package(pybind11 CONFIG REQUIRED)  message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") -add_library(test_cmake_build MODULE ../main.cpp) +add_library(test_installed_target MODULE ../main.cpp) -target_link_libraries(test_cmake_build PRIVATE pybind11::module) +target_link_libraries(test_installed_target PRIVATE pybind11::module) +set_target_properties(test_installed_target PROPERTIES OUTPUT_NAME test_cmake_build) -# make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib -set_target_properties(test_cmake_build PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" -                                                  SUFFIX "${PYTHON_MODULE_EXTENSION}") +# Make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib +pybind11_extension(test_installed_target)  # Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::module).  # This may be needed to resolve header conflicts, e.g. between Python release and debug headers. -set_target_properties(test_cmake_build PROPERTIES NO_SYSTEM_FROM_IMPORTED ON) +set_target_properties(test_installed_target PROPERTIES NO_SYSTEM_FROM_IMPORTED ON) + +if(DEFINED Python_EXECUTABLE) +  set(_Python_EXECUTABLE "${Python_EXECUTABLE}") +elseif(DEFINED PYTHON_EXECUTABLE) +  set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}") +else() +  message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)") +endif() -add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:test_cmake_build> -                  ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) +add_custom_target( +  check_installed_target +  ${CMAKE_COMMAND} +  -E +  env +  PYTHONPATH=$<TARGET_FILE_DIR:test_installed_target> +  ${_Python_EXECUTABLE} +  ${PROJECT_SOURCE_DIR}/../test.py +  ${PROJECT_NAME}) 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 88ba60dd..c7df0cf7 100644 --- a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt +++ b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt @@ -1,25 +1,39 @@ -cmake_minimum_required(VERSION 3.0) +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) +  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +else() +  cmake_policy(VERSION 3.18) +endif() +  project(test_subdirectory_embed CXX) -set(PYBIND11_INSTALL ON CACHE BOOL "") +set(PYBIND11_INSTALL +    ON +    CACHE BOOL "")  set(PYBIND11_EXPORT_NAME test_export)  add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11)  # Test basic target functionality -add_executable(test_cmake_build ../embed.cpp) -target_link_libraries(test_cmake_build PRIVATE pybind11::embed) +add_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 $<TARGET_FILE:test_cmake_build> ${PROJECT_SOURCE_DIR}/../test.py) +add_custom_target(check_subdirectory_embed $<TARGET_FILE:test_subdirectory_embed> +                                           ${PROJECT_SOURCE_DIR}/../test.py)  # Test custom export group -- PYBIND11_EXPORT_NAME  add_library(test_embed_lib ../embed.cpp)  target_link_libraries(test_embed_lib PRIVATE pybind11::embed) -install(TARGETS test_embed_lib -        EXPORT  test_export -        ARCHIVE DESTINATION bin -        LIBRARY DESTINATION lib -        RUNTIME DESTINATION lib) -install(EXPORT      test_export -        DESTINATION lib/cmake/test_export/test_export-Targets.cmake) +install( +  TARGETS test_embed_lib +  EXPORT test_export +  ARCHIVE DESTINATION bin +  LIBRARY DESTINATION lib +  RUNTIME DESTINATION lib) +install(EXPORT test_export DESTINATION lib/cmake/test_export/test_export-Targets.cmake) diff --git a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt index 278007ae..624c600f 100644 --- a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt +++ b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt @@ -1,8 +1,34 @@ -cmake_minimum_required(VERSION 2.8.12) -project(test_subdirectory_module CXX) +cmake_minimum_required(VERSION 3.4) -add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11) -pybind11_add_module(test_cmake_build THIN_LTO ../main.cpp) +# 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) +  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +else() +  cmake_policy(VERSION 3.18) +endif() -add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:test_cmake_build> -                  ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) +project(test_subdirectory_function CXX) + +add_subdirectory("${PYBIND11_PROJECT_DIR}" pybind11) +pybind11_add_module(test_subdirectory_function ../main.cpp) +set_target_properties(test_subdirectory_function PROPERTIES OUTPUT_NAME test_cmake_build) + +if(DEFINED Python_EXECUTABLE) +  set(_Python_EXECUTABLE "${Python_EXECUTABLE}") +elseif(DEFINED PYTHON_EXECUTABLE) +  set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}") +else() +  message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)") +endif() + +add_custom_target( +  check_subdirectory_function +  ${CMAKE_COMMAND} +  -E +  env +  PYTHONPATH=$<TARGET_FILE_DIR:test_subdirectory_function> +  ${_Python_EXECUTABLE} +  ${PROJECT_SOURCE_DIR}/../test.py +  ${PROJECT_NAME}) diff --git a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt index 6b142d62..2471941f 100644 --- a/3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt +++ b/3rdparty/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt @@ -1,15 +1,40 @@ -cmake_minimum_required(VERSION 3.0) +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) +  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +else() +  cmake_policy(VERSION 3.18) +endif() +  project(test_subdirectory_target CXX)  add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11) -add_library(test_cmake_build MODULE ../main.cpp) +add_library(test_subdirectory_target MODULE ../main.cpp) +set_target_properties(test_subdirectory_target PROPERTIES OUTPUT_NAME test_cmake_build) + +target_link_libraries(test_subdirectory_target PRIVATE pybind11::module) -target_link_libraries(test_cmake_build PRIVATE pybind11::module) +# Make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib +pybind11_extension(test_subdirectory_target) -# make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib -set_target_properties(test_cmake_build PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" -                                                  SUFFIX "${PYTHON_MODULE_EXTENSION}") +if(DEFINED Python_EXECUTABLE) +  set(_Python_EXECUTABLE "${Python_EXECUTABLE}") +elseif(DEFINED PYTHON_EXECUTABLE) +  set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}") +else() +  message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)") +endif() -add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$<TARGET_FILE_DIR:test_cmake_build> -                  ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) +add_custom_target( +  check_subdirectory_target +  ${CMAKE_COMMAND} +  -E +  env +  PYTHONPATH=$<TARGET_FILE_DIR:test_subdirectory_target> +  ${_Python_EXECUTABLE} +  ${PROJECT_SOURCE_DIR}/../test.py +  ${PROJECT_NAME}) diff --git a/3rdparty/pybind11/tests/test_cmake_build/test.py b/3rdparty/pybind11/tests/test_cmake_build/test.py index 1467a61d..87ed5135 100644 --- a/3rdparty/pybind11/tests/test_cmake_build/test.py +++ b/3rdparty/pybind11/tests/test_cmake_build/test.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*-  import sys  import test_cmake_build diff --git a/3rdparty/pybind11/tests/test_constants_and_functions.cpp b/3rdparty/pybind11/tests/test_constants_and_functions.cpp index e8ec74b7..f6077955 100644 --- a/3rdparty/pybind11/tests/test_constants_and_functions.cpp +++ b/3rdparty/pybind11/tests/test_constants_and_functions.cpp @@ -74,7 +74,7 @@ struct C {  #  pragma GCC diagnostic pop  #endif  }; -} +} // namespace test_exc_sp  TEST_SUBMODULE(constants_and_functions, m) { diff --git a/3rdparty/pybind11/tests/test_constants_and_functions.py b/3rdparty/pybind11/tests/test_constants_and_functions.py index 472682d6..b980ccf1 100644 --- a/3rdparty/pybind11/tests/test_constants_and_functions.py +++ b/3rdparty/pybind11/tests/test_constants_and_functions.py @@ -1,4 +1,7 @@ -from pybind11_tests import constants_and_functions as m +# -*- coding: utf-8 -*- +import pytest + +m = pytest.importorskip("pybind11_tests.constants_and_functions")  def test_constants(): diff --git a/3rdparty/pybind11/tests/test_copy_move.cpp b/3rdparty/pybind11/tests/test_copy_move.cpp index 98d5e0a0..2704217a 100644 --- a/3rdparty/pybind11/tests/test_copy_move.cpp +++ b/3rdparty/pybind11/tests/test_copy_move.cpp @@ -19,14 +19,14 @@ struct empty {  };  struct lacking_copy_ctor : public empty<lacking_copy_ctor> { -    lacking_copy_ctor() {} +    lacking_copy_ctor() = default;      lacking_copy_ctor(const lacking_copy_ctor& other) = delete;  };  template <> lacking_copy_ctor empty<lacking_copy_ctor>::instance_ = {};  struct lacking_move_ctor : public empty<lacking_move_ctor> { -    lacking_move_ctor() {} +    lacking_move_ctor() = default;      lacking_move_ctor(const lacking_move_ctor& other) = delete;      lacking_move_ctor(lacking_move_ctor&& other) = delete;  }; @@ -68,8 +68,8 @@ public:      int value;  }; -NAMESPACE_BEGIN(pybind11) -NAMESPACE_BEGIN(detail) +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; } @@ -97,8 +97,8 @@ public:      operator CopyOnlyInt&() { return value; }      template <typename T> using cast_op_type = pybind11::detail::cast_op_type<T>;  }; -NAMESPACE_END(detail) -NAMESPACE_END(pybind11) +PYBIND11_NAMESPACE_END(detail) +PYBIND11_NAMESPACE_END(pybind11)  TEST_SUBMODULE(copy_move_policies, m) {      // test_lacking_copy_ctor @@ -116,9 +116,9 @@ TEST_SUBMODULE(copy_move_policies, m) {          r += py::cast<MoveOrCopyInt>(o).value; /* moves */          r += py::cast<MoveOnlyInt>(o).value; /* moves */          r += py::cast<CopyOnlyInt>(o).value; /* copies */ -        MoveOrCopyInt m1(py::cast<MoveOrCopyInt>(o)); /* moves */ -        MoveOnlyInt m2(py::cast<MoveOnlyInt>(o)); /* moves */ -        CopyOnlyInt m3(py::cast<CopyOnlyInt>(o)); /* copies */ +        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; @@ -175,14 +175,20 @@ TEST_SUBMODULE(copy_move_policies, m) {      m.attr("has_optional") = false;  #endif -    // #70 compilation issue if operator new is not public +    // #70 compilation issue if operator new is not public - simple body added +    // but not needed on most compilers; MSVC and nvcc don't like a local +    // struct not having a method defined when declared, since it can not be +    // added later.      struct PrivateOpNew {          int value = 1;      private: -#if defined(_MSC_VER) -#  pragma warning(disable: 4822) // warning C4822: local class member function does not have a body -#endif -        void *operator new(size_t bytes); +        void *operator new(size_t bytes) { +            void *ptr = std::malloc(bytes); +            if (ptr) +                return ptr; +            else +                throw std::bad_alloc{}; +        }      };      py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);      m.def("private_op_new_value", []() { return PrivateOpNew(); }); diff --git a/3rdparty/pybind11/tests/test_copy_move.py b/3rdparty/pybind11/tests/test_copy_move.py index 0e671d96..7e3cc168 100644 --- a/3rdparty/pybind11/tests/test_copy_move.py +++ b/3rdparty/pybind11/tests/test_copy_move.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*-  import pytest  from pybind11_tests import copy_move_policies as m @@ -18,7 +19,11 @@ def test_move_and_copy_casts():      """Cast some values in C++ via custom type casters and count the number of moves/copies."""      cstats = m.move_and_copy_cstats() -    c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"] +    c_m, c_mc, c_c = ( +        cstats["MoveOnlyInt"], +        cstats["MoveOrCopyInt"], +        cstats["CopyOnlyInt"], +    )      # The type move constructions/assignments below each get incremented: the move assignment comes      # from the type_caster load; the move construction happens when extracting that via a cast or @@ -42,7 +47,11 @@ def test_move_and_copy_loads():      moves/copies."""      cstats = m.move_and_copy_cstats() -    c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"] +    c_m, c_mc, c_c = ( +        cstats["MoveOnlyInt"], +        cstats["MoveOrCopyInt"], +        cstats["CopyOnlyInt"], +    )      assert m.move_only(10) == 10  # 1 move, c_m      assert m.move_or_copy(11) == 11  # 1 move, c_mc @@ -65,12 +74,16 @@ def test_move_and_copy_loads():      assert c_m.alive() + c_mc.alive() + c_c.alive() == 0 -@pytest.mark.skipif(not m.has_optional, reason='no <optional>') +@pytest.mark.skipif(not m.has_optional, reason="no <optional>")  def test_move_and_copy_load_optional():      """Tests move/copy loads of std::optional arguments"""      cstats = m.move_and_copy_cstats() -    c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"] +    c_m, c_mc, c_c = ( +        cstats["MoveOnlyInt"], +        cstats["MoveOrCopyInt"], +        cstats["CopyOnlyInt"], +    )      # The extra move/copy constructions below come from the std::optional move (which has to move      # its arguments): diff --git a/3rdparty/pybind11/tests/test_custom_type_casters.cpp b/3rdparty/pybind11/tests/test_custom_type_casters.cpp new file mode 100644 index 00000000..d565add2 --- /dev/null +++ b/3rdparty/pybind11/tests/test_custom_type_casters.cpp @@ -0,0 +1,127 @@ +/* +    tests/test_custom_type_casters.cpp -- tests type_caster<T> + +    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> + +    All rights reserved. Use of this source code is governed by a +    BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" + + +// py::arg/py::arg_v testing: these arguments just record their argument when invoked +class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; }; +class ArgInspector2 { public: std::string arg = "(default arg inspector 2)"; }; +class ArgAlwaysConverts { }; +namespace pybind11 { namespace detail { +template <> struct type_caster<ArgInspector1> { +public: +    PYBIND11_TYPE_CASTER(ArgInspector1, _("ArgInspector1")); + +    bool load(handle src, bool convert) { +        value.arg = "loading ArgInspector1 argument " + +            std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed.  " +            "Argument value = " + (std::string) str(src); +        return true; +    } + +    static handle cast(const ArgInspector1 &src, return_value_policy, handle) { +        return str(src.arg).release(); +    } +}; +template <> struct type_caster<ArgInspector2> { +public: +    PYBIND11_TYPE_CASTER(ArgInspector2, _("ArgInspector2")); + +    bool load(handle src, bool convert) { +        value.arg = "loading ArgInspector2 argument " + +            std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed.  " +            "Argument value = " + (std::string) str(src); +        return true; +    } + +    static handle cast(const ArgInspector2 &src, return_value_policy, handle) { +        return str(src.arg).release(); +    } +}; +template <> struct type_caster<ArgAlwaysConverts> { +public: +    PYBIND11_TYPE_CASTER(ArgAlwaysConverts, _("ArgAlwaysConverts")); + +    bool load(handle, bool convert) { +        return convert; +    } + +    static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) { +        return py::none().release(); +    } +}; +} // namespace detail +} // namespace pybind11 + +// test_custom_caster_destruction +class DestructionTester { +public: +    DestructionTester() { print_default_created(this); } +    ~DestructionTester() { print_destroyed(this); } +    DestructionTester(const DestructionTester &) { print_copy_created(this); } +    DestructionTester(DestructionTester &&) { print_move_created(this); } +    DestructionTester &operator=(const DestructionTester &) { print_copy_assigned(this); return *this; } +    DestructionTester &operator=(DestructionTester &&) { print_move_assigned(this); return *this; } +}; +namespace pybind11 { namespace detail { +template <> struct type_caster<DestructionTester> { +    PYBIND11_TYPE_CASTER(DestructionTester, _("DestructionTester")); +    bool load(handle, bool) { return true; } + +    static handle cast(const DestructionTester &, return_value_policy, handle) { +        return py::bool_(true).release(); +    } +}; +} // namespace detail +} // namespace pybind11 + +TEST_SUBMODULE(custom_type_casters, m) { +    // test_custom_type_casters + +    // test_noconvert_args +    // +    // Test converting.  The ArgAlwaysConverts is just there to make the first no-conversion pass +    // fail so that our call always ends up happening via the second dispatch (the one that allows +    // some conversion). +    class ArgInspector { +    public: +        ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; } +        std::string g(ArgInspector1 a, const ArgInspector1 &b, int c, ArgInspector2 *d, ArgAlwaysConverts) { +            return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg; +        } +        static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; } +    }; +    py::class_<ArgInspector>(m, "ArgInspector") +        .def(py::init<>()) +        .def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts()) +        .def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert()=13, "d"_a=ArgInspector2(), py::arg() = ArgAlwaysConverts()) +        .def_static("h", &ArgInspector::h, py::arg().noconvert(), py::arg() = ArgAlwaysConverts()) +        ; +    m.def("arg_inspect_func", [](ArgInspector2 a, ArgInspector1 b, ArgAlwaysConverts) { return a.arg + "\n" + b.arg; }, +            py::arg().noconvert(false), py::arg_v(nullptr, ArgInspector1()).noconvert(true), py::arg() = ArgAlwaysConverts()); + +    m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f")); +    m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert()); +    m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i")); +    m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert()); + +    // test_custom_caster_destruction +    // Test that `take_ownership` works on types with a custom type caster when given a pointer + +    // default policy: don't take ownership: +    m.def("custom_caster_no_destroy", []() { static auto *dt = new DestructionTester(); return dt; }); + +    m.def("custom_caster_destroy", []() { return new DestructionTester(); }, +            py::return_value_policy::take_ownership); // Takes ownership: destroy when finished +    m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); }, +            py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction) +    m.def("destruction_tester_cstats", &ConstructorStats::get<DestructionTester>, py::return_value_policy::reference); +} diff --git a/3rdparty/pybind11/tests/test_custom_type_casters.py b/3rdparty/pybind11/tests/test_custom_type_casters.py new file mode 100644 index 00000000..bb74d54e --- /dev/null +++ b/3rdparty/pybind11/tests/test_custom_type_casters.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- +import pytest +from pybind11_tests import custom_type_casters as m + + +def test_noconvert_args(msg): +    a = m.ArgInspector() +    assert ( +        msg(a.f("hi")) +        == """ +        loading ArgInspector1 argument WITH conversion allowed.  Argument value = hi +    """ +    ) +    assert ( +        msg(a.g("this is a", "this is b")) +        == """ +        loading ArgInspector1 argument WITHOUT conversion allowed.  Argument value = this is a +        loading ArgInspector1 argument WITH conversion allowed.  Argument value = this is b +        13 +        loading ArgInspector2 argument WITH conversion allowed.  Argument value = (default arg inspector 2) +    """  # noqa: E501 line too long +    ) +    assert ( +        msg(a.g("this is a", "this is b", 42)) +        == """ +        loading ArgInspector1 argument WITHOUT conversion allowed.  Argument value = this is a +        loading ArgInspector1 argument WITH conversion allowed.  Argument value = this is b +        42 +        loading ArgInspector2 argument WITH conversion allowed.  Argument value = (default arg inspector 2) +    """  # noqa: E501 line too long +    ) +    assert ( +        msg(a.g("this is a", "this is b", 42, "this is d")) +        == """ +        loading ArgInspector1 argument WITHOUT conversion allowed.  Argument value = this is a +        loading ArgInspector1 argument WITH conversion allowed.  Argument value = this is b +        42 +        loading ArgInspector2 argument WITH conversion allowed.  Argument value = this is d +    """ +    ) +    assert ( +        a.h("arg 1") +        == "loading ArgInspector2 argument WITHOUT conversion allowed.  Argument value = arg 1" +    ) +    assert ( +        msg(m.arg_inspect_func("A1", "A2")) +        == """ +        loading ArgInspector2 argument WITH conversion allowed.  Argument value = A1 +        loading ArgInspector1 argument WITHOUT conversion allowed.  Argument value = A2 +    """ +    ) + +    assert m.floats_preferred(4) == 2.0 +    assert m.floats_only(4.0) == 2.0 +    with pytest.raises(TypeError) as excinfo: +        m.floats_only(4) +    assert ( +        msg(excinfo.value) +        == """ +        floats_only(): incompatible function arguments. The following argument types are supported: +            1. (f: float) -> float + +        Invoked with: 4 +    """ +    ) + +    assert m.ints_preferred(4) == 2 +    assert m.ints_preferred(True) == 0 +    with pytest.raises(TypeError) as excinfo: +        m.ints_preferred(4.0) +    assert ( +        msg(excinfo.value) +        == """ +        ints_preferred(): incompatible function arguments. The following argument types are supported: +            1. (i: int) -> int + +        Invoked with: 4.0 +    """  # noqa: E501 line too long +    ) + +    assert m.ints_only(4) == 2 +    with pytest.raises(TypeError) as excinfo: +        m.ints_only(4.0) +    assert ( +        msg(excinfo.value) +        == """ +        ints_only(): incompatible function arguments. The following argument types are supported: +            1. (i: int) -> int + +        Invoked with: 4.0 +    """ +    ) + + +def test_custom_caster_destruction(): +    """Tests that returning a pointer to a type that gets converted with a custom type caster gets +    destroyed when the function has py::return_value_policy::take_ownership policy applied.""" + +    cstats = m.destruction_tester_cstats() +    # This one *doesn't* have take_ownership: the pointer should be used but not destroyed: +    z = m.custom_caster_no_destroy() +    assert cstats.alive() == 1 and cstats.default_constructions == 1 +    assert z + +    # take_ownership applied: this constructs a new object, casts it, then destroys it: +    z = m.custom_caster_destroy() +    assert z +    assert cstats.default_constructions == 2 + +    # Same, but with a const pointer return (which should *not* inhibit destruction): +    z = m.custom_caster_destroy_const() +    assert z +    assert cstats.default_constructions == 3 + +    # Make sure we still only have the original object (from ..._no_destroy()) alive: +    assert cstats.alive() == 1 diff --git a/3rdparty/pybind11/tests/test_docstring_options.py b/3rdparty/pybind11/tests/test_docstring_options.py index 0dbca609..87d80d2d 100644 --- a/3rdparty/pybind11/tests/test_docstring_options.py +++ b/3rdparty/pybind11/tests/test_docstring_options.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*-  from pybind11_tests import docstring_options as m @@ -17,10 +18,10 @@ def test_docstring_options():      assert m.test_overloaded3.__doc__ == "Overload docstr"      # options.enable_function_signatures() -    assert m.test_function3.__doc__ .startswith("test_function3(a: int, b: int) -> None") +    assert m.test_function3.__doc__.startswith("test_function3(a: int, b: int) -> None") -    assert m.test_function4.__doc__ .startswith("test_function4(a: int, b: int) -> None") -    assert m.test_function4.__doc__ .endswith("A custom docstring\n") +    assert m.test_function4.__doc__.startswith("test_function4(a: int, b: int) -> None") +    assert m.test_function4.__doc__.endswith("A custom docstring\n")      # options.disable_function_signatures()      # options.disable_user_defined_docstrings() @@ -30,8 +31,8 @@ def test_docstring_options():      assert m.test_function6.__doc__ == "A custom docstring"      # RAII destructor -    assert m.test_function7.__doc__ .startswith("test_function7(a: int, b: int) -> None") -    assert m.test_function7.__doc__ .endswith("A custom docstring\n") +    assert m.test_function7.__doc__.startswith("test_function7(a: int, b: int) -> None") +    assert m.test_function7.__doc__.endswith("A custom docstring\n")      # Suppression of user-defined docstrings for non-function objects      assert not m.DocstringTestFoo.__doc__ diff --git a/3rdparty/pybind11/tests/test_eigen.cpp b/3rdparty/pybind11/tests/test_eigen.cpp index aba088d7..2cc2243d 100644 --- a/3rdparty/pybind11/tests/test_eigen.cpp +++ b/3rdparty/pybind11/tests/test_eigen.cpp @@ -61,8 +61,9 @@ double get_elem(Eigen::Ref<const Eigen::MatrixXd> m) { return m(2, 1); };  // reference is referencing rows/columns correctly).  template <typename MatrixArgType> Eigen::MatrixXd adjust_matrix(MatrixArgType m) {      Eigen::MatrixXd ret(m); -    for (int c = 0; c < m.cols(); c++) for (int r = 0; r < m.rows(); r++) -        ret(r, c) += 10*r + 100*c; +    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;  } @@ -87,8 +88,6 @@ TEST_SUBMODULE(eigen, m) {      using SparseMatrixR = Eigen::SparseMatrix<float, Eigen::RowMajor>;      using SparseMatrixC = Eigen::SparseMatrix<float>; -    m.attr("have_eigen") = true; -      // various tests      m.def("double_col", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2.0f * x; });      m.def("double_row", [](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2.0f * x; }); @@ -257,7 +256,7 @@ TEST_SUBMODULE(eigen, m) {      m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; });      m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; });      // test_sparse, test_sparse_signature -    m.def("sparse_r", [mat]() -> SparseMatrixR { return Eigen::SparseView<Eigen::MatrixXf>(mat); }); +    m.def("sparse_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_copy_r", [](const SparseMatrixR &m) -> SparseMatrixR { return m; });      m.def("sparse_copy_c", [](const SparseMatrixC &m) -> SparseMatrixC { return m; }); @@ -319,11 +318,11 @@ TEST_SUBMODULE(eigen, m) {      // a new array (np.ones(10)) increases the chances that the temp array will be garbage      // collected and/or that its memory will be overridden with different values.      m.def("get_elem_direct", [](Eigen::Ref<const Eigen::VectorXd> v) { -        py::module::import("numpy").attr("ones")(10); +        py::module_::import("numpy").attr("ones")(10);          return v(5);      });      m.def("get_elem_indirect", [](std::vector<Eigen::Ref<const Eigen::VectorXd>> v) { -        py::module::import("numpy").attr("ones")(10); +        py::module_::import("numpy").attr("ones")(10);          return v[0](5);      });  } diff --git a/3rdparty/pybind11/tests/test_eigen.py b/3rdparty/pybind11/tests/test_eigen.py index 55d93517..a131dc15 100644 --- a/3rdparty/pybind11/tests/test_eigen.py +++ b/3rdparty/pybind11/tests/test_eigen.py @@ -1,17 +1,20 @@ +# -*- coding: utf-8 -*-  import pytest  from pybind11_tests import ConstructorStats -pytestmark = pytest.requires_eigen_and_numpy +np = pytest.importorskip("numpy") +m = pytest.importorskip("pybind11_tests.eigen") -with pytest.suppress(ImportError): -    from pybind11_tests import eigen as m -    import numpy as np -    ref = np.array([[ 0.,  3,  0,  0,  0, 11], -                    [22,  0,  0,  0, 17, 11], -                    [ 7,  5,  0,  1,  0, 11], -                    [ 0,  0,  0,  0,  0, 11], -                    [ 0,  0, 14,  0,  8, 11]]) +ref = np.array( +    [ +        [0.0, 3, 0, 0, 0, 11], +        [22, 0, 0, 0, 17, 11], +        [7, 5, 0, 1, 0, 11], +        [0, 0, 0, 0, 0, 11], +        [0, 0, 14, 0, 8, 11], +    ] +)  def assert_equal_ref(mat): @@ -41,28 +44,37 @@ def test_dense():  def test_partially_fixed(): -    ref2 = np.array([[0., 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]) +    ref2 = np.array([[0.0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]])      np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2), ref2)      np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2), ref2)      np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, 1]), ref2[:, [1]])      np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2[0, :]), ref2[[0], :]) -    np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)])      np.testing.assert_array_equal( -        m.partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]) +        m.partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)] +    ) +    np.testing.assert_array_equal( +        m.partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :] +    )      np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2), ref2)      np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2), ref2)      np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, 1]), ref2[:, [1]])      np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2[0, :]), ref2[[0], :]) -    np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)])      np.testing.assert_array_equal( -        m.partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]) +        m.partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)] +    ) +    np.testing.assert_array_equal( +        m.partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :] +    )      # TypeError should be raise for a shape mismatch -    functions = [m.partial_copy_four_rm_r, m.partial_copy_four_rm_c, -                 m.partial_copy_four_cm_r, m.partial_copy_four_cm_c] -    matrix_with_wrong_shape = [[1, 2], -                               [3, 4]] +    functions = [ +        m.partial_copy_four_rm_r, +        m.partial_copy_four_rm_c, +        m.partial_copy_four_cm_r, +        m.partial_copy_four_cm_c, +    ] +    matrix_with_wrong_shape = [[1, 2], [3, 4]]      for f in functions:          with pytest.raises(TypeError) as excinfo:              f(matrix_with_wrong_shape) @@ -70,7 +82,7 @@ def test_partially_fixed():  def test_mutator_descriptors(): -    zr = np.arange(30, dtype='float32').reshape(5, 6)  # row-major +    zr = np.arange(30, dtype="float32").reshape(5, 6)  # row-major      zc = zr.reshape(6, 5).transpose()  # column-major      m.fixed_mutator_r(zr) @@ -79,16 +91,21 @@ def test_mutator_descriptors():      m.fixed_mutator_a(zc)      with pytest.raises(TypeError) as excinfo:          m.fixed_mutator_r(zc) -    assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.c_contiguous]) -> None' -            in str(excinfo.value)) +    assert ( +        "(arg0: numpy.ndarray[numpy.float32[5, 6]," +        " flags.writeable, flags.c_contiguous]) -> None" in str(excinfo.value) +    )      with pytest.raises(TypeError) as excinfo:          m.fixed_mutator_c(zr) -    assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.f_contiguous]) -> None' -            in str(excinfo.value)) +    assert ( +        "(arg0: numpy.ndarray[numpy.float32[5, 6]," +        " flags.writeable, flags.f_contiguous]) -> None" in str(excinfo.value) +    )      with pytest.raises(TypeError) as excinfo: -        m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype='float32')) -    assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable]) -> None' -            in str(excinfo.value)) +        m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype="float32")) +    assert "(arg0: numpy.ndarray[numpy.float32[5, 6], flags.writeable]) -> None" in str( +        excinfo.value +    )      zr.flags.writeable = False      with pytest.raises(TypeError):          m.fixed_mutator_r(zr) @@ -97,26 +114,26 @@ def test_mutator_descriptors():  def test_cpp_casting(): -    assert m.cpp_copy(m.fixed_r()) == 22. -    assert m.cpp_copy(m.fixed_c()) == 22. -    z = np.array([[5., 6], [7, 8]]) -    assert m.cpp_copy(z) == 7. -    assert m.cpp_copy(m.get_cm_ref()) == 21. -    assert m.cpp_copy(m.get_rm_ref()) == 21. -    assert m.cpp_ref_c(m.get_cm_ref()) == 21. -    assert m.cpp_ref_r(m.get_rm_ref()) == 21. +    assert m.cpp_copy(m.fixed_r()) == 22.0 +    assert m.cpp_copy(m.fixed_c()) == 22.0 +    z = np.array([[5.0, 6], [7, 8]]) +    assert m.cpp_copy(z) == 7.0 +    assert m.cpp_copy(m.get_cm_ref()) == 21.0 +    assert m.cpp_copy(m.get_rm_ref()) == 21.0 +    assert m.cpp_ref_c(m.get_cm_ref()) == 21.0 +    assert m.cpp_ref_r(m.get_rm_ref()) == 21.0      with pytest.raises(RuntimeError) as excinfo:          # Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles          m.cpp_ref_any(m.fixed_c()) -    assert 'Unable to cast Python instance' in str(excinfo.value) +    assert "Unable to cast Python instance" in str(excinfo.value)      with pytest.raises(RuntimeError) as excinfo:          # Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles          m.cpp_ref_any(m.fixed_r()) -    assert 'Unable to cast Python instance' in str(excinfo.value) -    assert m.cpp_ref_any(m.ReturnTester.create()) == 1. +    assert "Unable to cast Python instance" in str(excinfo.value) +    assert m.cpp_ref_any(m.ReturnTester.create()) == 1.0 -    assert m.cpp_ref_any(m.get_cm_ref()) == 21. -    assert m.cpp_ref_any(m.get_cm_ref()) == 21. +    assert m.cpp_ref_any(m.get_cm_ref()) == 21.0 +    assert m.cpp_ref_any(m.get_cm_ref()) == 21.0  def test_pass_readonly_array(): @@ -141,14 +158,14 @@ def test_nonunit_stride_from_python():      counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))      slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]] -    for slice_idx, ref_mat in enumerate(slices): +    for ref_mat in slices:          np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)          np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)      # Mutator:      m.double_threer(second_row)      m.double_threec(second_col) -    np.testing.assert_array_equal(counting_mat, [[0., 2, 2], [6, 16, 10], [6, 14, 8]]) +    np.testing.assert_array_equal(counting_mat, [[0.0, 2, 2], [6, 16, 10], [6, 14, 8]])  def test_negative_stride_from_python(msg): @@ -170,33 +187,43 @@ def test_negative_stride_from_python(msg):      counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))      counting_3d = counting_3d[::-1, ::-1, ::-1]      slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]] -    for slice_idx, ref_mat in enumerate(slices): +    for ref_mat in slices:          np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat)          np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat)      # Mutator:      with pytest.raises(TypeError) as excinfo:          m.double_threer(second_row) -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          double_threer(): incompatible function arguments. The following argument types are supported: -            1. (arg0: numpy.ndarray[float32[1, 3], flags.writeable]) -> None +            1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None -        Invoked with: """ + repr(np.array([ 5.,  4.,  3.], dtype='float32'))  # noqa: E501 line too long +        Invoked with: """  # noqa: E501 line too long +        + repr(np.array([5.0, 4.0, 3.0], dtype="float32")) +    )      with pytest.raises(TypeError) as excinfo:          m.double_threec(second_col) -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          double_threec(): incompatible function arguments. The following argument types are supported: -            1. (arg0: numpy.ndarray[float32[3, 1], flags.writeable]) -> None +            1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None -        Invoked with: """ + repr(np.array([ 7.,  4.,  1.], dtype='float32'))  # noqa: E501 line too long +        Invoked with: """  # noqa: E501 line too long +        + repr(np.array([7.0, 4.0, 1.0], dtype="float32")) +    )  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) +        ), "m.diagonal_n({})".format(i)      assert np.all(m.block(ref, 2, 1, 3, 3) == ref[2:5, 1:4])      assert np.all(m.block(ref, 1, 4, 4, 2) == ref[1:, 4:]) @@ -206,8 +233,10 @@ def test_nonunit_stride_to_python():  def test_eigen_ref_to_python():      chols = [m.cholesky1, m.cholesky2, m.cholesky3, m.cholesky4]      for i, chol in enumerate(chols, start=1): -        mymat = chol(np.array([[1., 2, 4], [2, 13, 23], [4, 23, 77]])) -        assert np.all(mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])), "cholesky{}".format(i) +        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)  def assign_both(a1, a2, r, c, v): @@ -324,8 +353,12 @@ def test_eigen_return_references():      np.testing.assert_array_equal(a_block1, master[3:5, 3:5])      np.testing.assert_array_equal(a_block2, master[2:5, 2:4])      np.testing.assert_array_equal(a_block3, master[6:10, 7:10]) -    np.testing.assert_array_equal(a_corn1, master[0::master.shape[0] - 1, 0::master.shape[1] - 1]) -    np.testing.assert_array_equal(a_corn2, master[0::master.shape[0] - 1, 0::master.shape[1] - 1]) +    np.testing.assert_array_equal( +        a_corn1, master[0 :: master.shape[0] - 1, 0 :: master.shape[1] - 1] +    ) +    np.testing.assert_array_equal( +        a_corn2, master[0 :: master.shape[0] - 1, 0 :: master.shape[1] - 1] +    )      np.testing.assert_array_equal(a_copy1, c1want)      np.testing.assert_array_equal(a_copy2, c2want) @@ -354,16 +387,28 @@ def test_eigen_keepalive():      cstats = ConstructorStats.get(m.ReturnTester)      assert cstats.alive() == 1      unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)] -    copies = [a.copy_get(), a.copy_view(), a.copy_ref(), a.copy_ref_const(), -              a.copy_block(4, 3, 2, 1)] +    copies = [ +        a.copy_get(), +        a.copy_view(), +        a.copy_ref(), +        a.copy_ref_const(), +        a.copy_block(4, 3, 2, 1), +    ]      del a      assert cstats.alive() == 0      del unsafe      del copies -    for meth in [m.ReturnTester.get, m.ReturnTester.get_ptr, m.ReturnTester.view, -                 m.ReturnTester.view_ptr, m.ReturnTester.ref_safe, m.ReturnTester.ref_const_safe, -                 m.ReturnTester.corners, m.ReturnTester.corners_const]: +    for meth in [ +        m.ReturnTester.get, +        m.ReturnTester.get_ptr, +        m.ReturnTester.view, +        m.ReturnTester.view_ptr, +        m.ReturnTester.ref_safe, +        m.ReturnTester.ref_const_safe, +        m.ReturnTester.corners, +        m.ReturnTester.corners_const, +    ]:          assert_keeps_alive(m.ReturnTester, meth)      for meth in [m.ReturnTester.block_safe, m.ReturnTester.block_const]: @@ -373,18 +418,18 @@ def test_eigen_keepalive():  def test_eigen_ref_mutators():      """Tests Eigen's ability to mutate numpy values""" -    orig = np.array([[1., 2, 3], [4, 5, 6], [7, 8, 9]]) +    orig = np.array([[1.0, 2, 3], [4, 5, 6], [7, 8, 9]])      zr = np.array(orig) -    zc = np.array(orig, order='F') +    zc = np.array(orig, order="F")      m.add_rm(zr, 1, 0, 100) -    assert np.all(zr == np.array([[1., 2, 3], [104, 5, 6], [7, 8, 9]])) +    assert np.all(zr == np.array([[1.0, 2, 3], [104, 5, 6], [7, 8, 9]]))      m.add_cm(zc, 1, 0, 200) -    assert np.all(zc == np.array([[1., 2, 3], [204, 5, 6], [7, 8, 9]])) +    assert np.all(zc == np.array([[1.0, 2, 3], [204, 5, 6], [7, 8, 9]]))      m.add_any(zr, 1, 0, 20) -    assert np.all(zr == np.array([[1., 2, 3], [124, 5, 6], [7, 8, 9]])) +    assert np.all(zr == np.array([[1.0, 2, 3], [124, 5, 6], [7, 8, 9]]))      m.add_any(zc, 1, 0, 10) -    assert np.all(zc == np.array([[1., 2, 3], [214, 5, 6], [7, 8, 9]])) +    assert np.all(zc == np.array([[1.0, 2, 3], [214, 5, 6], [7, 8, 9]]))      # Can't reference a col-major array with a row-major Ref, and vice versa:      with pytest.raises(TypeError): @@ -405,8 +450,8 @@ def test_eigen_ref_mutators():      cornersr = zr[0::2, 0::2]      cornersc = zc[0::2, 0::2] -    assert np.all(cornersr == np.array([[1., 3], [7, 9]])) -    assert np.all(cornersc == np.array([[1., 3], [7, 9]])) +    assert np.all(cornersr == np.array([[1.0, 3], [7, 9]])) +    assert np.all(cornersc == np.array([[1.0, 3], [7, 9]]))      with pytest.raises(TypeError):          m.add_rm(cornersr, 0, 1, 25) @@ -418,8 +463,8 @@ def test_eigen_ref_mutators():          m.add_cm(cornersc, 0, 1, 25)      m.add_any(cornersr, 0, 1, 25)      m.add_any(cornersc, 0, 1, 44) -    assert np.all(zr == np.array([[1., 2, 28], [4, 5, 6], [7, 8, 9]])) -    assert np.all(zc == np.array([[1., 2, 47], [4, 5, 6], [7, 8, 9]])) +    assert np.all(zr == np.array([[1.0, 2, 28], [4, 5, 6], [7, 8, 9]])) +    assert np.all(zc == np.array([[1.0, 2, 47], [4, 5, 6], [7, 8, 9]]))      # You shouldn't be allowed to pass a non-writeable array to a mutating Eigen method:      zro = zr[0:4, 0:4] @@ -457,7 +502,7 @@ def test_numpy_ref_mutators():      assert not zrro.flags.owndata and not zrro.flags.writeable      zc[1, 2] = 99 -    expect = np.array([[11., 12, 13], [21, 22, 99], [31, 32, 33]]) +    expect = np.array([[11.0, 12, 13], [21, 22, 99], [31, 32, 33]])      # We should have just changed zc, of course, but also zcro and the original eigen matrix      assert np.all(zc == expect)      assert np.all(zcro == expect) @@ -505,18 +550,20 @@ def test_both_ref_mutators():      assert np.all(z == z3)      assert np.all(z == z4)      assert np.all(z == z5) -    expect = np.array([[0., 22, 20], [31, 37, 33], [41, 42, 38]]) +    expect = np.array([[0.0, 22, 20], [31, 37, 33], [41, 42, 38]])      assert np.all(z == expect) -    y = np.array(range(100), dtype='float64').reshape(10, 10) +    y = np.array(range(100), dtype="float64").reshape(10, 10)      y2 = m.incr_matrix_any(y, 10)  # np -> eigen -> np -    y3 = m.incr_matrix_any(y2[0::2, 0::2], -33)  # np -> eigen -> np slice -> np -> eigen -> np +    y3 = m.incr_matrix_any( +        y2[0::2, 0::2], -33 +    )  # np -> eigen -> np slice -> np -> eigen -> np      y4 = m.even_rows(y3)  # numpy -> eigen slice -> (... y3)      y5 = m.even_cols(y4)  # numpy -> eigen slice -> (... y4)      y6 = m.incr_matrix_any(y5, 1000)  # numpy -> eigen -> (... y5)      # Apply same mutations using just numpy: -    yexpect = np.array(range(100), dtype='float64').reshape(10, 10) +    yexpect = np.array(range(100), dtype="float64").reshape(10, 10)      yexpect += 10      yexpect[0::2, 0::2] -= 33      yexpect[0::4, 0::4] += 1000 @@ -531,10 +578,14 @@ def test_both_ref_mutators():  def test_nocopy_wrapper():      # get_elem requires a column-contiguous matrix reference, but should be      # callable with other types of matrix (via copying): -    int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order='F') -    dbl_matrix_colmajor = np.array(int_matrix_colmajor, dtype='double', order='F', copy=True) -    int_matrix_rowmajor = np.array(int_matrix_colmajor, order='C', copy=True) -    dbl_matrix_rowmajor = np.array(int_matrix_rowmajor, dtype='double', order='C', copy=True) +    int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order="F") +    dbl_matrix_colmajor = np.array( +        int_matrix_colmajor, dtype="double", order="F", copy=True +    ) +    int_matrix_rowmajor = np.array(int_matrix_colmajor, order="C", copy=True) +    dbl_matrix_rowmajor = np.array( +        int_matrix_rowmajor, dtype="double", order="C", copy=True +    )      # All should be callable via get_elem:      assert m.get_elem(int_matrix_colmajor) == 8 @@ -545,32 +596,38 @@ def test_nocopy_wrapper():      # All but the second should fail with m.get_elem_nocopy:      with pytest.raises(TypeError) as excinfo:          m.get_elem_nocopy(int_matrix_colmajor) -    assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and -            ', flags.f_contiguous' in str(excinfo.value)) +    assert "get_elem_nocopy(): incompatible function arguments." in str( +        excinfo.value +    ) and ", flags.f_contiguous" in str(excinfo.value)      assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8      with pytest.raises(TypeError) as excinfo:          m.get_elem_nocopy(int_matrix_rowmajor) -    assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and -            ', flags.f_contiguous' in str(excinfo.value)) +    assert "get_elem_nocopy(): incompatible function arguments." in str( +        excinfo.value +    ) and ", flags.f_contiguous" in str(excinfo.value)      with pytest.raises(TypeError) as excinfo:          m.get_elem_nocopy(dbl_matrix_rowmajor) -    assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and -            ', flags.f_contiguous' in str(excinfo.value)) +    assert "get_elem_nocopy(): incompatible function arguments." in str( +        excinfo.value +    ) and ", flags.f_contiguous" in str(excinfo.value)      # For the row-major test, we take a long matrix in row-major, so only the third is allowed:      with pytest.raises(TypeError) as excinfo:          m.get_elem_rm_nocopy(int_matrix_colmajor) -    assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and -            ', flags.c_contiguous' in str(excinfo.value)) +    assert "get_elem_rm_nocopy(): incompatible function arguments." in str( +        excinfo.value +    ) and ", flags.c_contiguous" in str(excinfo.value)      with pytest.raises(TypeError) as excinfo:          m.get_elem_rm_nocopy(dbl_matrix_colmajor) -    assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and -            ', flags.c_contiguous' in str(excinfo.value)) +    assert "get_elem_rm_nocopy(): incompatible function arguments." in str( +        excinfo.value +    ) and ", flags.c_contiguous" in str(excinfo.value)      assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8      with pytest.raises(TypeError) as excinfo:          m.get_elem_rm_nocopy(dbl_matrix_rowmajor) -    assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and -            ', flags.c_contiguous' in str(excinfo.value)) +    assert "get_elem_rm_nocopy(): incompatible function arguments." in str( +        excinfo.value +    ) and ", flags.c_contiguous" in str(excinfo.value)  def test_eigen_ref_life_support(): @@ -588,12 +645,9 @@ def test_eigen_ref_life_support():  def test_special_matrix_objects(): -    assert np.all(m.incr_diag(7) == np.diag([1., 2, 3, 4, 5, 6, 7])) +    assert np.all(m.incr_diag(7) == np.diag([1.0, 2, 3, 4, 5, 6, 7])) -    asymm = np.array([[ 1.,  2,  3,  4], -                      [ 5,  6,  7,  8], -                      [ 9, 10, 11, 12], -                      [13, 14, 15, 16]]) +    asymm = np.array([[1.0, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])      symm_lower = np.array(asymm)      symm_upper = np.array(asymm)      for i in range(4): @@ -606,43 +660,55 @@ def test_special_matrix_objects():  def test_dense_signature(doc): -    assert doc(m.double_col) == """ -        double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]] +    assert ( +        doc(m.double_col) +        == """ +        double_col(arg0: numpy.ndarray[numpy.float32[m, 1]]) -> numpy.ndarray[numpy.float32[m, 1]]      """ -    assert doc(m.double_row) == """ -        double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]] +    ) +    assert ( +        doc(m.double_row) +        == """ +        double_row(arg0: numpy.ndarray[numpy.float32[1, n]]) -> numpy.ndarray[numpy.float32[1, n]]      """ -    assert doc(m.double_complex) == """ -        double_complex(arg0: numpy.ndarray[complex64[m, 1]]) -> numpy.ndarray[complex64[m, 1]] +    ) +    assert doc(m.double_complex) == ( +        """ +        double_complex(arg0: numpy.ndarray[numpy.complex64[m, 1]])""" +        """ -> numpy.ndarray[numpy.complex64[m, 1]]      """ -    assert doc(m.double_mat_rm) == """ -        double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]] +    ) +    assert doc(m.double_mat_rm) == ( +        """ +        double_mat_rm(arg0: numpy.ndarray[numpy.float32[m, n]])""" +        """ -> numpy.ndarray[numpy.float32[m, n]]      """ +    )  def test_named_arguments():      a = np.array([[1.0, 2], [3, 4], [5, 6]])      b = np.ones((2, 1)) -    assert np.all(m.matrix_multiply(a, b) == np.array([[3.], [7], [11]])) -    assert np.all(m.matrix_multiply(A=a, B=b) == np.array([[3.], [7], [11]])) -    assert np.all(m.matrix_multiply(B=b, A=a) == np.array([[3.], [7], [11]])) +    assert np.all(m.matrix_multiply(a, b) == np.array([[3.0], [7], [11]])) +    assert np.all(m.matrix_multiply(A=a, B=b) == np.array([[3.0], [7], [11]])) +    assert np.all(m.matrix_multiply(B=b, A=a) == np.array([[3.0], [7], [11]]))      with pytest.raises(ValueError) as excinfo:          m.matrix_multiply(b, a) -    assert str(excinfo.value) == 'Nonconformable matrices!' +    assert str(excinfo.value) == "Nonconformable matrices!"      with pytest.raises(ValueError) as excinfo:          m.matrix_multiply(A=b, B=a) -    assert str(excinfo.value) == 'Nonconformable matrices!' +    assert str(excinfo.value) == "Nonconformable matrices!"      with pytest.raises(ValueError) as excinfo:          m.matrix_multiply(B=a, A=b) -    assert str(excinfo.value) == 'Nonconformable matrices!' +    assert str(excinfo.value) == "Nonconformable matrices!" -@pytest.requires_eigen_and_scipy  def test_sparse(): +    pytest.importorskip("scipy")      assert_sparse_equal_ref(m.sparse_r())      assert_sparse_equal_ref(m.sparse_c())      assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_r())) @@ -651,23 +717,33 @@ def test_sparse():      assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_r())) -@pytest.requires_eigen_and_scipy  def test_sparse_signature(doc): -    assert doc(m.sparse_copy_r) == """ -        sparse_copy_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32] +    pytest.importorskip("scipy") +    assert ( +        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[float32]) -> scipy.sparse.csc_matrix[float32] +    ) +    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 +    )  def test_issue738():      """Ignore strides on a length-1 dimension (even if they would be incompatible length > 1)""" -    assert np.all(m.iss738_f1(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]])) -    assert np.all(m.iss738_f1(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]])) - -    assert np.all(m.iss738_f2(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]])) -    assert np.all(m.iss738_f2(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]])) +    assert np.all(m.iss738_f1(np.array([[1.0, 2, 3]])) == np.array([[1.0, 102, 203]])) +    assert np.all( +        m.iss738_f1(np.array([[1.0], [2], [3]])) == np.array([[1.0], [12], [23]]) +    ) + +    assert np.all(m.iss738_f2(np.array([[1.0, 2, 3]])) == np.array([[1.0, 102, 203]])) +    assert np.all( +        m.iss738_f2(np.array([[1.0], [2], [3]])) == np.array([[1.0], [12], [23]]) +    )  def test_issue1105(): diff --git a/3rdparty/pybind11/tests/test_embed/CMakeLists.txt b/3rdparty/pybind11/tests/test_embed/CMakeLists.txt index 8b4f1f84..fabcb24e 100644 --- a/3rdparty/pybind11/tests/test_embed/CMakeLists.txt +++ b/3rdparty/pybind11/tests/test_embed/CMakeLists.txt @@ -1,41 +1,43 @@ -if(${PYTHON_MODULE_EXTENSION} MATCHES "pypy") -  add_custom_target(cpptest)  # Dummy target on PyPy. Embedding is not supported. +if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy") +  add_custom_target(cpptest) # Dummy target on PyPy. Embedding is not supported.    set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}")    return()  endif() -find_package(Catch 1.9.3) +find_package(Catch 2.13.2) +  if(CATCH_FOUND)    message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}")  else()    message(STATUS "Catch not detected. Interpreter tests will be skipped. Install Catch headers" -                 " manually or use `cmake -DDOWNLOAD_CATCH=1` to fetch them automatically.") +                 " manually or use `cmake -DDOWNLOAD_CATCH=ON` to fetch them automatically.")    return()  endif() -add_executable(test_embed -  catch.cpp -  test_interpreter.cpp -) -target_include_directories(test_embed PRIVATE ${CATCH_INCLUDE_DIR}) +find_package(Threads REQUIRED) + +add_executable(test_embed catch.cpp test_interpreter.cpp)  pybind11_enable_warnings(test_embed) -if(NOT CMAKE_VERSION VERSION_LESS 3.0) -  target_link_libraries(test_embed PRIVATE pybind11::embed) -else() -  target_include_directories(test_embed PRIVATE ${PYBIND11_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS}) -  target_compile_options(test_embed PRIVATE ${PYBIND11_CPP_STANDARD}) -  target_link_libraries(test_embed PRIVATE ${PYTHON_LIBRARIES}) -endif() +target_link_libraries(test_embed PRIVATE pybind11::embed Catch2::Catch2 Threads::Threads) -find_package(Threads REQUIRED) -target_link_libraries(test_embed PUBLIC ${CMAKE_THREAD_LIBS_INIT}) +if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) +  file(COPY test_interpreter.py DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") +endif() -add_custom_target(cpptest COMMAND $<TARGET_FILE:test_embed> -                  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +add_custom_target( +  cpptest +  COMMAND "$<TARGET_FILE:test_embed>" +  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")  pybind11_add_module(external_module THIN_LTO external_module.cpp) -set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY +                                                 "${CMAKE_CURRENT_BINARY_DIR}") +foreach(config ${CMAKE_CONFIGURATION_TYPES}) +  string(TOUPPER ${config} config) +  set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} +                                                   "${CMAKE_CURRENT_BINARY_DIR}") +endforeach()  add_dependencies(cpptest external_module)  add_dependencies(check cpptest) diff --git a/3rdparty/pybind11/tests/test_embed/test_interpreter.cpp b/3rdparty/pybind11/tests/test_embed/test_interpreter.cpp index 222bd565..944334ce 100644 --- a/3rdparty/pybind11/tests/test_embed/test_interpreter.cpp +++ b/3rdparty/pybind11/tests/test_embed/test_interpreter.cpp @@ -30,7 +30,7 @@ private:  class PyWidget final : public Widget {      using Widget::Widget; -    int the_answer() const override { PYBIND11_OVERLOAD_PURE(int, Widget, the_answer); } +    int the_answer() const override { PYBIND11_OVERRIDE_PURE(int, Widget, the_answer); }  };  PYBIND11_EMBEDDED_MODULE(widget_module, m) { @@ -51,17 +51,17 @@ PYBIND11_EMBEDDED_MODULE(throw_error_already_set, ) {  }  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 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);      REQUIRE(locals["message"].cast<std::string>() == "Hello, World! - 5"); -    auto py_widget = module.attr("DerivedWidget")("The question"); +    auto py_widget = module_.attr("DerivedWidget")("The question");      auto message = py_widget.attr("the_message");      REQUIRE(message.cast<std::string>() == "The question"); @@ -70,10 +70,10 @@ TEST_CASE("Pass classes and data between modules defined in C++ and Python") {  }  TEST_CASE("Import error handling") { -    REQUIRE_NOTHROW(py::module::import("widget_module")); -    REQUIRE_THROWS_WITH(py::module::import("throw_exception"), +    REQUIRE_NOTHROW(py::module_::import("widget_module")); +    REQUIRE_THROWS_WITH(py::module_::import("throw_exception"),                          "ImportError: C++ Error"); -    REQUIRE_THROWS_WITH(py::module::import("throw_error_already_set"), +    REQUIRE_THROWS_WITH(py::module_::import("throw_error_already_set"),                          Catch::Contains("ImportError: KeyError"));  } @@ -107,14 +107,14 @@ bool has_pybind11_internals_static() {  TEST_CASE("Restart the interpreter") {      // Verify pre-restart state. -    REQUIRE(py::module::import("widget_module").attr("add")(1, 2).cast<int>() == 3); +    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>()); +            py::module_::import("external_module").attr("internals_at")().cast<uintptr_t>());      // Restart the interpreter.      py::finalize_interpreter(); @@ -130,14 +130,14 @@ TEST_CASE("Restart the interpreter") {      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>()); +            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::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()); @@ -149,20 +149,20 @@ TEST_CASE("Restart the interpreter") {      REQUIRE_FALSE(has_pybind11_internals_static());      // C++ modules can be reloaded. -    auto cpp_module = py::module::import("widget_module"); +    auto cpp_module = py::module_::import("widget_module");      REQUIRE(cpp_module.attr("add")(1, 2).cast<int>() == 3);      // C++ type information is reloaded and can be used in python modules. -    auto py_module = py::module::import("test_interpreter"); +    auto py_module = py::module_::import("test_interpreter");      auto py_widget = py_module.attr("DerivedWidget")("Hello after restart");      REQUIRE(py_widget.attr("the_message").cast<std::string>() == "Hello after restart");  }  TEST_CASE("Subinterpreter") {      // Add tags to the modules in the main interpreter and test the basics. -    py::module::import("__main__").attr("main_tag") = "main interpreter"; +    py::module_::import("__main__").attr("main_tag") = "main interpreter";      { -        auto m = py::module::import("widget_module"); +        auto m = py::module_::import("widget_module");          m.attr("extension_module_tag") = "added to module in main interpreter";          REQUIRE(m.attr("add")(1, 2).cast<int>() == 3); @@ -181,9 +181,9 @@ TEST_CASE("Subinterpreter") {      REQUIRE(has_pybind11_internals_static());      // Modules tags should be gone. -    REQUIRE_FALSE(py::hasattr(py::module::import("__main__"), "tag")); +    REQUIRE_FALSE(py::hasattr(py::module_::import("__main__"), "tag"));      { -        auto m = py::module::import("widget_module"); +        auto m = py::module_::import("widget_module");          REQUIRE_FALSE(py::hasattr(m, "extension_module_tag"));          // Function bindings should still work. @@ -194,8 +194,8 @@ TEST_CASE("Subinterpreter") {      Py_EndInterpreter(sub_tstate);      PyThreadState_Swap(main_tstate); -    REQUIRE(py::hasattr(py::module::import("__main__"), "main_tag")); -    REQUIRE(py::hasattr(py::module::import("widget_module"), "extension_module_tag")); +    REQUIRE(py::hasattr(py::module_::import("__main__"), "main_tag")); +    REQUIRE(py::hasattr(py::module_::import("widget_module"), "extension_module_tag"));  }  TEST_CASE("Execution frame") { @@ -245,7 +245,7 @@ TEST_CASE("Reload module from file") {      // Disable generation of cached bytecode (.pyc files) for this test, otherwise      // Python might pick up an old version from the cache instead of the new versions      // of the .py files generated below -    auto sys = py::module::import("sys"); +    auto sys = py::module_::import("sys");      bool dont_write_bytecode = sys.attr("dont_write_bytecode").cast<bool>();      sys.attr("dont_write_bytecode") = true;      // Reset the value at scope exit @@ -267,8 +267,8 @@ TEST_CASE("Reload module from file") {      });      // Import the module from file -    auto module = py::module::import(module_name.c_str()); -    int result = module.attr("test")().cast<int>(); +    auto module_ = py::module_::import(module_name.c_str()); +    int result = module_.attr("test")().cast<int>();      REQUIRE(result == 1);      // Update the module .py file with a small change @@ -278,7 +278,7 @@ TEST_CASE("Reload module from file") {      test_module.close();      // Reload the module -    module.reload(); -    result = module.attr("test")().cast<int>(); +    module_.reload(); +    result = module_.attr("test")().cast<int>();      REQUIRE(result == 2);  } diff --git a/3rdparty/pybind11/tests/test_embed/test_interpreter.py b/3rdparty/pybind11/tests/test_embed/test_interpreter.py index 26a04792..6174ede4 100644 --- a/3rdparty/pybind11/tests/test_embed/test_interpreter.py +++ b/3rdparty/pybind11/tests/test_embed/test_interpreter.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*-  from widget_module import Widget diff --git a/3rdparty/pybind11/tests/test_enum.py b/3rdparty/pybind11/tests/test_enum.py index 7fe9b618..f6b24fc2 100644 --- a/3rdparty/pybind11/tests/test_enum.py +++ b/3rdparty/pybind11/tests/test_enum.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*-  import pytest  from pybind11_tests import enums as m @@ -6,6 +7,9 @@ def test_unscoped_enum():      assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne"      assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"      assert str(m.EOne) == "UnscopedEnum.EOne" +    assert repr(m.UnscopedEnum.EOne) == "<UnscopedEnum.EOne: 1>" +    assert repr(m.UnscopedEnum.ETwo) == "<UnscopedEnum.ETwo: 2>" +    assert repr(m.EOne) == "<UnscopedEnum.EOne: 1>"      # name property      assert m.UnscopedEnum.EOne.name == "EOne" @@ -20,18 +24,24 @@ def test_unscoped_enum():      assert m.UnscopedEnum.EOne.name == "EOne"      # __members__ property -    assert m.UnscopedEnum.__members__ == \ -        {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo, "EThree": m.UnscopedEnum.EThree} +    assert m.UnscopedEnum.__members__ == { +        "EOne": m.UnscopedEnum.EOne, +        "ETwo": m.UnscopedEnum.ETwo, +        "EThree": m.UnscopedEnum.EThree, +    }      # __members__ readonly      with pytest.raises(AttributeError):          m.UnscopedEnum.__members__ = {}      # __members__ returns a copy      foo = m.UnscopedEnum.__members__      foo["bar"] = "baz" -    assert m.UnscopedEnum.__members__ == \ -        {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo, "EThree": m.UnscopedEnum.EThree} +    assert m.UnscopedEnum.__members__ == { +        "EOne": m.UnscopedEnum.EOne, +        "ETwo": m.UnscopedEnum.ETwo, +        "EThree": m.UnscopedEnum.EThree, +    } -    for docstring_line in '''An unscoped enumeration +    for docstring_line in """An unscoped enumeration  Members: @@ -39,7 +49,9 @@ Members:    ETwo : Docstring for ETwo -  EThree : Docstring for EThree'''.split('\n'): +  EThree : Docstring for EThree""".split( +        "\n" +    ):          assert docstring_line in m.UnscopedEnum.__doc__      # Unscoped enums will accept ==/!= int comparisons @@ -49,10 +61,10 @@ Members:      assert y != 3      assert 3 != y      # Compare with None -    assert (y != None)  # noqa: E711 +    assert y != None  # noqa: E711      assert not (y == None)  # noqa: E711      # Compare with an object -    assert (y != object()) +    assert y != object()      assert not (y == object())      # Compare with string      assert y != "2" @@ -115,10 +127,10 @@ def test_scoped_enum():      assert z != 3      assert 3 != z      # Compare with None -    assert (z != None)  # noqa: E711 +    assert z != None  # noqa: E711      assert not (z == None)  # noqa: E711      # Compare with an object -    assert (z != object()) +    assert z != object()      assert not (z == object())      # Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions)      with pytest.raises(TypeError): @@ -142,6 +154,8 @@ def test_scoped_enum():  def test_implicit_conversion():      assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"      assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode" +    assert repr(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "<EMode.EFirstMode: 1>" +    assert repr(m.ClassWithUnscopedEnum.EFirstMode) == "<EMode.EFirstMode: 1>"      f = m.ClassWithUnscopedEnum.test_function      first = m.ClassWithUnscopedEnum.EFirstMode @@ -166,7 +180,7 @@ def test_implicit_conversion():      x[f(first)] = 3      x[f(second)] = 4      # Hashing test -    assert str(x) == "{EMode.EFirstMode: 3, EMode.ESecondMode: 4}" +    assert repr(x) == "{<EMode.EFirstMode: 1>: 3, <EMode.ESecondMode: 2>: 4}"  def test_binary_operators(): @@ -204,3 +218,10 @@ def test_duplicate_enum_name():      with pytest.raises(ValueError) as excinfo:          m.register_bad_enum()      assert str(excinfo.value) == 'SimpleEnum: element "ONE" already exists!' + + +def test_docstring_signatures(): +    for enum_type in [m.ScopedEnum, m.UnscopedEnum]: +        for attr in enum_type.__dict__.values(): +            # Issue #2623/PR #2637: Add argument names to enum_ methods +            assert "arg0" not in (attr.__doc__ or "") diff --git a/3rdparty/pybind11/tests/test_eval.cpp b/3rdparty/pybind11/tests/test_eval.cpp index e0948219..5416c2ec 100644 --- a/3rdparty/pybind11/tests/test_eval.cpp +++ b/3rdparty/pybind11/tests/test_eval.cpp @@ -14,7 +14,7 @@  TEST_SUBMODULE(eval_, m) {      // test_evals -    auto global = py::dict(py::module::import("__main__").attr("__dict__")); +    auto global = py::dict(py::module_::import("__main__").attr("__dict__"));      m.def("test_eval_statements", [global]() {          auto local = py::dict(); @@ -88,4 +88,12 @@ TEST_SUBMODULE(eval_, m) {          }          return false;      }); + +    // test_eval_empty_globals +    m.def("eval_empty_globals", [](py::object global) { +        if (global.is_none()) +            global = py::dict(); +        auto int_class = py::eval("isinstance(42, int)", global); +        return global; +    });  } diff --git a/3rdparty/pybind11/tests/test_eval.py b/3rdparty/pybind11/tests/test_eval.py index bda4ef6b..1bb05af0 100644 --- a/3rdparty/pybind11/tests/test_eval.py +++ b/3rdparty/pybind11/tests/test_eval.py @@ -1,4 +1,10 @@ +# -*- coding: utf-8 -*-  import os + +import pytest + +import env  # noqa: F401 +  from pybind11_tests import eval_ as m @@ -10,8 +16,20 @@ def test_evals(capture):      assert m.test_eval()      assert m.test_eval_single_statement() +    assert m.test_eval_failure() + + +@pytest.mark.xfail("env.PYPY and not env.PY2", raises=RuntimeError) +def test_eval_file():      filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")      assert m.test_eval_file(filename) -    assert m.test_eval_failure()      assert m.test_eval_file_failure() + + +def test_eval_empty_globals(): +    assert "__builtins__" in m.eval_empty_globals(None) + +    g = {} +    assert "__builtins__" in m.eval_empty_globals(g) +    assert "__builtins__" in g diff --git a/3rdparty/pybind11/tests/test_eval_call.py b/3rdparty/pybind11/tests/test_eval_call.py index 53c7e721..373b67ba 100644 --- a/3rdparty/pybind11/tests/test_eval_call.py +++ b/3rdparty/pybind11/tests/test_eval_call.py @@ -1,4 +1,5 @@ +# -*- coding: utf-8 -*-  # This file is called from 'test_eval.py' -if 'call_test2' in locals(): +if "call_test2" in locals():      call_test2(y)  # noqa: F821 undefined name diff --git a/3rdparty/pybind11/tests/test_exceptions.cpp b/3rdparty/pybind11/tests/test_exceptions.cpp index 56cd9bc4..e27c16df 100644 --- a/3rdparty/pybind11/tests/test_exceptions.cpp +++ b/3rdparty/pybind11/tests/test_exceptions.cpp @@ -13,7 +13,7 @@  class MyException : public std::exception {  public:      explicit MyException(const char * m) : message{m} {} -    virtual const char * what() const noexcept override {return message.c_str();} +    const char * what() const noexcept override {return message.c_str();}  private:      std::string message = "";  }; @@ -22,7 +22,7 @@ private:  class MyException2 : public std::exception {  public:      explicit MyException2(const char * m) : message{m} {} -    virtual const char * what() const noexcept override {return message.c_str();} +    const char * what() const noexcept override {return message.c_str();}  private:      std::string message = "";  }; @@ -32,6 +32,13 @@ class MyException3 {  public:      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; +    virtual ~MyException3() = default; +    // Rule of 5 END.  private:      std::string message = "";  }; @@ -41,7 +48,7 @@ private:  class MyException4 : public std::exception {  public:      explicit MyException4(const char * m) : message{m} {} -    virtual const char * what() const noexcept override {return message.c_str();} +    const char * what() const noexcept override {return message.c_str();}  private:      std::string message = "";  }; @@ -65,6 +72,25 @@ struct PythonCallInDestructor {      py::dict d;  }; + + +struct PythonAlreadySetInDestructor { +    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) { +            ex.discard_as_unraisable(s); +        } +    } + +    py::str s; +}; + +  TEST_SUBMODULE(exceptions, m) {      m.def("throw_std_exception", []() {          throw std::runtime_error("This exception was intentionally thrown."); @@ -144,7 +170,7 @@ TEST_SUBMODULE(exceptions, m) {      m.def("modulenotfound_exception_matches_base", []() {          try {              // On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError -            py::module::import("nonexistent"); +            py::module_::import("nonexistent");          }          catch (py::error_already_set &ex) {              if (!ex.matches(PyExc_ImportError)) throw; @@ -183,6 +209,11 @@ TEST_SUBMODULE(exceptions, m) {          return false;      }); +    m.def("python_alreadyset_in_destructor", [](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); } @@ -194,4 +225,7 @@ TEST_SUBMODULE(exceptions, m) {          }      }); +    // Test repr that cannot be displayed +    m.def("simple_bool_passthrough", [](bool x) {return x;}); +  } diff --git a/3rdparty/pybind11/tests/test_exceptions.py b/3rdparty/pybind11/tests/test_exceptions.py index ac2b3603..95eac709 100644 --- a/3rdparty/pybind11/tests/test_exceptions.py +++ b/3rdparty/pybind11/tests/test_exceptions.py @@ -1,3 +1,6 @@ +# -*- coding: utf-8 -*- +import sys +  import pytest  from pybind11_tests import exceptions as m @@ -47,6 +50,33 @@ def test_python_call_in_catch():      assert d["good"] is True +def test_python_alreadyset_in_destructor(monkeypatch, capsys): +    hooked = False +    triggered = [False]  # mutable, so Python 2.7 closure can modify it + +    if hasattr(sys, "unraisablehook"):  # Python 3.8+ +        hooked = True +        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 +            default_hook(unraisable_hook_args) +            return + +        # Use monkeypatch so pytest can apply and remove the patch as appropriate +        monkeypatch.setattr(sys, "unraisablehook", hook) + +    assert m.python_alreadyset_in_destructor("already_set demo") is True +    if hooked: +        assert triggered[0] 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 + +  def test_exception_matches():      assert m.exception_matches()      assert m.exception_matches_base() @@ -77,7 +107,9 @@ def test_custom(msg):      # Can we fall-through to the default handler?      with pytest.raises(RuntimeError) as excinfo:          m.throws_logic_error() -    assert msg(excinfo.value) == "this error should fall through to the standard handler" +    assert ( +        msg(excinfo.value) == "this error should fall through to the standard handler" +    )      # OverFlow error translation.      with pytest.raises(OverflowError) as excinfo: @@ -136,7 +168,13 @@ def test_nested_throws(capture):      # C++ -> Python -> C++ -> Python      with capture:          m.try_catch( -            m.MyException5, pycatch, m.MyException, m.try_catch, m.MyException, throw_myex5) +            m.MyException5, +            pycatch, +            m.MyException, +            m.try_catch, +            m.MyException, +            throw_myex5, +        )      assert str(capture).startswith("MyException5: nested error 5")      # C++ -> Python -> C++ @@ -148,3 +186,13 @@ def test_nested_throws(capture):      with pytest.raises(m.MyException5) as excinfo:          m.try_catch(m.MyException, pycatch, m.MyException, m.throws5)      assert str(excinfo.value) == "this is a helper-defined translated exception" + + +# This can often happen if you wrap a pybind11 class in a Python wrapper +def test_invalid_repr(): +    class MyRepr(object): +        def __repr__(self): +            raise AttributeError("Example error") + +    with pytest.raises(TypeError): +        m.simple_bool_passthrough(MyRepr()) diff --git a/3rdparty/pybind11/tests/test_factory_constructors.cpp b/3rdparty/pybind11/tests/test_factory_constructors.cpp index 5cfbfdc3..f42d1f29 100644 --- a/3rdparty/pybind11/tests/test_factory_constructors.cpp +++ b/3rdparty/pybind11/tests/test_factory_constructors.cpp @@ -11,6 +11,7 @@  #include "pybind11_tests.h"  #include "constructor_stats.h"  #include <cmath> +#include <new>  // Classes for testing python construction via C++ factory function:  // Not publicly constructible, copyable, or movable: @@ -57,13 +58,13 @@ class TestFactory4 : public TestFactory3 {  public:      TestFactory4() : TestFactory3() { print_default_created(this); }      TestFactory4(int v) : TestFactory3(v) { print_created(this, v); } -    virtual ~TestFactory4() { print_destroyed(this); } +    ~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); } -    virtual ~TestFactory5() { print_destroyed(this); } +    ~TestFactory5() override { print_destroyed(this); }  };  class TestFactory6 { @@ -87,8 +88,8 @@ public:      PyTF6(PyTF6 &&f) : TestFactory6(std::move(f)) { print_move_created(this); }      PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); }      PyTF6(std::string s) : TestFactory6((int) s.size()) { alias = true; print_created(this, s); } -    virtual ~PyTF6() { print_destroyed(this); } -    int get() override { PYBIND11_OVERLOAD(int, TestFactory6, get, /*no args*/); } +    ~PyTF6() override { print_destroyed(this); } +    int get() override { PYBIND11_OVERRIDE(int, TestFactory6, get, /*no args*/); }  };  class TestFactory7 { @@ -108,8 +109,8 @@ public:      PyTF7(int i) : TestFactory7(i) { alias = true; print_created(this, i); }      PyTF7(PyTF7 &&f) : TestFactory7(std::move(f)) { print_move_created(this); }      PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); } -    virtual ~PyTF7() { print_destroyed(this); } -    int get() override { PYBIND11_OVERLOAD(int, TestFactory7, get, /*no args*/); } +    ~PyTF7() override { print_destroyed(this); } +    int get() override { PYBIND11_OVERRIDE(int, TestFactory7, get, /*no args*/); }  }; @@ -141,7 +142,7 @@ public:  TEST_SUBMODULE(factory_constructors, m) {      // Define various trivial types to allow simpler overload resolution: -    py::module m_tag = m.def_submodule("tag"); +    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<>()); \ @@ -154,6 +155,8 @@ TEST_SUBMODULE(factory_constructors, m) {      MAKE_TAG_TYPE(TF4);      MAKE_TAG_TYPE(TF5);      MAKE_TAG_TYPE(null_ptr); +    MAKE_TAG_TYPE(null_unique_ptr); +    MAKE_TAG_TYPE(null_shared_ptr);      MAKE_TAG_TYPE(base);      MAKE_TAG_TYPE(invalid_base);      MAKE_TAG_TYPE(alias); @@ -194,6 +197,8 @@ TEST_SUBMODULE(factory_constructors, m) {          // 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)          ; diff --git a/3rdparty/pybind11/tests/test_factory_constructors.py b/3rdparty/pybind11/tests/test_factory_constructors.py index 78a3910a..ffcce6fd 100644 --- a/3rdparty/pybind11/tests/test_factory_constructors.py +++ b/3rdparty/pybind11/tests/test_factory_constructors.py @@ -1,6 +1,9 @@ +# -*- coding: utf-8 -*-  import pytest  import re +import env  # noqa: F401 +  from pybind11_tests import factory_constructors as m  from pybind11_tests.factory_constructors import tag  from pybind11_tests import ConstructorStats @@ -9,7 +12,10 @@ from pybind11_tests import ConstructorStats  def test_init_factory_basic():      """Tests py::init_factory() wrapper around various ways of returning the object""" -    cstats = [ConstructorStats.get(c) for c in [m.TestFactory1, m.TestFactory2, m.TestFactory3]] +    cstats = [ +        ConstructorStats.get(c) +        for c in [m.TestFactory1, m.TestFactory2, m.TestFactory3] +    ]      cstats[0].alive()  # force gc      n_inst = ConstructorStats.detail_reg_inst() @@ -38,9 +44,12 @@ def test_init_factory_basic():      z3 = m.TestFactory3("bye")      assert z3.value == "bye" -    with pytest.raises(TypeError) as excinfo: -        m.TestFactory3(tag.null_ptr) -    assert str(excinfo.value) == "pybind11::init(): factory function returned nullptr" +    for null_ptr_kind in [tag.null_ptr, tag.null_unique_ptr, tag.null_shared_ptr]: +        with pytest.raises(TypeError) as excinfo: +            m.TestFactory3(null_ptr_kind) +        assert ( +            str(excinfo.value) == "pybind11::init(): factory function returned nullptr" +        )      assert [i.alive() for i in cstats] == [3, 3, 3]      assert ConstructorStats.detail_reg_inst() == n_inst + 9 @@ -55,7 +64,7 @@ def test_init_factory_basic():      assert [i.values() for i in cstats] == [          ["3", "hi!"],          ["7", "hi again"], -        ["42", "bye"] +        ["42", "bye"],      ]      assert [i.default_constructions for i in cstats] == [1, 1, 1] @@ -63,7 +72,9 @@ def test_init_factory_basic():  def test_init_factory_signature(msg):      with pytest.raises(TypeError) as excinfo:          m.TestFactory1("invalid", "constructor", "arguments") -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          __init__(): incompatible constructor arguments. The following argument types are supported:              1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int)              2. m.factory_constructors.TestFactory1(arg0: str) @@ -72,8 +83,11 @@ def test_init_factory_signature(msg):          Invoked with: 'invalid', 'constructor', 'arguments'      """  # noqa: E501 line too long +    ) -    assert msg(m.TestFactory1.__init__.__doc__) == """ +    assert ( +        msg(m.TestFactory1.__init__.__doc__) +        == """          __init__(*args, **kwargs)          Overloaded function. @@ -85,12 +99,16 @@ def test_init_factory_signature(msg):          4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None      """  # noqa: E501 line too long +    )  def test_init_factory_casting():      """Tests py::init_factory() wrapper with various upcasting and downcasting returns""" -    cstats = [ConstructorStats.get(c) for c in [m.TestFactory3, m.TestFactory4, m.TestFactory5]] +    cstats = [ +        ConstructorStats.get(c) +        for c in [m.TestFactory3, m.TestFactory4, m.TestFactory5] +    ]      cstats[0].alive()  # force gc      n_inst = ConstructorStats.detail_reg_inst() @@ -128,7 +146,7 @@ def test_init_factory_casting():      assert [i.values() for i in cstats] == [          ["4", "5", "6", "7", "8"],          ["4", "5", "8"], -        ["6", "7"] +        ["6", "7"],      ] @@ -198,7 +216,7 @@ def test_init_factory_alias():      assert [i.values() for i in cstats] == [          ["1", "8", "3", "4", "5", "6", "123", "10", "47"], -        ["hi there", "3", "4", "6", "move", "123", "why hello!", "move", "47"] +        ["hi there", "3", "4", "6", "move", "123", "why hello!", "move", "47"],      ] @@ -262,9 +280,11 @@ def test_init_factory_dual():      assert not g1.has_alias()      with pytest.raises(TypeError) as excinfo:          PythFactory7(tag.shared_ptr, tag.invalid_base, 14) -    assert (str(excinfo.value) == -            "pybind11::init(): construction failed: returned holder-wrapped instance is not an " -            "alias instance") +    assert ( +        str(excinfo.value) +        == "pybind11::init(): construction failed: returned holder-wrapped instance is not an " +        "alias instance" +    )      assert [i.alive() for i in cstats] == [13, 7]      assert ConstructorStats.detail_reg_inst() == n_inst + 13 @@ -278,7 +298,7 @@ def test_init_factory_dual():      assert [i.values() for i in cstats] == [          ["1", "2", "3", "4", "5", "6", "7", "8", "9", "100", "11", "12", "13", "14"], -        ["2", "4", "6", "8", "9", "100", "12"] +        ["2", "4", "6", "8", "9", "100", "12"],      ] @@ -288,7 +308,7 @@ def test_no_placement_new(capture):      with capture:          a = m.NoPlacementNew(123) -    found = re.search(r'^operator new called, returning (\d+)\n$', str(capture)) +    found = re.search(r"^operator new called, returning (\d+)\n$", str(capture))      assert found      assert a.i == 123      with capture: @@ -299,7 +319,7 @@ def test_no_placement_new(capture):      with capture:          b = m.NoPlacementNew() -    found = re.search(r'^operator new called, returning (\d+)\n$', str(capture)) +    found = re.search(r"^operator new called, returning (\d+)\n$", str(capture))      assert found      assert b.i == 100      with capture: @@ -327,19 +347,21 @@ def create_and_destroy(*args):  def strip_comments(s): -    return re.sub(r'\s+#.*', '', s) +    return re.sub(r"\s+#.*", "", s) -def test_reallocations(capture, msg): +def test_reallocation_a(capture, msg):      """When the constructor is overloaded, previous overloads can require a preallocated value.      This test makes sure that such preallocated values only happen when they might be necessary, -    and that they are deallocated properly""" +    and that they are deallocated properly."""      pytest.gc_collect()      with capture:          create_and_destroy(1) -    assert msg(capture) == """ +    assert ( +        msg(capture) +        == """          noisy new          noisy placement new          NoisyAlloc(int 1) @@ -347,9 +369,14 @@ def test_reallocations(capture, msg):          ~NoisyAlloc()          noisy delete      """ +    ) + + +def test_reallocation_b(capture, msg):      with capture:          create_and_destroy(1.5) -    assert msg(capture) == strip_comments(""" +    assert msg(capture) == strip_comments( +        """          noisy new               # allocation required to attempt first overload          noisy delete            # have to dealloc before considering factory init overload          noisy new               # pointer factory calling "new", part 1: allocation @@ -357,43 +384,59 @@ def test_reallocations(capture, msg):          ---          ~NoisyAlloc()  # Destructor          noisy delete   # operator delete -    """) +    """ +    ) + +def test_reallocation_c(capture, msg):      with capture:          create_and_destroy(2, 3) -    assert msg(capture) == strip_comments(""" +    assert msg(capture) == strip_comments( +        """          noisy new          # pointer factory calling "new", allocation          NoisyAlloc(int 2)  # constructor          ---          ~NoisyAlloc()  # Destructor          noisy delete   # operator delete -    """) +    """ +    ) + +def test_reallocation_d(capture, msg):      with capture:          create_and_destroy(2.5, 3) -    assert msg(capture) == strip_comments(""" +    assert msg(capture) == strip_comments( +        """          NoisyAlloc(double 2.5)  # construction (local func variable: operator_new not called)          noisy new               # return-by-value "new" part 1: allocation          ~NoisyAlloc()           # moved-away local func variable destruction          ---          ~NoisyAlloc()  # Destructor          noisy delete   # operator delete -    """) +    """ +    ) + +def test_reallocation_e(capture, msg):      with capture:          create_and_destroy(3.5, 4.5) -    assert msg(capture) == strip_comments(""" +    assert msg(capture) == strip_comments( +        """          noisy new               # preallocation needed before invoking placement-new overload          noisy placement new     # Placement new          NoisyAlloc(double 3.5)  # construction          ---          ~NoisyAlloc()  # Destructor          noisy delete   # operator delete -    """) +    """ +    ) + +def test_reallocation_f(capture, msg):      with capture:          create_and_destroy(4, 0.5) -    assert msg(capture) == strip_comments(""" +    assert msg(capture) == strip_comments( +        """          noisy new          # preallocation needed before invoking placement-new overload          noisy delete       # deallocation of preallocated storage          noisy new          # Factory pointer allocation @@ -401,11 +444,15 @@ def test_reallocations(capture, msg):          ---          ~NoisyAlloc()  # Destructor          noisy delete   # operator delete -    """) +    """ +    ) + +def test_reallocation_g(capture, msg):      with capture:          create_and_destroy(5, "hi") -    assert msg(capture) == strip_comments(""" +    assert msg(capture) == strip_comments( +        """          noisy new            # preallocation needed before invoking first placement new          noisy delete         # delete before considering new-style constructor          noisy new            # preallocation for second placement new @@ -414,13 +461,15 @@ def test_reallocations(capture, msg):          ---          ~NoisyAlloc()  # Destructor          noisy delete   # operator delete -    """) +    """ +    ) -@pytest.unsupported_on_py2 +@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.""" +      class NotPybindDerived(object):          pass @@ -444,16 +493,26 @@ def test_invalid_self():                  a = m.TestFactory2(tag.pointer, 1)                  m.TestFactory6.__init__(a, tag.alias, 1)              elif bad == 3: -                m.TestFactory6.__init__(NotPybindDerived.__new__(NotPybindDerived), tag.base, 1) +                m.TestFactory6.__init__( +                    NotPybindDerived.__new__(NotPybindDerived), tag.base, 1 +                )              elif bad == 4: -                m.TestFactory6.__init__(NotPybindDerived.__new__(NotPybindDerived), tag.alias, 1) +                m.TestFactory6.__init__( +                    NotPybindDerived.__new__(NotPybindDerived), tag.alias, 1 +                )      for arg in (1, 2):          with pytest.raises(TypeError) as excinfo:              BrokenTF1(arg) -        assert str(excinfo.value) == "__init__(self, ...) called with invalid `self` argument" +        assert ( +            str(excinfo.value) +            == "__init__(self, ...) called with invalid `self` argument" +        )      for arg in (1, 2, 3, 4):          with pytest.raises(TypeError) as excinfo:              BrokenTF6(arg) -        assert str(excinfo.value) == "__init__(self, ...) called with invalid `self` argument" +        assert ( +            str(excinfo.value) +            == "__init__(self, ...) called with invalid `self` argument" +        ) diff --git a/3rdparty/pybind11/tests/test_gil_scoped.cpp b/3rdparty/pybind11/tests/test_gil_scoped.cpp index 76c17fdc..b6a45a5f 100644 --- a/3rdparty/pybind11/tests/test_gil_scoped.cpp +++ b/3rdparty/pybind11/tests/test_gil_scoped.cpp @@ -13,17 +13,19 @@  class VirtClass  {  public: -    virtual ~VirtClass() {} +    virtual ~VirtClass() = default; +    VirtClass() = default; +    VirtClass(const VirtClass&) = delete;      virtual void virtual_func() {}      virtual void pure_virtual_func() = 0;  };  class PyVirtClass : public VirtClass {      void virtual_func() override { -        PYBIND11_OVERLOAD(void, VirtClass, virtual_func,); +        PYBIND11_OVERRIDE(void, VirtClass, virtual_func,);      }      void pure_virtual_func() override { -        PYBIND11_OVERLOAD_PURE(void, VirtClass, pure_virtual_func,); +        PYBIND11_OVERRIDE_PURE(void, VirtClass, pure_virtual_func,);      }  }; @@ -43,7 +45,7 @@ TEST_SUBMODULE(gil_scoped, m) {            [](VirtClass &virt) { virt.pure_virtual_func(); });      m.def("test_cross_module_gil",            []() { -              auto cm = py::module::import("cross_module_gil_utils"); +              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; diff --git a/3rdparty/pybind11/tests/test_gil_scoped.py b/3rdparty/pybind11/tests/test_gil_scoped.py index 1548337c..0a1d6274 100644 --- a/3rdparty/pybind11/tests/test_gil_scoped.py +++ b/3rdparty/pybind11/tests/test_gil_scoped.py @@ -1,5 +1,7 @@ +# -*- coding: utf-8 -*-  import multiprocessing  import threading +  from pybind11_tests import gil_scoped as m @@ -19,6 +21,7 @@ def _run_in_process(target, *args, **kwargs):  def _python_to_cpp_to_python():      """Calls different C++ functions that come back to Python.""" +      class ExtendedVirtClass(m.VirtClass):          def virtual_func(self):              pass @@ -48,6 +51,7 @@ def _python_to_cpp_to_python_from_threads(num_threads, parallel=False):          thread.join() +# TODO: FIXME, sometimes returns -11 (segfault) instead of 0 on macOS Python 3.9  def test_python_to_cpp_to_python_from_thread():      """Makes sure there is no GIL deadlock when running in a thread. @@ -56,6 +60,7 @@ def test_python_to_cpp_to_python_from_thread():      assert _run_in_process(_python_to_cpp_to_python_from_threads, 1) == 0 +# TODO: FIXME on macOS Python 3.9  def test_python_to_cpp_to_python_from_thread_multiple_parallel():      """Makes sure there is no GIL deadlock when running in a thread multiple times in parallel. @@ -64,14 +69,18 @@ def test_python_to_cpp_to_python_from_thread_multiple_parallel():      assert _run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=True) == 0 +# TODO: FIXME on macOS Python 3.9  def test_python_to_cpp_to_python_from_thread_multiple_sequential():      """Makes sure there is no GIL deadlock when running in a thread multiple times sequentially.      It runs in a separate process to be able to stop and assert if it deadlocks.      """ -    assert _run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=False) == 0 +    assert ( +        _run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=False) == 0 +    ) +# TODO: FIXME on macOS Python 3.9  def test_python_to_cpp_to_python_from_process():      """Makes sure there is no GIL deadlock when using processes. diff --git a/3rdparty/pybind11/tests/test_iostream.cpp b/3rdparty/pybind11/tests/test_iostream.cpp index e67f88af..e9161505 100644 --- a/3rdparty/pybind11/tests/test_iostream.cpp +++ b/3rdparty/pybind11/tests/test_iostream.cpp @@ -37,7 +37,7 @@ TEST_SUBMODULE(iostream, m) {      });      m.def("captured_output", [](std::string msg) { -        py::scoped_ostream_redirect redir(std::cout, py::module::import("sys").attr("stdout")); +        py::scoped_ostream_redirect redir(std::cout, py::module_::import("sys").attr("stdout"));          std::cout << msg << std::flush;      }); @@ -46,7 +46,7 @@ TEST_SUBMODULE(iostream, m) {              py::arg("msg"), py::arg("flush")=true);      m.def("captured_err", [](std::string msg) { -        py::scoped_ostream_redirect redir(std::cerr, py::module::import("sys").attr("stderr")); +        py::scoped_ostream_redirect redir(std::cerr, py::module_::import("sys").attr("stderr"));          std::cerr << msg << std::flush;      }); @@ -65,8 +65,8 @@ TEST_SUBMODULE(iostream, m) {      });      m.def("captured_dual", [](std::string msg, std::string emsg) { -        py::scoped_ostream_redirect redirout(std::cout, py::module::import("sys").attr("stdout")); -        py::scoped_ostream_redirect redirerr(std::cerr, py::module::import("sys").attr("stderr")); +        py::scoped_ostream_redirect redirout(std::cout, py::module_::import("sys").attr("stdout")); +        py::scoped_ostream_redirect redirerr(std::cerr, py::module_::import("sys").attr("stderr"));          std::cout << msg << std::flush;          std::cerr << emsg << std::flush;      }); diff --git a/3rdparty/pybind11/tests/test_iostream.py b/3rdparty/pybind11/tests/test_iostream.py index 27095b27..506db42e 100644 --- a/3rdparty/pybind11/tests/test_iostream.py +++ b/3rdparty/pybind11/tests/test_iostream.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*-  from pybind11_tests import iostream as m  import sys @@ -17,6 +18,7 @@ try:      # Python 3.4      from contextlib import redirect_stdout  except ImportError: +      @contextmanager      def redirect_stdout(target):          original = sys.stdout @@ -24,10 +26,12 @@ except ImportError:          yield          sys.stdout = original +  try:      # Python 3.5      from contextlib import redirect_stderr  except ImportError: +      @contextmanager      def redirect_stderr(target):          original = sys.stderr @@ -41,16 +45,16 @@ def test_captured(capsys):      m.captured_output(msg)      stdout, stderr = capsys.readouterr()      assert stdout == msg -    assert stderr == '' +    assert stderr == ""      m.captured_output_default(msg)      stdout, stderr = capsys.readouterr()      assert stdout == msg -    assert stderr == '' +    assert stderr == ""      m.captured_err(msg)      stdout, stderr = capsys.readouterr() -    assert stdout == '' +    assert stdout == ""      assert stderr == msg @@ -62,7 +66,7 @@ def test_captured_large_string(capsys):      m.captured_output_default(msg)      stdout, stderr = capsys.readouterr()      assert stdout == msg -    assert stderr == '' +    assert stderr == ""  def test_guard_capture(capsys): @@ -70,7 +74,7 @@ def test_guard_capture(capsys):      m.guard_output(msg)      stdout, stderr = capsys.readouterr()      assert stdout == msg -    assert stderr == '' +    assert stderr == ""  def test_series_captured(capture): @@ -87,7 +91,7 @@ def test_flush(capfd):      with m.ostream_redirect():          m.noisy_function(msg, flush=False)          stdout, stderr = capfd.readouterr() -        assert stdout == '' +        assert stdout == ""          m.noisy_function(msg2, flush=True)          stdout, stderr = capfd.readouterr() @@ -106,15 +110,15 @@ def test_not_captured(capfd):          m.raw_output(msg)      stdout, stderr = capfd.readouterr()      assert stdout == msg -    assert stderr == '' -    assert stream.getvalue() == '' +    assert stderr == "" +    assert stream.getvalue() == ""      stream = StringIO()      with redirect_stdout(stream):          m.captured_output(msg)      stdout, stderr = capfd.readouterr() -    assert stdout == '' -    assert stderr == '' +    assert stdout == "" +    assert stderr == ""      assert stream.getvalue() == msg @@ -124,16 +128,16 @@ def test_err(capfd):      with redirect_stderr(stream):          m.raw_err(msg)      stdout, stderr = capfd.readouterr() -    assert stdout == '' +    assert stdout == ""      assert stderr == msg -    assert stream.getvalue() == '' +    assert stream.getvalue() == ""      stream = StringIO()      with redirect_stderr(stream):          m.captured_err(msg)      stdout, stderr = capfd.readouterr() -    assert stdout == '' -    assert stderr == '' +    assert stdout == "" +    assert stderr == ""      assert stream.getvalue() == msg @@ -145,8 +149,8 @@ def test_multi_captured(capfd):          m.captured_output("c")          m.raw_output("d")      stdout, stderr = capfd.readouterr() -    assert stdout == 'bd' -    assert stream.getvalue() == 'ac' +    assert stdout == "bd" +    assert stream.getvalue() == "ac"  def test_dual(capsys): @@ -163,14 +167,14 @@ def test_redirect(capfd):          m.raw_output(msg)      stdout, stderr = capfd.readouterr()      assert stdout == msg -    assert stream.getvalue() == '' +    assert stream.getvalue() == ""      stream = StringIO()      with redirect_stdout(stream):          with m.ostream_redirect():              m.raw_output(msg)      stdout, stderr = capfd.readouterr() -    assert stdout == '' +    assert stdout == ""      assert stream.getvalue() == msg      stream = StringIO() @@ -178,7 +182,7 @@ def test_redirect(capfd):          m.raw_output(msg)      stdout, stderr = capfd.readouterr()      assert stdout == msg -    assert stream.getvalue() == '' +    assert stream.getvalue() == ""  def test_redirect_err(capfd): @@ -192,7 +196,7 @@ def test_redirect_err(capfd):              m.raw_err(msg2)      stdout, stderr = capfd.readouterr()      assert stdout == msg -    assert stderr == '' +    assert stderr == ""      assert stream.getvalue() == msg2 @@ -208,7 +212,7 @@ def test_redirect_both(capfd):                  m.raw_output(msg)                  m.raw_err(msg2)      stdout, stderr = capfd.readouterr() -    assert stdout == '' -    assert stderr == '' +    assert stdout == "" +    assert stderr == ""      assert stream.getvalue() == msg      assert stream2.getvalue() == msg2 diff --git a/3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp b/3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp index 6563fb9a..627a7969 100644 --- a/3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp +++ b/3rdparty/pybind11/tests/test_kwargs_and_defaults.cpp @@ -71,7 +71,7 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {          py::tuple t(a.size());          for (size_t i = 0; i < a.size(); i++)              // Use raw Python API here to avoid an extra, intermediate incref on the tuple item: -            t[i] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast<ssize_t>(i))); +            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) { @@ -80,7 +80,7 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {          t[0] = o.ref_count();          for (size_t i = 0; i < a.size(); i++)              // Use raw Python API here to avoid an extra, intermediate incref on the tuple item: -            t[i + 1] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast<ssize_t>(i))); +            t[i + 1] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast<py::ssize_t>(i)));          return t;      }); @@ -94,9 +94,49 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {  //    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("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); +    }); + +    // 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); + + +    // These should fail to compile: +    // argument annotations are required when using 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); +      // test_function_signatures (along with most of the above)      struct KWClass { void foo(int, float) {} };      py::class_<KWClass>(m, "KWClass")          .def("foo0", &KWClass::foo)          .def("foo1", &KWClass::foo, "x"_a, "y"_a); + +    // 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); }, +        "a"_a = py::module_::import("decimal").attr("Decimal"));  } diff --git a/3rdparty/pybind11/tests/test_kwargs_and_defaults.py b/3rdparty/pybind11/tests/test_kwargs_and_defaults.py index 27a05a02..12fe705b 100644 --- a/3rdparty/pybind11/tests/test_kwargs_and_defaults.py +++ b/3rdparty/pybind11/tests/test_kwargs_and_defaults.py @@ -1,4 +1,8 @@ +# -*- coding: utf-8 -*-  import pytest + +import env  # noqa: F401 +  from pybind11_tests import kwargs_and_defaults as m @@ -11,11 +15,17 @@ def test_function_signatures(doc):      assert doc(m.kw_func_udl) == "kw_func_udl(x: int, y: int = 300) -> str"      assert doc(m.kw_func_udl_z) == "kw_func_udl_z(x: int, y: int = 0) -> str"      assert doc(m.args_function) == "args_function(*args) -> tuple" -    assert doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple" -    assert doc(m.KWClass.foo0) == \ -        "foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None" -    assert doc(m.KWClass.foo1) == \ -        "foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None" +    assert ( +        doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple" +    ) +    assert ( +        doc(m.KWClass.foo0) +        == "foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None" +    ) +    assert ( +        doc(m.KWClass.foo1) +        == "foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None" +    )  def test_named_arguments(msg): @@ -36,7 +46,9 @@ def test_named_arguments(msg):          # noinspection PyArgumentList          m.kw_func2(x=5, y=10, z=12)      assert excinfo.match( -        r'(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))' + '{3}$') +        r"(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))" +        + "{3}$" +    )      assert m.kw_func4() == "{13 17}"      assert m.kw_func4(myList=[1, 2, 3]) == "{1 2 3}" @@ -46,11 +58,11 @@ def test_named_arguments(msg):  def test_arg_and_kwargs(): -    args = 'arg1_value', 'arg2_value', 3 +    args = "arg1_value", "arg2_value", 3      assert m.args_function(*args) == args -    args = 'a1', 'a2' -    kwargs = dict(arg3='a3', arg4=4) +    args = "a1", "a2" +    kwargs = dict(arg3="a3", arg4=4)      assert m.args_kwargs_function(*args, **kwargs) == (args, kwargs) @@ -64,49 +76,166 @@ def test_mixed_args_and_kwargs(msg):      assert mpa(1, 2.5) == (1, 2.5, ())      with pytest.raises(TypeError) as excinfo:          assert mpa(1) -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          mixed_plus_args(): incompatible function arguments. The following argument types are supported:              1. (arg0: int, arg1: float, *args) -> tuple          Invoked with: 1      """  # noqa: E501 line too long +    )      with pytest.raises(TypeError) as excinfo:          assert mpa() -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          mixed_plus_args(): incompatible function arguments. The following argument types are supported:              1. (arg0: int, arg1: float, *args) -> tuple          Invoked with:      """  # noqa: E501 line too long +    ) -    assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (-2, 3.5, {'e': 2.71828, 'pi': 3.14159}) +    assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == ( +        -2, +        3.5, +        {"e": 2.71828, "pi": 3.14159}, +    )      assert mpak(7, 7.7, 7.77, 7.777, 7.7777, minusseven=-7) == ( -        7, 7.7, (7.77, 7.777, 7.7777), {'minusseven': -7}) +        7, +        7.7, +        (7.77, 7.777, 7.7777), +        {"minusseven": -7}, +    )      assert mpakd() == (1, 3.14159, (), {})      assert mpakd(3) == (3, 3.14159, (), {})      assert mpakd(j=2.71828) == (1, 2.71828, (), {}) -    assert mpakd(k=42) == (1, 3.14159, (), {'k': 42}) +    assert mpakd(k=42) == (1, 3.14159, (), {"k": 42})      assert mpakd(1, 1, 2, 3, 5, 8, then=13, followedby=21) == ( -        1, 1, (2, 3, 5, 8), {'then': 13, 'followedby': 21}) +        1, +        1, +        (2, 3, 5, 8), +        {"then": 13, "followedby": 21}, +    )      # Arguments specified both positionally and via kwargs should fail:      with pytest.raises(TypeError) as excinfo:          assert mpakd(1, i=1) -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:              1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple          Invoked with: 1; kwargs: i=1      """  # noqa: E501 line too long +    )      with pytest.raises(TypeError) as excinfo:          assert mpakd(1, 2, j=1) -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:              1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple          Invoked with: 1, 2; kwargs: j=1      """  # noqa: E501 line too long +    ) + + +def test_keyword_only_args(msg): +    assert m.kw_only_all(i=1, j=2) == (1, 2) +    assert m.kw_only_all(j=1, i=2) == (2, 1) + +    with pytest.raises(TypeError) as excinfo: +        assert m.kw_only_all(i=1) == (1,) +    assert "incompatible function arguments" in str(excinfo.value) + +    with pytest.raises(TypeError) as excinfo: +        assert m.kw_only_all(1, 2) == (1, 2) +    assert "incompatible function arguments" in str(excinfo.value) + +    assert m.kw_only_some(1, k=3, j=2) == (1, 2, 3) +    assert m.kw_only_with_defaults(z=8) == (3, 4, 5, 8) +    assert m.kw_only_with_defaults(2, z=8) == (2, 4, 5, 8) +    assert m.kw_only_with_defaults(2, j=7, k=8, z=9) == (2, 7, 8, 9) +    assert m.kw_only_with_defaults(2, 7, z=9, k=8) == (2, 7, 8, 9) + +    assert m.kw_only_mixed(1, j=2) == (1, 2) +    assert m.kw_only_mixed(j=2, i=3) == (3, 2) +    assert m.kw_only_mixed(i=2, j=3) == (2, 3) + +    assert m.kw_only_plus_more(4, 5, k=6, extra=7) == (4, 5, 6, {"extra": 7}) +    assert m.kw_only_plus_more(3, k=5, j=4, extra=6) == (3, 4, 5, {"extra": 6}) +    assert m.kw_only_plus_more(2, k=3, extra=4) == (2, -1, 3, {"extra": 4}) + +    with pytest.raises(TypeError) as excinfo: +        assert m.kw_only_mixed(i=1) == (1,) +    assert "incompatible function arguments" in str(excinfo.value) + +    with pytest.raises(RuntimeError) as excinfo: +        m.register_invalid_kw_only(m) +    assert ( +        msg(excinfo.value) +        == """ +        arg(): cannot specify an unnamed argument after an kw_only() annotation +    """ +    ) + + +def test_positional_only_args(msg): +    assert m.pos_only_all(1, 2) == (1, 2) +    assert m.pos_only_all(2, 1) == (2, 1) + +    with pytest.raises(TypeError) as excinfo: +        m.pos_only_all(i=1, j=2) +    assert "incompatible function arguments" in str(excinfo.value) +    assert m.pos_only_mix(1, 2) == (1, 2) +    assert m.pos_only_mix(2, j=1) == (2, 1) + +    with pytest.raises(TypeError) as excinfo: +        m.pos_only_mix(i=1, j=2) +    assert "incompatible function arguments" in str(excinfo.value) + +    assert m.pos_kw_only_mix(1, 2, k=3) == (1, 2, 3) +    assert m.pos_kw_only_mix(1, j=2, k=3) == (1, 2, 3) + +    with pytest.raises(TypeError) as excinfo: +        m.pos_kw_only_mix(i=1, j=2, k=3) +    assert "incompatible function arguments" in str(excinfo.value) + +    with pytest.raises(TypeError) as excinfo: +        m.pos_kw_only_mix(1, 2, 3) +    assert "incompatible function arguments" in str(excinfo.value) + +    with pytest.raises(TypeError) as excinfo: +        m.pos_only_def_mix() +    assert "incompatible function arguments" in str(excinfo.value) + +    assert m.pos_only_def_mix(1) == (1, 2, 3) +    assert m.pos_only_def_mix(1, 4) == (1, 4, 3) +    assert m.pos_only_def_mix(1, 4, 7) == (1, 4, 7) +    assert m.pos_only_def_mix(1, 4, k=7) == (1, 4, 7) + +    with pytest.raises(TypeError) as excinfo: +        m.pos_only_def_mix(1, j=4) +    assert "incompatible function arguments" in str(excinfo.value) + + +def test_signatures(): +    assert "kw_only_all(*, i: int, j: int) -> tuple\n" == m.kw_only_all.__doc__ +    assert "kw_only_mixed(i: int, *, j: int) -> tuple\n" == m.kw_only_mixed.__doc__ +    assert "pos_only_all(i: int, j: int, /) -> tuple\n" == m.pos_only_all.__doc__ +    assert "pos_only_mix(i: int, /, j: int) -> tuple\n" == m.pos_only_mix.__doc__ +    assert ( +        "pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple\n" +        == m.pos_kw_only_mix.__doc__ +    ) + + +@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""" @@ -128,11 +257,18 @@ def test_args_refcount():      assert m.args_function(-1, myval) == (-1, myval)      assert refcount(myval) == expected -    assert m.mixed_plus_args_kwargs(5, 6.0, myval, a=myval) == (5, 6.0, (myval,), {"a": myval}) +    assert m.mixed_plus_args_kwargs(5, 6.0, myval, a=myval) == ( +        5, +        6.0, +        (myval,), +        {"a": myval}, +    )      assert refcount(myval) == expected -    assert m.args_kwargs_function(7, 8, myval, a=1, b=myval) == \ -        ((7, 8, myval), {"a": 1, "b": myval}) +    assert m.args_kwargs_function(7, 8, myval, a=1, b=myval) == ( +        (7, 8, myval), +        {"a": 1, "b": myval}, +    )      assert refcount(myval) == expected      exp3 = refcount(myval, myval, myval) @@ -145,3 +281,5 @@ def test_args_refcount():      # tuple without having to inc_ref the individual elements, but here we can't, hence the extra      # refs.      assert m.mixed_args_refcount(myval, myval, myval) == (exp3 + 3, exp3 + 3, exp3 + 3) + +    assert m.class_default_argument() == "<class 'decimal.Decimal'>" diff --git a/3rdparty/pybind11/tests/test_local_bindings.cpp b/3rdparty/pybind11/tests/test_local_bindings.cpp index 97c02dbe..c61e3888 100644 --- a/3rdparty/pybind11/tests/test_local_bindings.cpp +++ b/3rdparty/pybind11/tests/test_local_bindings.cpp @@ -41,7 +41,7 @@ TEST_SUBMODULE(local_bindings, m) {      // 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"); +        auto main = py::module_::import("pybind11_tests");          if (py::hasattr(main, "class_")) {              bind_local<LocalExternal, 7>(m, "LocalExternal", py::module_local());          } diff --git a/3rdparty/pybind11/tests/test_local_bindings.py b/3rdparty/pybind11/tests/test_local_bindings.py index b380376e..d23c4675 100644 --- a/3rdparty/pybind11/tests/test_local_bindings.py +++ b/3rdparty/pybind11/tests/test_local_bindings.py @@ -1,5 +1,8 @@ +# -*- coding: utf-8 -*-  import pytest +import env  # noqa: F401 +  from pybind11_tests import local_bindings as m @@ -33,8 +36,8 @@ def test_local_bindings():      assert i2.get() == 11      assert i2.get2() == 12 -    assert not hasattr(i1, 'get2') -    assert not hasattr(i2, 'get3') +    assert not hasattr(i1, "get2") +    assert not hasattr(i2, "get3")      # Loading within the local module      assert m.local_value(i1) == 5 @@ -52,7 +55,9 @@ def test_nonlocal_failure():      with pytest.raises(RuntimeError) as excinfo:          cm.register_nonlocal() -    assert str(excinfo.value) == 'generic_type: type "NonLocalType" is already registered!' +    assert ( +        str(excinfo.value) == 'generic_type: type "NonLocalType" is already registered!' +    )  def test_duplicate_local(): @@ -60,9 +65,12 @@ def test_duplicate_local():      with pytest.raises(RuntimeError) as excinfo:          m.register_local_external()      import pybind11_tests +      assert str(excinfo.value) == (          'generic_type: type "LocalExternal" is already registered!' -        if hasattr(pybind11_tests, 'class_') else 'test_class not enabled') +        if hasattr(pybind11_tests, "class_") +        else "test_class not enabled" +    )  def test_stl_bind_local(): @@ -95,8 +103,8 @@ def test_stl_bind_local():      d1["b"] = v1[1]      d2["c"] = v2[0]      d2["d"] = v2[1] -    assert {i: d1[i].get() for i in d1} == {'a': 0, 'b': 1} -    assert {i: d2[i].get() for i in d2} == {'c': 2, 'd': 3} +    assert {i: d1[i].get() for i in d1} == {"a": 0, "b": 1} +    assert {i: d2[i].get() for i in d2} == {"c": 2, "d": 3}  def test_stl_bind_global(): @@ -104,15 +112,21 @@ def test_stl_bind_global():      with pytest.raises(RuntimeError) as excinfo:          cm.register_nonlocal_map() -    assert str(excinfo.value) == 'generic_type: type "NonLocalMap" is already registered!' +    assert ( +        str(excinfo.value) == 'generic_type: type "NonLocalMap" is already registered!' +    )      with pytest.raises(RuntimeError) as excinfo:          cm.register_nonlocal_vec() -    assert str(excinfo.value) == 'generic_type: type "NonLocalVec" is already registered!' +    assert ( +        str(excinfo.value) == 'generic_type: type "NonLocalVec" is already registered!' +    )      with pytest.raises(RuntimeError) as excinfo:          cm.register_nonlocal_map2() -    assert str(excinfo.value) == 'generic_type: type "NonLocalMap2" is already registered!' +    assert ( +        str(excinfo.value) == 'generic_type: type "NonLocalMap2" is already registered!' +    )  def test_mixed_local_global(): @@ -120,6 +134,7 @@ def test_mixed_local_global():      type can be registered even if the type is already registered globally.  With the module,      casting will go to the local type; outside the module casting goes to the global type."""      import pybind11_cross_module_tests as cm +      m.register_mixed_global()      m.register_mixed_local() @@ -142,16 +157,30 @@ def test_mixed_local_global():      a.append(cm.get_mixed_gl(11))      a.append(cm.get_mixed_lg(12)) -    assert [x.get() for x in a] == \ -        [101, 1002, 103, 1004, 105, 1006, 207, 2008, 109, 1010, 211, 2012] +    assert [x.get() for x in a] == [ +        101, +        1002, +        103, +        1004, +        105, +        1006, +        207, +        2008, +        109, +        1010, +        211, +        2012, +    ]  def test_internal_locals_differ():      """Makes sure the internal local type map differs across the two modules"""      import pybind11_cross_module_tests as cm +      assert m.local_cpp_types_addr() != cm.local_cpp_types_addr() +@pytest.mark.xfail("env.PYPY and sys.pypy_version_info < (7, 3, 2)")  def test_stl_caster_vs_stl_bind(msg):      """One module uses a generic vector caster from `<pybind11/stl.h>` while the other      exports `std::vector<int>` via `py:bind_vector` and `py::module_local`""" @@ -165,12 +194,15 @@ def test_stl_caster_vs_stl_bind(msg):      assert m.load_vector_via_caster(v2) == 6      with pytest.raises(TypeError) as excinfo:          cm.load_vector_via_binding(v2) == 6 -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """      load_vector_via_binding(): incompatible function arguments. The following argument types are supported:          1. (arg0: pybind11_cross_module_tests.VectorInt) -> int      Invoked with: [1, 2, 3]      """  # noqa: E501 line too long +    )  def test_cross_module_calls(): diff --git a/3rdparty/pybind11/tests/test_methods_and_attributes.cpp b/3rdparty/pybind11/tests/test_methods_and_attributes.cpp index c7b82f13..6a2cfb6f 100644 --- a/3rdparty/pybind11/tests/test_methods_and_attributes.cpp +++ b/3rdparty/pybind11/tests/test_methods_and_attributes.cpp @@ -21,6 +21,7 @@ public:      ExampleMandA() { print_default_created(this); }      ExampleMandA(int value) : value(value) { print_created(this, value); }      ExampleMandA(const ExampleMandA &e) : value(e.value) { print_copy_created(this); } +    ExampleMandA(std::string&&) {}      ExampleMandA(ExampleMandA &&e) : value(e.value) { print_move_created(this); }      ~ExampleMandA() { print_destroyed(this); } @@ -43,6 +44,8 @@ public:      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 @@ -105,76 +108,6 @@ struct TestPropRVP {  UserType TestPropRVP::sv1(1);  UserType TestPropRVP::sv2(1); -// py::arg/py::arg_v testing: these arguments just record their argument when invoked -class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; }; -class ArgInspector2 { public: std::string arg = "(default arg inspector 2)"; }; -class ArgAlwaysConverts { }; -namespace pybind11 { namespace detail { -template <> struct type_caster<ArgInspector1> { -public: -    PYBIND11_TYPE_CASTER(ArgInspector1, _("ArgInspector1")); - -    bool load(handle src, bool convert) { -        value.arg = "loading ArgInspector1 argument " + -            std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed.  " -            "Argument value = " + (std::string) str(src); -        return true; -    } - -    static handle cast(const ArgInspector1 &src, return_value_policy, handle) { -        return str(src.arg).release(); -    } -}; -template <> struct type_caster<ArgInspector2> { -public: -    PYBIND11_TYPE_CASTER(ArgInspector2, _("ArgInspector2")); - -    bool load(handle src, bool convert) { -        value.arg = "loading ArgInspector2 argument " + -            std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed.  " -            "Argument value = " + (std::string) str(src); -        return true; -    } - -    static handle cast(const ArgInspector2 &src, return_value_policy, handle) { -        return str(src.arg).release(); -    } -}; -template <> struct type_caster<ArgAlwaysConverts> { -public: -    PYBIND11_TYPE_CASTER(ArgAlwaysConverts, _("ArgAlwaysConverts")); - -    bool load(handle, bool convert) { -        return convert; -    } - -    static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) { -        return py::none().release(); -    } -}; -}} - -// test_custom_caster_destruction -class DestructionTester { -public: -    DestructionTester() { print_default_created(this); } -    ~DestructionTester() { print_destroyed(this); } -    DestructionTester(const DestructionTester &) { print_copy_created(this); } -    DestructionTester(DestructionTester &&) { print_move_created(this); } -    DestructionTester &operator=(const DestructionTester &) { print_copy_assigned(this); return *this; } -    DestructionTester &operator=(DestructionTester &&) { print_move_assigned(this); return *this; } -}; -namespace pybind11 { namespace detail { -template <> struct type_caster<DestructionTester> { -    PYBIND11_TYPE_CASTER(DestructionTester, _("DestructionTester")); -    bool load(handle, bool) { return true; } - -    static handle cast(const DestructionTester &, return_value_policy, handle) { -        return py::bool_(true).release(); -    } -}; -}} -  // Test None-allowed py::arg argument policy  class NoneTester { public: int answer = 42; };  int none1(const NoneTester &obj) { return obj.answer; } @@ -207,11 +140,20 @@ public:      double sum() const { return rw_value + ro_value; }  }; +// Test explicit lvalue ref-qualification +struct RefQualified { +    int value = 0; + +    void refQualified(int other) & { value += other; } +    int constRefQualified(int other) const & { return value + other; } +}; +  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("add1", &ExampleMandA::add1)          .def("add2", &ExampleMandA::add2) @@ -223,6 +165,7 @@ TEST_SUBMODULE(methods_and_attributes, m) {          .def("add8", &ExampleMandA::add8)          .def("add9", &ExampleMandA::add9)          .def("add10", &ExampleMandA::add10) +        .def("consume_str", &ExampleMandA::consume_str)          .def("self1", &ExampleMandA::self1)          .def("self2", &ExampleMandA::self2)          .def("self3", &ExampleMandA::self3) @@ -264,12 +207,12 @@ TEST_SUBMODULE(methods_and_attributes, m) {          // 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")); +            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")); +            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));          }) @@ -341,11 +284,18 @@ TEST_SUBMODULE(methods_and_attributes, m) {      py::class_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type))          .def_property_readonly_static("readonly", [](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", [](int) { return 3; }); +    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() { print_destroyed(this); }      };      py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr()) @@ -356,33 +306,6 @@ TEST_SUBMODULE(methods_and_attributes, m) {          .def(py::init());  #endif -    // test_noconvert_args -    // -    // Test converting.  The ArgAlwaysConverts is just there to make the first no-conversion pass -    // fail so that our call always ends up happening via the second dispatch (the one that allows -    // some conversion). -    class ArgInspector { -    public: -        ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; } -        std::string g(ArgInspector1 a, const ArgInspector1 &b, int c, ArgInspector2 *d, ArgAlwaysConverts) { -            return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg; -        } -        static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; } -    }; -    py::class_<ArgInspector>(m, "ArgInspector") -        .def(py::init<>()) -        .def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts()) -        .def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert()=13, "d"_a=ArgInspector2(), py::arg() = ArgAlwaysConverts()) -        .def_static("h", &ArgInspector::h, py::arg().noconvert(), py::arg() = ArgAlwaysConverts()) -        ; -    m.def("arg_inspect_func", [](ArgInspector2 a, ArgInspector1 b, ArgAlwaysConverts) { return a.arg + "\n" + b.arg; }, -            py::arg().noconvert(false), py::arg_v(nullptr, ArgInspector1()).noconvert(true), py::arg() = ArgAlwaysConverts()); - -    m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f")); -    m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert()); -    m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i")); -    m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert()); -      // test_bad_arg_default      // Issue/PR #648: bad arg default debugging output  #if !defined(NDEBUG) @@ -391,11 +314,11 @@ TEST_SUBMODULE(methods_and_attributes, m) {      m.attr("debug_enabled") = false;  #endif      m.def("bad_arg_def_named", []{ -        auto m = py::module::import("pybind11_tests"); +        auto m = py::module_::import("pybind11_tests");          m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg("a") = UnregisteredType());      });      m.def("bad_arg_def_unnamed", []{ -        auto m = py::module::import("pybind11_tests"); +        auto m = py::module_::import("pybind11_tests");          m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType());      }); @@ -413,6 +336,9 @@ TEST_SUBMODULE(methods_and_attributes, m) {      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)); +      // test_str_issue      // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid      py::class_<StrIssue>(m, "StrIssue") @@ -446,15 +372,10 @@ TEST_SUBMODULE(methods_and_attributes, m) {      using Adapted = decltype(py::method_adaptor<RegisteredDerived>(&RegisteredDerived::do_nothing));      static_assert(std::is_same<Adapted, void (RegisteredDerived::*)() const>::value, ""); -    // test_custom_caster_destruction -    // Test that `take_ownership` works on types with a custom type caster when given a pointer - -    // default policy: don't take ownership: -    m.def("custom_caster_no_destroy", []() { static auto *dt = new DestructionTester(); return dt; }); - -    m.def("custom_caster_destroy", []() { return new DestructionTester(); }, -            py::return_value_policy::take_ownership); // Takes ownership: destroy when finished -    m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); }, -            py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction) -    m.def("destruction_tester_cstats", &ConstructorStats::get<DestructionTester>, py::return_value_policy::reference); +    // test_methods_and_attributes +    py::class_<RefQualified>(m, "RefQualified") +        .def(py::init<>()) +        .def_readonly("value", &RefQualified::value) +        .def("refQualified", &RefQualified::refQualified) +        .def("constRefQualified", &RefQualified::constRefQualified);  } diff --git a/3rdparty/pybind11/tests/test_methods_and_attributes.py b/3rdparty/pybind11/tests/test_methods_and_attributes.py index f1c862be..2aaf9331 100644 --- a/3rdparty/pybind11/tests/test_methods_and_attributes.py +++ b/3rdparty/pybind11/tests/test_methods_and_attributes.py @@ -1,4 +1,8 @@ +# -*- coding: utf-8 -*-  import pytest + +import env  # noqa: F401 +  from pybind11_tests import methods_and_attributes as m  from pybind11_tests import ConstructorStats @@ -36,17 +40,17 @@ def test_methods_and_attributes():      assert instance1.overloaded(0) == "(int)"      assert instance1.overloaded(1, 1.0) == "(int, float)"      assert instance1.overloaded(2.0, 2) == "(float, int)" -    assert instance1.overloaded(3,   3) == "(int, int)" -    assert instance1.overloaded(4., 4.) == "(float, float)" +    assert instance1.overloaded(3, 3) == "(int, int)" +    assert instance1.overloaded(4.0, 4.0) == "(float, float)"      assert instance1.overloaded_const(-3) == "(int) const"      assert instance1.overloaded_const(5, 5.0) == "(int, float) const"      assert instance1.overloaded_const(6.0, 6) == "(float, int) const" -    assert instance1.overloaded_const(7,   7) == "(int, int) const" -    assert instance1.overloaded_const(8., 8.) == "(float, float) const" +    assert instance1.overloaded_const(7, 7) == "(int, int) const" +    assert instance1.overloaded_const(8.0, 8.0) == "(float, float) const"      assert instance1.overloaded_float(1, 1) == "(float, float)" -    assert instance1.overloaded_float(1, 1.) == "(float, float)" -    assert instance1.overloaded_float(1., 1) == "(float, float)" -    assert instance1.overloaded_float(1., 1.) == "(float, float)" +    assert instance1.overloaded_float(1, 1.0) == "(float, float)" +    assert instance1.overloaded_float(1.0, 1) == "(float, float)" +    assert instance1.overloaded_float(1.0, 1.0) == "(float, float)"      assert instance1.value == 320      instance1.value = 100 @@ -58,8 +62,8 @@ def test_methods_and_attributes():      assert cstats.alive() == 0      assert cstats.values() == ["32"]      assert cstats.default_constructions == 1 -    assert cstats.copy_constructions == 3 -    assert cstats.move_constructions >= 1 +    assert cstats.copy_constructions == 2 +    assert cstats.move_constructions >= 2      assert cstats.copy_assignments == 0      assert cstats.move_assignments == 0 @@ -167,6 +171,19 @@ def test_static_properties():      assert m.TestPropertiesOverride().def_readonly == 99      assert m.TestPropertiesOverride.def_readonly_static == 99 +    # Only static attributes can be deleted +    del m.TestPropertiesOverride.def_readonly_static +    assert ( +        hasattr(m.TestPropertiesOverride, "def_readonly_static") +        and m.TestPropertiesOverride.def_readonly_static +        is m.TestProperties.def_readonly_static +    ) +    assert "def_readonly_static" not in m.TestPropertiesOverride.__dict__ +    properties_override = m.TestPropertiesOverride() +    with pytest.raises(AttributeError) as excinfo: +        del properties_override.def_readonly +    assert "can't delete attribute" in str(excinfo.value) +  def test_static_cls():      """Static property getter and setters expect the type object as the their only argument""" @@ -189,7 +206,10 @@ def test_metaclass_override():      assert type(m.MetaclassOverride).__name__ == "type"      assert m.MetaclassOverride.readonly == 1 -    assert type(m.MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property" +    assert ( +        type(m.MetaclassOverride.__dict__["readonly"]).__name__ +        == "pybind11_static_property" +    )      # Regular `type` replaces the property instead of calling `__set__()`      m.MetaclassOverride.readonly = 2 @@ -202,22 +222,26 @@ def test_no_mixed_overloads():      with pytest.raises(RuntimeError) as excinfo:          m.ExampleMandA.add_mixed_overloads1() -    assert (str(excinfo.value) == -            "overloading a method with both static and instance methods is not supported; " + -            ("compile in debug mode for more details" if not debug_enabled else -             "error while attempting to bind static method ExampleMandA.overload_mixed1" -             "(arg0: float) -> str") -            ) +    assert str( +        excinfo.value +    ) == "overloading a method with both static and instance methods is not supported; " + ( +        "compile in debug mode for more details" +        if not debug_enabled +        else "error while attempting to bind static method ExampleMandA.overload_mixed1" +        "(arg0: float) -> str" +    )      with pytest.raises(RuntimeError) as excinfo:          m.ExampleMandA.add_mixed_overloads2() -    assert (str(excinfo.value) == -            "overloading a method with both static and instance methods is not supported; " + -            ("compile in debug mode for more details" if not debug_enabled else -             "error while attempting to bind instance method ExampleMandA.overload_mixed2" -             "(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)" -             " -> str") -            ) +    assert str( +        excinfo.value +    ) == "overloading a method with both static and instance methods is not supported; " + ( +        "compile in debug mode for more details" +        if not debug_enabled +        else "error while attempting to bind instance method ExampleMandA.overload_mixed2" +        "(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)" +        " -> str" +    )  @pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"]) @@ -256,8 +280,8 @@ def test_property_rvalue_policy():      assert os.value == 1 -# https://bitbucket.org/pypy/pypy/issues/2447 -@pytest.unsupported_on_pypy +# https://foss.heptapod.net/pypy/pypy/-/issues/2447 +@pytest.mark.xfail("env.PYPY")  def test_dynamic_attributes():      instance = m.DynamicClass()      assert not hasattr(instance, "foo") @@ -298,8 +322,8 @@ def test_dynamic_attributes():          assert cstats.alive() == 0 -# https://bitbucket.org/pypy/pypy/issues/2447 -@pytest.unsupported_on_pypy +# https://foss.heptapod.net/pypy/pypy/-/issues/2447 +@pytest.mark.xfail("env.PYPY")  def test_cyclic_gc():      # One object references itself      instance = m.DynamicClass() @@ -321,69 +345,6 @@ def test_cyclic_gc():      assert cstats.alive() == 0 -def test_noconvert_args(msg): -    a = m.ArgInspector() -    assert msg(a.f("hi")) == """ -        loading ArgInspector1 argument WITH conversion allowed.  Argument value = hi -    """ -    assert msg(a.g("this is a", "this is b")) == """ -        loading ArgInspector1 argument WITHOUT conversion allowed.  Argument value = this is a -        loading ArgInspector1 argument WITH conversion allowed.  Argument value = this is b -        13 -        loading ArgInspector2 argument WITH conversion allowed.  Argument value = (default arg inspector 2) -    """  # noqa: E501 line too long -    assert msg(a.g("this is a", "this is b", 42)) == """ -        loading ArgInspector1 argument WITHOUT conversion allowed.  Argument value = this is a -        loading ArgInspector1 argument WITH conversion allowed.  Argument value = this is b -        42 -        loading ArgInspector2 argument WITH conversion allowed.  Argument value = (default arg inspector 2) -    """  # noqa: E501 line too long -    assert msg(a.g("this is a", "this is b", 42, "this is d")) == """ -        loading ArgInspector1 argument WITHOUT conversion allowed.  Argument value = this is a -        loading ArgInspector1 argument WITH conversion allowed.  Argument value = this is b -        42 -        loading ArgInspector2 argument WITH conversion allowed.  Argument value = this is d -    """ -    assert (a.h("arg 1") == -            "loading ArgInspector2 argument WITHOUT conversion allowed.  Argument value = arg 1") -    assert msg(m.arg_inspect_func("A1", "A2")) == """ -        loading ArgInspector2 argument WITH conversion allowed.  Argument value = A1 -        loading ArgInspector1 argument WITHOUT conversion allowed.  Argument value = A2 -    """ - -    assert m.floats_preferred(4) == 2.0 -    assert m.floats_only(4.0) == 2.0 -    with pytest.raises(TypeError) as excinfo: -        m.floats_only(4) -    assert msg(excinfo.value) == """ -        floats_only(): incompatible function arguments. The following argument types are supported: -            1. (f: float) -> float - -        Invoked with: 4 -    """ - -    assert m.ints_preferred(4) == 2 -    assert m.ints_preferred(True) == 0 -    with pytest.raises(TypeError) as excinfo: -        m.ints_preferred(4.0) -    assert msg(excinfo.value) == """ -        ints_preferred(): incompatible function arguments. The following argument types are supported: -            1. (i: int) -> int - -        Invoked with: 4.0 -    """  # noqa: E501 line too long - -    assert m.ints_only(4) == 2 -    with pytest.raises(TypeError) as excinfo: -        m.ints_only(4.0) -    assert msg(excinfo.value) == """ -        ints_only(): incompatible function arguments. The following argument types are supported: -            1. (i: int) -> int - -        Invoked with: 4.0 -    """ - -  def test_bad_arg_default(msg):      from pybind11_tests import debug_enabled @@ -392,8 +353,8 @@ def test_bad_arg_default(msg):      assert msg(excinfo.value) == (          "arg(): could not convert default argument 'a: UnregisteredType' in function "          "'should_fail' into a Python object (type not registered yet?)" -        if debug_enabled else -        "arg(): could not convert default argument into a Python object (type not registered " +        if debug_enabled +        else "arg(): could not convert default argument into a Python object (type not registered "          "yet?). Compile in debug mode for more information."      ) @@ -402,8 +363,8 @@ 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 else -        "arg(): could not convert default argument into a Python object (type not registered " +        if debug_enabled +        else "arg(): could not convert default argument into a Python object (type not registered "          "yet?). Compile in debug mode for more information."      ) @@ -440,12 +401,15 @@ def test_accepts_none(msg):      # The first one still raises because you can't pass None as a lvalue reference arg:      with pytest.raises(TypeError) as excinfo:          assert m.ok_none1(None) == -1 -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          ok_none1(): incompatible function arguments. The following argument types are supported:              1. (arg0: m.methods_and_attributes.NoneTester) -> int          Invoked with: None      """ +    )      # The rest take the argument as pointer or holder, and accept None:      assert m.ok_none2(None) == -1 @@ -453,6 +417,19 @@ def test_accepts_none(msg):      assert m.ok_none4(None) == -1      assert m.ok_none5(None) == -1 +    with pytest.raises(TypeError) as excinfo: +        m.no_none_kwarg(None) +    assert "incompatible function arguments" in str(excinfo.value) +    with pytest.raises(TypeError) as excinfo: +        m.no_none_kwarg(a=None) +    assert "incompatible function arguments" in str(excinfo.value) +    with pytest.raises(TypeError) as excinfo: +        m.no_none_kwarg_kw_only(None) +    assert "incompatible function arguments" in str(excinfo.value) +    with pytest.raises(TypeError) as excinfo: +        m.no_none_kwarg_kw_only(a=None) +    assert "incompatible function arguments" in str(excinfo.value) +  def test_str_issue(msg):      """#283: __str__ called on uninitialized instance when constructor arguments invalid""" @@ -461,13 +438,16 @@ def test_str_issue(msg):      with pytest.raises(TypeError) as excinfo:          str(m.StrIssue("no", "such", "constructor")) -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          __init__(): incompatible constructor arguments. The following argument types are supported:              1. m.methods_and_attributes.StrIssue(arg0: int)              2. m.methods_and_attributes.StrIssue()          Invoked with: 'no', 'such', 'constructor'      """ +    )  def test_unregistered_base_implementations(): @@ -488,25 +468,40 @@ def test_unregistered_base_implementations():      assert a.ro_value_prop == 1.75 -def test_custom_caster_destruction(): -    """Tests that returning a pointer to a type that gets converted with a custom type caster gets -    destroyed when the function has py::return_value_policy::take_ownership policy applied.""" +def test_ref_qualified(): +    """Tests that explicit lvalue ref-qualified methods can be called just like their +    non ref-qualified counterparts.""" -    cstats = m.destruction_tester_cstats() -    # This one *doesn't* have take_ownership: the pointer should be used but not destroyed: -    z = m.custom_caster_no_destroy() -    assert cstats.alive() == 1 and cstats.default_constructions == 1 -    assert z +    r = m.RefQualified() +    assert r.value == 0 +    r.refQualified(17) +    assert r.value == 17 +    assert r.constRefQualified(23) == 40 -    # take_ownership applied: this constructs a new object, casts it, then destroys it: -    z = m.custom_caster_destroy() -    assert z -    assert cstats.default_constructions == 2 -    # Same, but with a const pointer return (which should *not* inhibit destruction): -    z = m.custom_caster_destroy_const() -    assert z -    assert cstats.default_constructions == 3 +def test_overload_ordering(): +    "Check to see if the normal overload order (first defined) and prepend overload order works" +    assert m.overload_order("string") == 1 +    assert m.overload_order(0) == 4 -    # Make sure we still only have the original object (from ..._no_destroy()) alive: -    assert cstats.alive() == 1 +    # 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 "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 "4. (arg0: int) -> int" in str(err.value) diff --git a/3rdparty/pybind11/tests/test_modules.cpp b/3rdparty/pybind11/tests/test_modules.cpp index c1475fa6..67387e80 100644 --- a/3rdparty/pybind11/tests/test_modules.cpp +++ b/3rdparty/pybind11/tests/test_modules.cpp @@ -13,6 +13,7 @@  TEST_SUBMODULE(modules, m) {      // test_nested_modules +    // This is intentionally "py::module" to verify it still can be used in place of "py::module_"      py::module m_sub = m.def_submodule("subsubmodule");      m_sub.def("submodule_func", []() { return "submodule_func()"; }); @@ -50,6 +51,7 @@ TEST_SUBMODULE(modules, m) {          .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_"      m.attr("OD") = py::module::import("collections").attr("OrderedDict");      // test_duplicate_registration @@ -60,7 +62,8 @@ TEST_SUBMODULE(modules, m) {          class Dupe3 { };          class DupeException { }; -        auto dm = py::module("dummy"); +        // 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 failures = py::list();          py::class_<Dupe1>(dm, "Dupe1"); diff --git a/3rdparty/pybind11/tests/test_modules.py b/3rdparty/pybind11/tests/test_modules.py index 2552838c..5630ccf9 100644 --- a/3rdparty/pybind11/tests/test_modules.py +++ b/3rdparty/pybind11/tests/test_modules.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*-  from pybind11_tests import modules as m  from pybind11_tests.modules import subsubmodule as ms  from pybind11_tests import ConstructorStats @@ -5,9 +6,13 @@ from pybind11_tests import ConstructorStats  def test_nested_modules():      import pybind11_tests +      assert pybind11_tests.__name__ == "pybind11_tests"      assert pybind11_tests.modules.__name__ == "pybind11_tests.modules" -    assert pybind11_tests.modules.subsubmodule.__name__ == "pybind11_tests.modules.subsubmodule" +    assert ( +        pybind11_tests.modules.subsubmodule.__name__ +        == "pybind11_tests.modules.subsubmodule" +    )      assert m.__name__ == "pybind11_tests.modules"      assert ms.__name__ == "pybind11_tests.modules.subsubmodule" @@ -34,7 +39,7 @@ def test_reference_internal():      del b      assert astats.alive() == 0      assert bstats.alive() == 0 -    assert astats.values() == ['1', '2', '42', '43'] +    assert astats.values() == ["1", "2", "42", "43"]      assert bstats.values() == []      assert astats.default_constructions == 0      assert bstats.default_constructions == 1 @@ -53,7 +58,7 @@ def test_importing():      from collections import OrderedDict      assert OD is OrderedDict -    assert str(OD([(1, 'a'), (2, 'b')])) == "OrderedDict([(1, 'a'), (2, 'b')])" +    assert str(OD([(1, "a"), (2, "b")])) == "OrderedDict([(1, 'a'), (2, 'b')])"  def test_pydoc(): diff --git a/3rdparty/pybind11/tests/test_multiple_inheritance.cpp b/3rdparty/pybind11/tests/test_multiple_inheritance.cpp index ba1674fb..e6720080 100644 --- a/3rdparty/pybind11/tests/test_multiple_inheritance.cpp +++ b/3rdparty/pybind11/tests/test_multiple_inheritance.cpp @@ -193,14 +193,12 @@ TEST_SUBMODULE(multiple_inheritance, m) {          .def_readwrite_static("static_value", &VanillaStaticMix2::static_value); -#if !defined(PYPY_VERSION)      struct WithDict { };      struct VanillaDictMix1 : Vanilla, WithDict { };      struct VanillaDictMix2 : WithDict, Vanilla { };      py::class_<WithDict>(m, "WithDict", py::dynamic_attr()).def(py::init<>());      py::class_<VanillaDictMix1, Vanilla, WithDict>(m, "VanillaDictMix1").def(py::init<>());      py::class_<VanillaDictMix2, WithDict, Vanilla>(m, "VanillaDictMix2").def(py::init<>()); -#endif      // test_diamond_inheritance      // Issue #959: segfault when constructing diamond inheritance instance diff --git a/3rdparty/pybind11/tests/test_multiple_inheritance.py b/3rdparty/pybind11/tests/test_multiple_inheritance.py index 475dd3b3..e6a7f976 100644 --- a/3rdparty/pybind11/tests/test_multiple_inheritance.py +++ b/3rdparty/pybind11/tests/test_multiple_inheritance.py @@ -1,4 +1,8 @@ +# -*- coding: utf-8 -*-  import pytest + +import env  # noqa: F401 +  from pybind11_tests import ConstructorStats  from pybind11_tests import multiple_inheritance as m @@ -10,6 +14,8 @@ 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")  def test_multiple_inheritance_mix1():      class Base1:          def __init__(self, i): @@ -30,7 +36,6 @@ def test_multiple_inheritance_mix1():  def test_multiple_inheritance_mix2(): -      class Base2:          def __init__(self, i):              self.i = i @@ -49,8 +54,9 @@ 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")  def test_multiple_inheritance_python(): -      class MI1(m.Base1, m.Base2):          def __init__(self, i, j):              m.Base1.__init__(self, i) @@ -156,7 +162,6 @@ def test_multiple_inheritance_python():  def test_multiple_inheritance_python_many_bases(): -      class MIMany14(m.BaseN1, m.BaseN2, m.BaseN3, m.BaseN4):          def __init__(self):              m.BaseN1.__init__(self, 1) @@ -171,8 +176,16 @@ def test_multiple_inheritance_python_many_bases():              m.BaseN7.__init__(self, 7)              m.BaseN8.__init__(self, 8) -    class MIMany916(m.BaseN9, m.BaseN10, m.BaseN11, m.BaseN12, m.BaseN13, m.BaseN14, m.BaseN15, -                    m.BaseN16): +    class MIMany916( +        m.BaseN9, +        m.BaseN10, +        m.BaseN11, +        m.BaseN12, +        m.BaseN13, +        m.BaseN14, +        m.BaseN15, +        m.BaseN16, +    ):          def __init__(self):              m.BaseN9.__init__(self, 9)              m.BaseN10.__init__(self, 10) @@ -218,7 +231,6 @@ def test_multiple_inheritance_python_many_bases():  def test_multiple_inheritance_virtbase(): -      class MITypePy(m.Base12a):          def __init__(self, i, j):              m.Base12a.__init__(self, i, j) @@ -231,7 +243,7 @@ def test_multiple_inheritance_virtbase():  def test_mi_static_properties():      """Mixing bases with and without static properties should be possible -     and the result should be independent of base definition order""" +    and the result should be independent of base definition order"""      for d in (m.VanillaStaticMix1(), m.VanillaStaticMix2()):          assert d.vanilla() == "Vanilla" @@ -253,7 +265,7 @@ def test_mi_static_properties():          assert d.static_value == 0 -@pytest.unsupported_on_pypy +# Requires PyPy 6+  def test_mi_dynamic_attributes():      """Mixing bases with and without dynamic attribute support""" diff --git a/3rdparty/pybind11/tests/test_numpy_array.cpp b/3rdparty/pybind11/tests/test_numpy_array.cpp index 156a3bfa..a84de77f 100644 --- a/3rdparty/pybind11/tests/test_numpy_array.cpp +++ b/3rdparty/pybind11/tests/test_numpy_array.cpp @@ -22,7 +22,7 @@ struct DtypeCheck {  template <typename T>  DtypeCheck get_dtype_check(const char* name) { -    py::module np = py::module::import("numpy"); +    py::module_ np = py::module_::import("numpy");      DtypeCheck check{};      check.numpy = np.attr("dtype")(np.attr(name));      check.pybind11 = py::dtype::of<T>(); @@ -89,23 +89,23 @@ template<typename... Ix> arr data_t(const arr_t& a, Ix... index) {  template<typename... Ix> arr& mutate_data(arr& a, Ix... index) {      auto ptr = (uint8_t *) a.mutable_data(index...); -    for (ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++) +    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) {      auto ptr = a.mutable_data(index...); -    for (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> ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); } -template<typename... Ix> ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); } -template<typename... Ix> ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); } -template<typename... Ix> ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); } -template<typename... Ix> ssize_t at_t(const arr_t& a, Ix... idx) { return a.at(idx...); } +template<typename... Ix> 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) \ @@ -133,7 +133,7 @@ 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"); } +    try { py::module_::import("numpy"); }      catch (...) { return; }      // test_dtypes @@ -159,9 +159,9 @@ TEST_SUBMODULE(numpy_array, sm) {      // test_array_attributes      sm.def("ndim", [](const arr& a) { return a.ndim(); });      sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); }); -    sm.def("shape", [](const arr& a, ssize_t dim) { return a.shape(dim); }); +    sm.def("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, ssize_t dim) { return a.strides(dim); }); +    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(); }); @@ -212,7 +212,7 @@ TEST_SUBMODULE(numpy_array, sm) {          .def(py::init<>())          .def("numpy_view", [](py::object &obj) {              py::print("ArrayClass::numpy_view()"); -            ArrayClass &a = obj.cast<ArrayClass&>(); +            auto &a = obj.cast<ArrayClass&>();              return py::array_t<int>({2}, {4}, a.data, obj);          }      ); @@ -281,33 +281,33 @@ TEST_SUBMODULE(numpy_array, sm) {      // test_array_unchecked_fixed_dims      sm.def("proxy_add2", [](py::array_t<double> a, double v) {          auto r = a.mutable_unchecked<2>(); -        for (ssize_t i = 0; i < r.shape(0); i++) -            for (ssize_t j = 0; j < r.shape(1); j++) +        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 });          auto r = a.mutable_unchecked<3>(); -        for (ssize_t i = 0; i < r.shape(0); i++) -        for (ssize_t j = 0; j < r.shape(1); j++) -        for (ssize_t k = 0; k < r.shape(2); k++) +        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 });          auto r = a.mutable_unchecked<3>(); -        for (ssize_t k = 0; k < r.shape(2); k++) -        for (ssize_t j = 0; j < r.shape(1); j++) -        for (ssize_t i = 0; i < r.shape(0); i++) +        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) {          auto r = a.unchecked<1>();          double sumsq = 0; -        for (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;      }); @@ -318,22 +318,34 @@ TEST_SUBMODULE(numpy_array, sm) {          return auxiliaries(r, r2);      }); +    sm.def("proxy_auxiliaries1_const_ref", [](py::array_t<double> a) { +        const auto &r = a.unchecked<1>(); +        const auto &r2 = a.mutable_unchecked<1>(); +        return r(0) == r2(0) && r[0] == r2[0]; +    }); + +    sm.def("proxy_auxiliaries2_const_ref", [](py::array_t<double> a) { +        const auto &r = a.unchecked<2>(); +        const auto &r2 = a.mutable_unchecked<2>(); +        return r(0, 0) == r2(0, 0); +    }); +      // test_array_unchecked_dyn_dims      // Same as the above, but without a compile-time dimensions specification:      sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) {          auto r = a.mutable_unchecked();          if (r.ndim() != 2) throw std::domain_error("error: ndim != 2"); -        for (ssize_t i = 0; i < r.shape(0); i++) -            for (ssize_t j = 0; j < r.shape(1); j++) +        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 });          auto r = a.mutable_unchecked();          if (r.ndim() != 3) throw std::domain_error("error: ndim != 3"); -        for (ssize_t i = 0; i < r.shape(0); i++) -        for (ssize_t j = 0; j < r.shape(1); j++) -        for (ssize_t k = 0; k < r.shape(2); k++) +        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;      }); @@ -362,7 +374,7 @@ TEST_SUBMODULE(numpy_array, sm) {      // test_array_resize      // reshape array to 2D without changing size      sm.def("array_reshape2", [](py::array_t<double> a) { -        const ssize_t dim_sz = (ssize_t)std::sqrt(a.size()); +        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}); @@ -382,9 +394,45 @@ TEST_SUBMODULE(numpy_array, sm) {          return a;      }); -#if PY_MAJOR_VERSION >= 3 -        sm.def("index_using_ellipsis", [](py::array a) { -            return a[py::make_tuple(0, py::ellipsis(), 0)]; -        }); -#endif +    sm.def("index_using_ellipsis", [](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());  } diff --git a/3rdparty/pybind11/tests/test_numpy_array.py b/3rdparty/pybind11/tests/test_numpy_array.py index d0a6324d..02f3ecfc 100644 --- a/3rdparty/pybind11/tests/test_numpy_array.py +++ b/3rdparty/pybind11/tests/test_numpy_array.py @@ -1,10 +1,11 @@ +# -*- coding: utf-8 -*-  import pytest -from pybind11_tests import numpy_array as m -pytestmark = pytest.requires_numpy +import env  # noqa: F401 + +from pybind11_tests import numpy_array as m -with pytest.suppress(ImportError): -    import numpy as np +np = pytest.importorskip("numpy")  def test_dtypes(): @@ -18,33 +19,36 @@ def test_dtypes():          print(check)          assert check.numpy == check.pybind11, check          if check.numpy.num != check.pybind11.num: -            print("NOTE: typenum mismatch for {}: {} != {}".format( -                check, check.numpy.num, check.pybind11.num)) +            print( +                "NOTE: typenum mismatch for {}: {} != {}".format( +                    check, check.numpy.num, check.pybind11.num +                ) +            ) -@pytest.fixture(scope='function') +@pytest.fixture(scope="function")  def arr(): -    return np.array([[1, 2, 3], [4, 5, 6]], '=u2') +    return np.array([[1, 2, 3], [4, 5, 6]], "=u2")  def test_array_attributes(): -    a = np.array(0, 'f8') +    a = np.array(0, "f8")      assert m.ndim(a) == 0      assert all(m.shape(a) == [])      assert all(m.strides(a) == [])      with pytest.raises(IndexError) as excinfo:          m.shape(a, 0) -    assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)' +    assert str(excinfo.value) == "invalid axis: 0 (ndim = 0)"      with pytest.raises(IndexError) as excinfo:          m.strides(a, 0) -    assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)' +    assert str(excinfo.value) == "invalid axis: 0 (ndim = 0)"      assert m.writeable(a)      assert m.size(a) == 1      assert m.itemsize(a) == 8      assert m.nbytes(a) == 8      assert m.owndata(a) -    a = np.array([[1, 2, 3], [4, 5, 6]], 'u2').view() +    a = np.array([[1, 2, 3], [4, 5, 6]], "u2").view()      a.flags.writeable = False      assert m.ndim(a) == 2      assert all(m.shape(a) == [2, 3]) @@ -55,10 +59,10 @@ def test_array_attributes():      assert m.strides(a, 1) == 2      with pytest.raises(IndexError) as excinfo:          m.shape(a, 2) -    assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)' +    assert str(excinfo.value) == "invalid axis: 2 (ndim = 2)"      with pytest.raises(IndexError) as excinfo:          m.strides(a, 2) -    assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)' +    assert str(excinfo.value) == "invalid axis: 2 (ndim = 2)"      assert not m.writeable(a)      assert m.size(a) == 6      assert m.itemsize(a) == 2 @@ -66,7 +70,9 @@ def test_array_attributes():      assert not m.owndata(a) -@pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)]) +@pytest.mark.parametrize( +    "args, ret", [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)] +)  def test_index_offset(arr, args, ret):      assert m.index_at(arr, *args) == ret      assert m.index_at_t(arr, *args) == ret @@ -75,31 +81,46 @@ def test_index_offset(arr, args, ret):  def test_dim_check_fail(arr): -    for func in (m.index_at, m.index_at_t, m.offset_at, m.offset_at_t, m.data, m.data_t, -                 m.mutate_data, m.mutate_data_t): +    for func in ( +        m.index_at, +        m.index_at_t, +        m.offset_at, +        m.offset_at_t, +        m.data, +        m.data_t, +        m.mutate_data, +        m.mutate_data_t, +    ):          with pytest.raises(IndexError) as excinfo:              func(arr, 1, 2, 3) -        assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)' - - -@pytest.mark.parametrize('args, ret', -                         [([], [1, 2, 3, 4, 5, 6]), -                          ([1], [4, 5, 6]), -                          ([0, 1], [2, 3, 4, 5, 6]), -                          ([1, 2], [6])]) +        assert str(excinfo.value) == "too many indices for an array: 3 (ndim = 2)" + + +@pytest.mark.parametrize( +    "args, ret", +    [ +        ([], [1, 2, 3, 4, 5, 6]), +        ([1], [4, 5, 6]), +        ([0, 1], [2, 3, 4, 5, 6]), +        ([1, 2], [6]), +    ], +)  def test_data(arr, args, ret):      from sys import byteorder +      assert all(m.data_t(arr, *args) == ret) -    assert all(m.data(arr, *args)[(0 if byteorder == 'little' else 1)::2] == ret) -    assert all(m.data(arr, *args)[(1 if byteorder == 'little' else 0)::2] == 0) +    assert all(m.data(arr, *args)[(0 if byteorder == "little" else 1) :: 2] == ret) +    assert all(m.data(arr, *args)[(1 if byteorder == "little" else 0) :: 2] == 0) -@pytest.mark.parametrize('dim', [0, 1, 3]) +@pytest.mark.parametrize("dim", [0, 1, 3])  def test_at_fail(arr, dim):      for func in m.at_t, m.mutate_at_t:          with pytest.raises(IndexError) as excinfo:              func(arr, *([0] * dim)) -        assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim) +        assert str(excinfo.value) == "index dimension mismatch: {} (ndim = 2)".format( +            dim +        )  def test_at(arr): @@ -112,10 +133,14 @@ def test_at(arr):  def test_mutate_readonly(arr):      arr.flags.writeable = False -    for func, args in (m.mutate_data, ()), (m.mutate_data_t, ()), (m.mutate_at_t, (0, 0)): +    for func, args in ( +        (m.mutate_data, ()), +        (m.mutate_data_t, ()), +        (m.mutate_at_t, (0, 0)), +    ):          with pytest.raises(ValueError) as excinfo:              func(arr, *args) -        assert str(excinfo.value) == 'array is not writeable' +        assert str(excinfo.value) == "array is not writeable"  def test_mutate_data(arr): @@ -133,14 +158,22 @@ def test_mutate_data(arr):  def test_bounds_check(arr): -    for func in (m.index_at, m.index_at_t, m.data, m.data_t, -                 m.mutate_data, m.mutate_data_t, m.at_t, m.mutate_at_t): +    for func in ( +        m.index_at, +        m.index_at_t, +        m.data, +        m.data_t, +        m.mutate_data, +        m.mutate_data_t, +        m.at_t, +        m.mutate_at_t, +    ):          with pytest.raises(IndexError) as excinfo:              func(arr, 2, 0) -        assert str(excinfo.value) == 'index 2 is out of bounds for axis 0 with size 2' +        assert str(excinfo.value) == "index 2 is out of bounds for axis 0 with size 2"          with pytest.raises(IndexError) as excinfo:              func(arr, 0, 4) -        assert str(excinfo.value) == 'index 4 is out of bounds for axis 1 with size 3' +        assert str(excinfo.value) == "index 4 is out of bounds for axis 1 with size 3"  def test_make_c_f_array(): @@ -162,10 +195,11 @@ 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 -        assert a.__array_interface__['data'][0] == b.__array_interface__['data'][0] +        assert a.__array_interface__["data"][0] == b.__array_interface__["data"][0]          assert a.shape == b.shape          assert a.strides == b.strides          assert a.flags.c_contiguous == b.flags.c_contiguous @@ -188,12 +222,12 @@ def test_wrap():      a2 = m.wrap(a1)      assert_references(a1, a2) -    a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='F') +    a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order="F")      assert a1.flags.owndata and a1.base is None      a2 = m.wrap(a1)      assert_references(a1, a2) -    a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='C') +    a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order="C")      a1.flags.writeable = False      a2 = m.wrap(a1)      assert_references(a1, a2) @@ -223,11 +257,14 @@ def test_numpy_view(capture):          assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32))          del ac          pytest.gc_collect() -    assert capture == """ +    assert ( +        capture +        == """          ArrayClass()          ArrayClass::numpy_view()          ArrayClass::numpy_view()      """ +    )      ac_view_1[0] = 4      ac_view_1[1] = 3      assert ac_view_2[0] == 4 @@ -237,12 +274,14 @@ def test_numpy_view(capture):          del ac_view_2          pytest.gc_collect()          pytest.gc_collect() -    assert capture == """ +    assert ( +        capture +        == """          ~ArrayClass()      """ +    ) -@pytest.unsupported_on_pypy  def test_cast_numpy_int64_to_uint64():      m.function_taking_uint64(123)      m.function_taking_uint64(np.uint64(123)) @@ -271,89 +310,94 @@ def test_constructors():  def test_overload_resolution(msg):      # Exact overload matches: -    assert m.overloaded(np.array([1], dtype='float64')) == 'double' -    assert m.overloaded(np.array([1], dtype='float32')) == 'float' -    assert m.overloaded(np.array([1], dtype='ushort')) == 'unsigned short' -    assert m.overloaded(np.array([1], dtype='intc')) == 'int' -    assert m.overloaded(np.array([1], dtype='longlong')) == 'long long' -    assert m.overloaded(np.array([1], dtype='complex')) == 'double complex' -    assert m.overloaded(np.array([1], dtype='csingle')) == 'float complex' +    assert m.overloaded(np.array([1], dtype="float64")) == "double" +    assert m.overloaded(np.array([1], dtype="float32")) == "float" +    assert m.overloaded(np.array([1], dtype="ushort")) == "unsigned short" +    assert m.overloaded(np.array([1], dtype="intc")) == "int" +    assert m.overloaded(np.array([1], dtype="longlong")) == "long long" +    assert m.overloaded(np.array([1], dtype="complex")) == "double complex" +    assert m.overloaded(np.array([1], dtype="csingle")) == "float complex"      # No exact match, should call first convertible version: -    assert m.overloaded(np.array([1], dtype='uint8')) == 'double' +    assert m.overloaded(np.array([1], dtype="uint8")) == "double"      with pytest.raises(TypeError) as excinfo:          m.overloaded("not an array") -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          overloaded(): incompatible function arguments. The following argument types are supported: -            1. (arg0: numpy.ndarray[float64]) -> str -            2. (arg0: numpy.ndarray[float32]) -> str -            3. (arg0: numpy.ndarray[int32]) -> str -            4. (arg0: numpy.ndarray[uint16]) -> str -            5. (arg0: numpy.ndarray[int64]) -> str -            6. (arg0: numpy.ndarray[complex128]) -> str -            7. (arg0: numpy.ndarray[complex64]) -> str +            1. (arg0: numpy.ndarray[numpy.float64]) -> str +            2. (arg0: numpy.ndarray[numpy.float32]) -> str +            3. (arg0: numpy.ndarray[numpy.int32]) -> str +            4. (arg0: numpy.ndarray[numpy.uint16]) -> str +            5. (arg0: numpy.ndarray[numpy.int64]) -> str +            6. (arg0: numpy.ndarray[numpy.complex128]) -> str +            7. (arg0: numpy.ndarray[numpy.complex64]) -> str          Invoked with: 'not an array'      """ +    ) -    assert m.overloaded2(np.array([1], dtype='float64')) == 'double' -    assert m.overloaded2(np.array([1], dtype='float32')) == 'float' -    assert m.overloaded2(np.array([1], dtype='complex64')) == 'float complex' -    assert m.overloaded2(np.array([1], dtype='complex128')) == 'double complex' -    assert m.overloaded2(np.array([1], dtype='float32')) == 'float' +    assert m.overloaded2(np.array([1], dtype="float64")) == "double" +    assert m.overloaded2(np.array([1], dtype="float32")) == "float" +    assert m.overloaded2(np.array([1], dtype="complex64")) == "float complex" +    assert m.overloaded2(np.array([1], dtype="complex128")) == "double complex" +    assert m.overloaded2(np.array([1], dtype="float32")) == "float" -    assert m.overloaded3(np.array([1], dtype='float64')) == 'double' -    assert m.overloaded3(np.array([1], dtype='intc')) == 'int' +    assert m.overloaded3(np.array([1], dtype="float64")) == "double" +    assert m.overloaded3(np.array([1], dtype="intc")) == "int"      expected_exc = """          overloaded3(): incompatible function arguments. The following argument types are supported: -            1. (arg0: numpy.ndarray[int32]) -> str -            2. (arg0: numpy.ndarray[float64]) -> str +            1. (arg0: numpy.ndarray[numpy.int32]) -> str +            2. (arg0: numpy.ndarray[numpy.float64]) -> str          Invoked with: """      with pytest.raises(TypeError) as excinfo: -        m.overloaded3(np.array([1], dtype='uintc')) -    assert msg(excinfo.value) == expected_exc + repr(np.array([1], dtype='uint32')) +        m.overloaded3(np.array([1], dtype="uintc")) +    assert msg(excinfo.value) == expected_exc + repr(np.array([1], dtype="uint32"))      with pytest.raises(TypeError) as excinfo: -        m.overloaded3(np.array([1], dtype='float32')) -    assert msg(excinfo.value) == expected_exc + repr(np.array([1.], dtype='float32')) +        m.overloaded3(np.array([1], dtype="float32")) +    assert msg(excinfo.value) == expected_exc + repr(np.array([1.0], dtype="float32"))      with pytest.raises(TypeError) as excinfo: -        m.overloaded3(np.array([1], dtype='complex')) -    assert msg(excinfo.value) == expected_exc + repr(np.array([1. + 0.j])) +        m.overloaded3(np.array([1], dtype="complex")) +    assert msg(excinfo.value) == expected_exc + repr(np.array([1.0 + 0.0j]))      # Exact matches: -    assert m.overloaded4(np.array([1], dtype='double')) == 'double' -    assert m.overloaded4(np.array([1], dtype='longlong')) == 'long long' +    assert m.overloaded4(np.array([1], dtype="double")) == "double" +    assert m.overloaded4(np.array([1], dtype="longlong")) == "long long"      # Non-exact matches requiring conversion.  Since float to integer isn't a      # save conversion, it should go to the double overload, but short can go to      # either (and so should end up on the first-registered, the long long). -    assert m.overloaded4(np.array([1], dtype='float32')) == 'double' -    assert m.overloaded4(np.array([1], dtype='short')) == 'long long' +    assert m.overloaded4(np.array([1], dtype="float32")) == "double" +    assert m.overloaded4(np.array([1], dtype="short")) == "long long" -    assert m.overloaded5(np.array([1], dtype='double')) == 'double' -    assert m.overloaded5(np.array([1], dtype='uintc')) == 'unsigned int' -    assert m.overloaded5(np.array([1], dtype='float32')) == 'unsigned int' +    assert m.overloaded5(np.array([1], dtype="double")) == "double" +    assert m.overloaded5(np.array([1], dtype="uintc")) == "unsigned int" +    assert m.overloaded5(np.array([1], dtype="float32")) == "unsigned int"  def test_greedy_string_overload():      """Tests fix for #685 - ndarray shouldn't go to std::string overload"""      assert m.issue685("abc") == "string" -    assert m.issue685(np.array([97, 98, 99], dtype='b')) == "array" +    assert m.issue685(np.array([97, 98, 99], dtype="b")) == "array"      assert m.issue685(123) == "other"  def test_array_unchecked_fixed_dims(msg): -    z1 = np.array([[1, 2], [3, 4]], dtype='float64') +    z1 = np.array([[1, 2], [3, 4]], dtype="float64")      m.proxy_add2(z1, 10)      assert np.all(z1 == [[11, 12], [13, 14]])      with pytest.raises(ValueError) as excinfo: -        m.proxy_add2(np.array([1., 2, 3]), 5.0) -    assert msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2" +        m.proxy_add2(np.array([1.0, 2, 3]), 5.0) +    assert ( +        msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2" +    ) -    expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int') +    expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype="int")      assert np.all(m.proxy_init3(3.0) == expect_c)      expect_f = np.transpose(expect_c)      assert np.all(m.proxy_init3F(3.0) == expect_f) @@ -364,13 +408,16 @@ def test_array_unchecked_fixed_dims(msg):      assert m.proxy_auxiliaries2(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]      assert m.proxy_auxiliaries2(z1) == m.array_auxiliaries2(z1) +    assert m.proxy_auxiliaries1_const_ref(z1[0, :]) +    assert m.proxy_auxiliaries2_const_ref(z1) +  def test_array_unchecked_dyn_dims(msg): -    z1 = np.array([[1, 2], [3, 4]], dtype='float64') +    z1 = np.array([[1, 2], [3, 4]], dtype="float64")      m.proxy_add2_dyn(z1, 10)      assert np.all(z1 == [[11, 12], [13, 14]]) -    expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int') +    expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype="int")      assert np.all(m.proxy_init3_dyn(3.0) == expect_c)      assert m.proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32] @@ -380,15 +427,15 @@ def test_array_unchecked_dyn_dims(msg):  def test_array_failure():      with pytest.raises(ValueError) as excinfo:          m.array_fail_test() -    assert str(excinfo.value) == 'cannot create a pybind11::array from a nullptr' +    assert str(excinfo.value) == "cannot create a pybind11::array from a nullptr"      with pytest.raises(ValueError) as excinfo:          m.array_t_fail_test() -    assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr' +    assert str(excinfo.value) == "cannot create a pybind11::array_t from a nullptr"      with pytest.raises(ValueError) as excinfo:          m.array_fail_test_negative_size() -    assert str(excinfo.value) == 'negative dimensions are not allowed' +    assert str(excinfo.value) == "negative dimensions are not allowed"  def test_initializer_list(): @@ -399,46 +446,93 @@ def test_initializer_list():  def test_array_resize(msg): -    a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='float64') +    a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype="float64")      m.array_reshape2(a) -    assert(a.size == 9) -    assert(np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]])) +    assert a.size == 9 +    assert np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]])      # total size change should succced with refcheck off      m.array_resize3(a, 4, False) -    assert(a.size == 64) +    assert a.size == 64      # ... and fail with refcheck on      try:          m.array_resize3(a, 3, True)      except ValueError as e: -        assert(str(e).startswith("cannot resize an array")) +        assert str(e).startswith("cannot resize an array")      # transposed array doesn't own data      b = a.transpose()      try:          m.array_resize3(b, 3, False)      except ValueError as e: -        assert(str(e).startswith("cannot resize this array: it does not own its data")) +        assert str(e).startswith("cannot resize this array: it does not own its data")      # ... but reshape should be fine      m.array_reshape2(b) -    assert(b.shape == (8, 8)) +    assert b.shape == (8, 8) -@pytest.unsupported_on_pypy +@pytest.mark.xfail("env.PYPY")  def test_array_create_and_resize(msg):      a = m.create_and_resize(2) -    assert(a.size == 4) -    assert(np.all(a == 42.)) +    assert a.size == 4 +    assert np.all(a == 42.0) -@pytest.unsupported_on_py2  def test_index_using_ellipsis():      a = m.index_using_ellipsis(np.zeros((5, 6, 7)))      assert a.shape == (6,) -@pytest.unsupported_on_pypy +@pytest.mark.parametrize("forcecast", [False, True]) +@pytest.mark.parametrize("contiguity", [None, "C", "F"]) +@pytest.mark.parametrize("noconvert", [False, True]) +@pytest.mark.filterwarnings( +    "ignore:Casting complex values to real discards the imaginary part:numpy.ComplexWarning" +) +def test_argument_conversions(forcecast, contiguity, noconvert): +    function_name = "accept_double" +    if contiguity == "C": +        function_name += "_c_style" +    elif contiguity == "F": +        function_name += "_f_style" +    if forcecast: +        function_name += "_forcecast" +    if noconvert: +        function_name += "_noconvert" +    function = getattr(m, function_name) + +    for dtype in [np.dtype("float32"), np.dtype("float64"), np.dtype("complex128")]: +        for order in ["C", "F"]: +            for shape in [(2, 2), (1, 3, 1, 1), (1, 1, 1), (0,)]: +                if not noconvert: +                    # If noconvert is not passed, only complex128 needs to be truncated and +                    # "cannot be safely obtained". So without `forcecast`, the argument shouldn't +                    # be accepted. +                    should_raise = dtype.name == "complex128" and not forcecast +                else: +                    # If noconvert is passed, only float64 and the matching order is accepted. +                    # If at most one dimension has a size greater than 1, the array is also +                    # trivially contiguous. +                    trivially_contiguous = sum(1 for d in shape if d > 1) <= 1 +                    should_raise = dtype.name != "float64" or ( +                        contiguity is not None +                        and contiguity != order +                        and not trivially_contiguous +                    ) + +                array = np.zeros(shape, dtype=dtype, order=order) +                if not should_raise: +                    function(array) +                else: +                    with pytest.raises( +                        TypeError, match="incompatible function arguments" +                    ): +                        function(array) + + +@pytest.mark.xfail("env.PYPY")  def test_dtype_refcount_leak():      from sys import getrefcount +      dtype = np.dtype(np.float_)      a = np.array([1], dtype=dtype)      before = getrefcount(dtype) diff --git a/3rdparty/pybind11/tests/test_numpy_dtypes.cpp b/3rdparty/pybind11/tests/test_numpy_dtypes.cpp index 467e0253..b2e5e607 100644 --- a/3rdparty/pybind11/tests/test_numpy_dtypes.cpp +++ b/3rdparty/pybind11/tests/test_numpy_dtypes.cpp @@ -168,7 +168,7 @@ py::list print_recarray(py::array_t<S, 0> arr) {      const auto req = arr.request();      const auto ptr = static_cast<S*>(req.ptr);      auto l = py::list(); -    for (ssize_t i = 0; i < req.size; i++) { +    for (py::ssize_t i = 0; i < req.size; i++) {          std::stringstream ss;          ss << ptr[i];          l.append(py::str(ss.str())); @@ -180,8 +180,8 @@ py::array_t<int32_t, 0> test_array_ctors(int i) {      using arr_t = py::array_t<int32_t, 0>;      std::vector<int32_t> data { 1, 2, 3, 4, 5, 6 }; -    std::vector<ssize_t> shape { 3, 2 }; -    std::vector<ssize_t> strides { 8, 4 }; +    std::vector<py::ssize_t> shape { 3, 2 }; +    std::vector<py::ssize_t> strides { 8, 4 };      auto ptr = data.data();      auto vptr = (void *) ptr; @@ -255,11 +255,30 @@ struct A {};  struct B {};  TEST_SUBMODULE(numpy_dtypes, m) { -    try { py::module::import("numpy"); } +    try { py::module_::import("numpy"); }      catch (...) { return; }      // typeinfo may be registered before the dtype descriptor for scalar casts to work... -    py::class_<SimpleStruct>(m, "SimpleStruct"); +    py::class_<SimpleStruct>(m, "SimpleStruct") +        // Explicit construct to ensure zero-valued initialization. +        .def(py::init([]() { return SimpleStruct(); })) +        .def_readwrite("bool_", &SimpleStruct::bool_) +        .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) { +            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>()}; +        });      PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_);      PYBIND11_NUMPY_DTYPE(SimpleStructReordered, bool_, uint_, float_, ldbl_); @@ -379,7 +398,7 @@ TEST_SUBMODULE(numpy_dtypes, m) {          if (non_empty) {              auto req = arr.request();              auto ptr = static_cast<StringStruct*>(req.ptr); -            for (ssize_t i = 0; i < req.size * req.itemsize; i++) +            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'; @@ -462,10 +481,16 @@ TEST_SUBMODULE(numpy_dtypes, m) {      m.def("buffer_to_dtype", [](py::buffer& buf) { return py::dtype(buf.request()); });      // test_scalar_conversion -    m.def("f_simple", [](SimpleStruct s) { return s.uint_ * 10; }); +    auto f_simple = [](SimpleStruct s) { return s.uint_ * 10; }; +    m.def("f_simple", f_simple);      m.def("f_packed", [](PackedStruct s) { return s.uint_ * 10; });      m.def("f_nested", [](NestedStruct s) { return s.a.uint_ * 10; }); +    // test_vectorize +    m.def("f_simple_vectorized", py::vectorize(f_simple)); +    auto f_simple_pass_thru = [](SimpleStruct s) { return s; }; +    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_); }); diff --git a/3rdparty/pybind11/tests/test_numpy_dtypes.py b/3rdparty/pybind11/tests/test_numpy_dtypes.py index 2e638851..f56b776a 100644 --- a/3rdparty/pybind11/tests/test_numpy_dtypes.py +++ b/3rdparty/pybind11/tests/test_numpy_dtypes.py @@ -1,64 +1,80 @@ +# -*- coding: utf-8 -*-  import re +  import pytest -from pybind11_tests import numpy_dtypes as m -pytestmark = pytest.requires_numpy +import env  # noqa: F401 -with pytest.suppress(ImportError): -    import numpy as np +from pybind11_tests import numpy_dtypes as m +np = pytest.importorskip("numpy") -@pytest.fixture(scope='module') + +@pytest.fixture(scope="module")  def simple_dtype(): -    ld = np.dtype('longdouble') -    return np.dtype({'names': ['bool_', 'uint_', 'float_', 'ldbl_'], -                     'formats': ['?', 'u4', 'f4', 'f{}'.format(ld.itemsize)], -                     'offsets': [0, 4, 8, (16 if ld.alignment > 4 else 12)]}) +    ld = np.dtype("longdouble") +    return np.dtype( +        { +            "names": ["bool_", "uint_", "float_", "ldbl_"], +            "formats": ["?", "u4", "f4", "f{}".format(ld.itemsize)], +            "offsets": [0, 4, 8, (16 if ld.alignment > 4 else 12)], +        } +    ) -@pytest.fixture(scope='module') +@pytest.fixture(scope="module")  def packed_dtype(): -    return np.dtype([('bool_', '?'), ('uint_', 'u4'), ('float_', 'f4'), ('ldbl_', 'g')]) +    return np.dtype([("bool_", "?"), ("uint_", "u4"), ("float_", "f4"), ("ldbl_", "g")])  def dt_fmt():      from sys import byteorder -    e = '<' if byteorder == 'little' else '>' -    return ("{{'names':['bool_','uint_','float_','ldbl_']," -            " 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}']," -            " 'offsets':[0,4,8,{}], 'itemsize':{}}}") + +    e = "<" if byteorder == "little" else ">" +    return ( +        "{{'names':['bool_','uint_','float_','ldbl_']," +        " 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}']," +        " 'offsets':[0,4,8,{}], 'itemsize':{}}}" +    )  def simple_dtype_fmt(): -    ld = np.dtype('longdouble') +    ld = np.dtype("longdouble")      simple_ld_off = 12 + 4 * (ld.alignment > 4)      return dt_fmt().format(ld.itemsize, simple_ld_off, simple_ld_off + ld.itemsize)  def packed_dtype_fmt():      from sys import byteorder +      return "[('bool_', '?'), ('uint_', '{e}u4'), ('float_', '{e}f4'), ('ldbl_', '{e}f{}')]".format( -        np.dtype('longdouble').itemsize, e='<' if byteorder == 'little' else '>') +        np.dtype("longdouble").itemsize, e="<" if byteorder == "little" else ">" +    )  def partial_ld_offset(): -    return 12 + 4 * (np.dtype('uint64').alignment > 4) + 8 + 8 * ( -        np.dtype('longdouble').alignment > 8) +    return ( +        12 +        + 4 * (np.dtype("uint64").alignment > 4) +        + 8 +        + 8 * (np.dtype("longdouble").alignment > 8) +    )  def partial_dtype_fmt(): -    ld = np.dtype('longdouble') +    ld = np.dtype("longdouble")      partial_ld_off = partial_ld_offset()      return dt_fmt().format(ld.itemsize, partial_ld_off, partial_ld_off + ld.itemsize)  def partial_nested_fmt(): -    ld = np.dtype('longdouble') +    ld = np.dtype("longdouble")      partial_nested_off = 8 + 8 * (ld.alignment > 8)      partial_ld_off = partial_ld_offset()      partial_nested_size = partial_nested_off * 2 + partial_ld_off + ld.itemsize      return "{{'names':['a'], 'formats':[{}], 'offsets':[{}], 'itemsize':{}}}".format( -        partial_dtype_fmt(), partial_nested_off, partial_nested_size) +        partial_dtype_fmt(), partial_nested_off, partial_nested_size +    )  def assert_equal(actual, expected_data, expected_dtype): @@ -68,15 +84,19 @@ def assert_equal(actual, expected_data, expected_dtype):  def test_format_descriptors():      with pytest.raises(RuntimeError) as excinfo:          m.get_format_unbound() -    assert re.match('^NumPy type info missing for .*UnboundStruct.*$', str(excinfo.value)) +    assert re.match( +        "^NumPy type info missing for .*UnboundStruct.*$", str(excinfo.value) +    ) -    ld = np.dtype('longdouble') -    ldbl_fmt = ('4x' if ld.alignment > 4 else '') + ld.char +    ld = np.dtype("longdouble") +    ldbl_fmt = ("4x" if ld.alignment > 4 else "") + ld.char      ss_fmt = "^T{?:bool_:3xI:uint_:f:float_:" + ldbl_fmt + ":ldbl_:}" -    dbl = np.dtype('double') -    partial_fmt = ("^T{?:bool_:3xI:uint_:f:float_:" + -                   str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) + -                   "xg:ldbl_:}") +    dbl = np.dtype("double") +    partial_fmt = ( +        "^T{?:bool_:3xI:uint_:f:float_:" +        + str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) +        + "xg:ldbl_:}" +    )      nested_extra = str(max(8, ld.alignment))      assert m.print_format_descriptors() == [          ss_fmt, @@ -86,14 +106,15 @@ def test_format_descriptors():          "^T{" + nested_extra + "x" + partial_fmt + ":a:" + nested_extra + "x}",          "^T{3s:a:3s:b:}",          "^T{(3)4s:a:(2)i:b:(3)B:c:1x(4, 2)f:d:}", -        '^T{q:e1:B:e2:}', -        '^T{Zf:cflt:Zd:cdbl:}' +        "^T{q:e1:B:e2:}", +        "^T{Zf:cflt:Zd:cdbl:}",      ]  def test_dtype(simple_dtype):      from sys import byteorder -    e = '<' if byteorder == 'little' else '>' + +    e = "<" if byteorder == "little" else ">"      assert m.print_dtypes() == [          simple_dtype_fmt(), @@ -102,30 +123,60 @@ def test_dtype(simple_dtype):          partial_dtype_fmt(),          partial_nested_fmt(),          "[('a', 'S3'), ('b', 'S3')]", -        ("{{'names':['a','b','c','d'], " + -         "'formats':[('S4', (3,)),('" + e + "i4', (2,)),('u1', (3,)),('" + e + "f4', (4, 2))], " + -         "'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e), +        ( +            "{{'names':['a','b','c','d'], " +            + "'formats':[('S4', (3,)),('" +            + e +            + "i4', (2,)),('u1', (3,)),('" +            + e +            + "f4', (4, 2))], " +            + "'offsets':[0,12,20,24], 'itemsize':56}}" +        ).format(e=e),          "[('e1', '" + e + "i8'), ('e2', 'u1')]",          "[('x', 'i1'), ('y', '" + e + "u8')]", -        "[('cflt', '" + e + "c8'), ('cdbl', '" + e + "c16')]" +        "[('cflt', '" + e + "c8'), ('cdbl', '" + e + "c16')]",      ] -    d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'], -                   'offsets': [1, 10], 'itemsize': 20}) -    d2 = np.dtype([('a', 'i4'), ('b', 'f4')]) -    assert m.test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'), -                                    np.dtype('bool'), d1, d1, np.dtype('uint32'), d2] +    d1 = np.dtype( +        { +            "names": ["a", "b"], +            "formats": ["int32", "float64"], +            "offsets": [1, 10], +            "itemsize": 20, +        } +    ) +    d2 = np.dtype([("a", "i4"), ("b", "f4")]) +    assert m.test_dtype_ctors() == [ +        np.dtype("int32"), +        np.dtype("float64"), +        np.dtype("bool"), +        d1, +        d1, +        np.dtype("uint32"), +        d2, +    ] -    assert m.test_dtype_methods() == [np.dtype('int32'), simple_dtype, False, True, -                                      np.dtype('int32').itemsize, simple_dtype.itemsize] +    assert m.test_dtype_methods() == [ +        np.dtype("int32"), +        simple_dtype, +        False, +        True, +        np.dtype("int32").itemsize, +        simple_dtype.itemsize, +    ] -    assert m.trailing_padding_dtype() == m.buffer_to_dtype(np.zeros(1, m.trailing_padding_dtype())) +    assert m.trailing_padding_dtype() == m.buffer_to_dtype( +        np.zeros(1, m.trailing_padding_dtype()) +    )  def test_recarray(simple_dtype, packed_dtype):      elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)] -    for func, dtype in [(m.create_rec_simple, simple_dtype), (m.create_rec_packed, packed_dtype)]: +    for func, dtype in [ +        (m.create_rec_simple, simple_dtype), +        (m.create_rec_packed, packed_dtype), +    ]:          arr = func(0)          assert arr.dtype == dtype          assert_equal(arr, [], simple_dtype) @@ -136,20 +187,24 @@ def test_recarray(simple_dtype, packed_dtype):          assert_equal(arr, elements, simple_dtype)          assert_equal(arr, elements, packed_dtype) +        # Show what recarray's look like in NumPy. +        assert type(arr[0]) == np.void +        assert type(arr[0].item()) == tuple +          if dtype == simple_dtype:              assert m.print_rec_simple(arr) == [                  "s:0,0,0,-0",                  "s:1,1,1.5,-2.5", -                "s:0,2,3,-5" +                "s:0,2,3,-5",              ]          else:              assert m.print_rec_packed(arr) == [                  "p:0,0,0,-0",                  "p:1,1,1.5,-2.5", -                "p:0,2,3,-5" +                "p:0,2,3,-5",              ] -    nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)]) +    nested_dtype = np.dtype([("a", simple_dtype), ("b", packed_dtype)])      arr = m.create_rec_nested(0)      assert arr.dtype == nested_dtype @@ -157,33 +212,39 @@ def test_recarray(simple_dtype, packed_dtype):      arr = m.create_rec_nested(3)      assert arr.dtype == nested_dtype -    assert_equal(arr, [((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)), -                       ((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)), -                       ((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5))], nested_dtype) +    assert_equal( +        arr, +        [ +            ((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)), +            ((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)), +            ((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5)), +        ], +        nested_dtype, +    )      assert m.print_rec_nested(arr) == [          "n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5",          "n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5", -        "n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5" +        "n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5",      ]      arr = m.create_rec_partial(3)      assert str(arr.dtype) == partial_dtype_fmt()      partial_dtype = arr.dtype -    assert '' not in arr.dtype.fields +    assert "" not in arr.dtype.fields      assert partial_dtype.itemsize > simple_dtype.itemsize      assert_equal(arr, elements, simple_dtype)      assert_equal(arr, elements, packed_dtype)      arr = m.create_rec_partial_nested(3)      assert str(arr.dtype) == partial_nested_fmt() -    assert '' not in arr.dtype.fields -    assert '' not in arr.dtype.fields['a'][0].fields +    assert "" not in arr.dtype.fields +    assert "" not in arr.dtype.fields["a"][0].fields      assert arr.dtype.itemsize > partial_dtype.itemsize -    np.testing.assert_equal(arr['a'], m.create_rec_partial(3)) +    np.testing.assert_equal(arr["a"], m.create_rec_partial(3))  def test_array_constructors(): -    data = np.arange(1, 7, dtype='int32') +    data = np.arange(1, 7, dtype="int32")      for i in range(8):          np.testing.assert_array_equal(m.test_array_ctors(10 + i), data.reshape((3, 2)))          np.testing.assert_array_equal(m.test_array_ctors(20 + i), data.reshape((3, 2))) @@ -199,82 +260,92 @@ def test_string_array():          "a='',b=''",          "a='a',b='a'",          "a='ab',b='ab'", -        "a='abc',b='abc'" +        "a='abc',b='abc'",      ]      dtype = arr.dtype -    assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc'] -    assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc'] +    assert arr["a"].tolist() == [b"", b"a", b"ab", b"abc"] +    assert arr["b"].tolist() == [b"", b"a", b"ab", b"abc"]      arr = m.create_string_array(False)      assert dtype == arr.dtype  def test_array_array():      from sys import byteorder -    e = '<' if byteorder == 'little' else '>' + +    e = "<" if byteorder == "little" else ">"      arr = m.create_array_array(3)      assert str(arr.dtype) == ( -        "{{'names':['a','b','c','d'], " + -        "'formats':[('S4', (3,)),('" + e + "i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], " + -        "'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e) +        "{{'names':['a','b','c','d'], " +        + "'formats':[('S4', (3,)),('" +        + e +        + "i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], " +        + "'offsets':[0,12,20,24], 'itemsize':56}}" +    ).format(e=e)      assert m.print_array_array(arr) == [ -        "a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," + -        "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}", -        "a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," + -        "c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}", -        "a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001}," + -        "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}", +        "a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," +        + "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}", +        "a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," +        + "c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}", +        "a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001}," +        + "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}", +    ] +    assert arr["a"].tolist() == [ +        [b"ABCD", b"KLMN", b"UVWX"], +        [b"WXYZ", b"GHIJ", b"QRST"], +        [b"STUV", b"CDEF", b"MNOP"],      ] -    assert arr['a'].tolist() == [[b'ABCD', b'KLMN', b'UVWX'], -                                 [b'WXYZ', b'GHIJ', b'QRST'], -                                 [b'STUV', b'CDEF', b'MNOP']] -    assert arr['b'].tolist() == [[0, 1], [1000, 1001], [2000, 2001]] +    assert arr["b"].tolist() == [[0, 1], [1000, 1001], [2000, 2001]]      assert m.create_array_array(0).dtype == arr.dtype  def test_enum_array():      from sys import byteorder -    e = '<' if byteorder == 'little' else '>' + +    e = "<" if byteorder == "little" else ">"      arr = m.create_enum_array(3)      dtype = arr.dtype -    assert dtype == np.dtype([('e1', e + 'i8'), ('e2', 'u1')]) -    assert m.print_enum_array(arr) == [ -        "e1=A,e2=X", -        "e1=B,e2=Y", -        "e1=A,e2=X" -    ] -    assert arr['e1'].tolist() == [-1, 1, -1] -    assert arr['e2'].tolist() == [1, 2, 1] +    assert dtype == np.dtype([("e1", e + "i8"), ("e2", "u1")]) +    assert m.print_enum_array(arr) == ["e1=A,e2=X", "e1=B,e2=Y", "e1=A,e2=X"] +    assert arr["e1"].tolist() == [-1, 1, -1] +    assert arr["e2"].tolist() == [1, 2, 1]      assert m.create_enum_array(0).dtype == dtype  def test_complex_array():      from sys import byteorder -    e = '<' if byteorder == 'little' else '>' + +    e = "<" if byteorder == "little" else ">"      arr = m.create_complex_array(3)      dtype = arr.dtype -    assert dtype == np.dtype([('cflt', e + 'c8'), ('cdbl', e + 'c16')]) +    assert dtype == np.dtype([("cflt", e + "c8"), ("cdbl", e + "c16")])      assert m.print_complex_array(arr) == [          "c:(0,0.25),(0.5,0.75)",          "c:(1,1.25),(1.5,1.75)", -        "c:(2,2.25),(2.5,2.75)" +        "c:(2,2.25),(2.5,2.75)",      ] -    assert arr['cflt'].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j] -    assert arr['cdbl'].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j] +    assert arr["cflt"].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j] +    assert arr["cdbl"].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j]      assert m.create_complex_array(0).dtype == dtype  def test_signature(doc): -    assert doc(m.create_rec_nested) == \ -        "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]" +    assert ( +        doc(m.create_rec_nested) +        == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]" +    )  def test_scalar_conversion():      n = 3 -    arrays = [m.create_rec_simple(n), m.create_rec_packed(n), -              m.create_rec_nested(n), m.create_enum_array(n)] +    arrays = [ +        m.create_rec_simple(n), +        m.create_rec_packed(n), +        m.create_rec_nested(n), +        m.create_enum_array(n), +    ]      funcs = [m.f_simple, m.f_packed, m.f_nested]      for i, func in enumerate(funcs): @@ -284,18 +355,68 @@ def test_scalar_conversion():              else:                  with pytest.raises(TypeError) as excinfo:                      func(arr[0]) -                assert 'incompatible function arguments' in str(excinfo.value) +                assert "incompatible function arguments" in str(excinfo.value) + + +def test_vectorize(): +    n = 3 +    array = m.create_rec_simple(n) +    values = m.f_simple_vectorized(array) +    np.testing.assert_array_equal(values, [0, 10, 20]) +    array_2 = m.f_simple_pass_thru_vectorized(array) +    np.testing.assert_array_equal(array, array_2) + + +def test_cls_and_dtype_conversion(simple_dtype): +    s = m.SimpleStruct() +    assert s.astuple() == (False, 0, 0.0, 0.0) +    assert m.SimpleStruct.fromtuple(s.astuple()).astuple() == s.astuple() + +    s.uint_ = 2 +    assert m.f_simple(s) == 20 + +    # Try as recarray of shape==(1,). +    s_recarray = np.array([(False, 2, 0.0, 0.0)], dtype=simple_dtype) +    # Show that this will work for vectorized case. +    np.testing.assert_array_equal(m.f_simple_vectorized(s_recarray), [20]) + +    # Show as a scalar that inherits from np.generic. +    s_scalar = s_recarray[0] +    assert isinstance(s_scalar, np.void) +    assert m.f_simple(s_scalar) == 20 + +    # Show that an *array* scalar (np.ndarray.shape == ()) does not convert. +    # More specifically, conversion to SimpleStruct is not implicit. +    s_recarray_scalar = s_recarray.reshape(()) +    assert isinstance(s_recarray_scalar, np.ndarray) +    assert s_recarray_scalar.dtype == simple_dtype +    with pytest.raises(TypeError) as excinfo: +        m.f_simple(s_recarray_scalar) +    assert "incompatible function arguments" in str(excinfo.value) +    # Explicitly convert to m.SimpleStruct. +    assert m.f_simple(m.SimpleStruct.fromtuple(s_recarray_scalar.item())) == 20 + +    # Show that an array of dtype=object does *not* convert. +    s_array_object = np.array([s]) +    assert s_array_object.dtype == object +    with pytest.raises(TypeError) as excinfo: +        m.f_simple_vectorized(s_array_object) +    assert "incompatible function arguments" in str(excinfo.value) +    # Explicitly convert to `np.array(..., dtype=simple_dtype)` +    s_array = np.array([s.astuple()], dtype=simple_dtype) +    np.testing.assert_array_equal(m.f_simple_vectorized(s_array), [20])  def test_register_dtype():      with pytest.raises(RuntimeError) as excinfo:          m.register_dtype() -    assert 'dtype is already registered' in str(excinfo.value) +    assert "dtype is already registered" in str(excinfo.value) -@pytest.unsupported_on_pypy +@pytest.mark.xfail("env.PYPY")  def test_str_leak():      from sys import getrefcount +      fmt = "f4"      pytest.gc_collect()      start = getrefcount(fmt) diff --git a/3rdparty/pybind11/tests/test_numpy_vectorize.cpp b/3rdparty/pybind11/tests/test_numpy_vectorize.cpp index a875a74b..274b7558 100644 --- a/3rdparty/pybind11/tests/test_numpy_vectorize.cpp +++ b/3rdparty/pybind11/tests/test_numpy_vectorize.cpp @@ -17,7 +17,7 @@ double my_func(int x, float y, double z) {  }  TEST_SUBMODULE(numpy_vectorize, m) { -    try { py::module::import("numpy"); } +    try { py::module_::import("numpy"); }      catch (...) { return; }      // test_vectorize, test_docs, test_array_collapse @@ -37,7 +37,7 @@ TEST_SUBMODULE(numpy_vectorize, m) {      ));      // test_type_selection -    // Numpy function which only accepts specific data types +    // 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."; }); @@ -50,7 +50,9 @@ TEST_SUBMODULE(numpy_vectorize, m) {          NonPODClass(int v) : value{v} {}          int value;      }; -    py::class_<NonPODClass>(m, "NonPODClass").def(py::init<int>()); +    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; @@ -81,9 +83,11 @@ TEST_SUBMODULE(numpy_vectorize, m) {                  py::array_t<float, py::array::forcecast> arg2,                  py::array_t<double, py::array::forcecast> arg3                  ) { -        ssize_t ndim; -        std::vector<ssize_t> shape; +        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("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 0e9c8839..4e6b2d19 100644 --- a/3rdparty/pybind11/tests/test_numpy_vectorize.py +++ b/3rdparty/pybind11/tests/test_numpy_vectorize.py @@ -1,10 +1,8 @@ +# -*- coding: utf-8 -*-  import pytest  from pybind11_tests import numpy_vectorize as m -pytestmark = pytest.requires_numpy - -with pytest.suppress(ImportError): -    import numpy as np +np = pytest.importorskip("numpy")  def test_vectorize(capture): @@ -19,28 +17,40 @@ def test_vectorize(capture):          assert capture == "my_func(x:int=1, y:float=2, z:float=3)"          with capture:              assert np.allclose(f(np.array([1, 3]), np.array([2, 4]), 3), [6, 36]) -        assert capture == """ +        assert ( +            capture +            == """              my_func(x:int=1, y:float=2, z:float=3)              my_func(x:int=3, y:float=4, z:float=3)          """ +        )          with capture: -            a = np.array([[1, 2], [3, 4]], order='F') -            b = np.array([[10, 20], [30, 40]], order='F') +            a = np.array([[1, 2], [3, 4]], order="F") +            b = np.array([[10, 20], [30, 40]], order="F")              c = 3              result = f(a, b, c)              assert np.allclose(result, a * b * c)              assert result.flags.f_contiguous          # All inputs are F order and full or singletons, so we the result is in col-major order: -        assert capture == """ +        assert ( +            capture +            == """              my_func(x:int=1, y:float=10, z:float=3)              my_func(x:int=3, y:float=30, z:float=3)              my_func(x:int=2, y:float=20, z:float=3)              my_func(x:int=4, y:float=40, z:float=3)          """ +        )          with capture: -            a, b, c = np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3 +            a, b, c = ( +                np.array([[1, 3, 5], [7, 9, 11]]), +                np.array([[2, 4, 6], [8, 10, 12]]), +                3, +            )              assert np.allclose(f(a, b, c), a * b * c) -        assert capture == """ +        assert ( +            capture +            == """              my_func(x:int=1, y:float=2, z:float=3)              my_func(x:int=3, y:float=4, z:float=3)              my_func(x:int=5, y:float=6, z:float=3) @@ -48,10 +58,13 @@ def test_vectorize(capture):              my_func(x:int=9, y:float=10, z:float=3)              my_func(x:int=11, y:float=12, z:float=3)          """ +        )          with capture:              a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2              assert np.allclose(f(a, b, c), a * b * c) -        assert capture == """ +        assert ( +            capture +            == """              my_func(x:int=1, y:float=2, z:float=2)              my_func(x:int=2, y:float=3, z:float=2)              my_func(x:int=3, y:float=4, z:float=2) @@ -59,10 +72,13 @@ def test_vectorize(capture):              my_func(x:int=5, y:float=3, z:float=2)              my_func(x:int=6, y:float=4, z:float=2)          """ +        )          with capture:              a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2              assert np.allclose(f(a, b, c), a * b * c) -        assert capture == """ +        assert ( +            capture +            == """              my_func(x:int=1, y:float=2, z:float=2)              my_func(x:int=2, y:float=2, z:float=2)              my_func(x:int=3, y:float=2, z:float=2) @@ -70,10 +86,17 @@ def test_vectorize(capture):              my_func(x:int=5, y:float=3, z:float=2)              my_func(x:int=6, y:float=3, z:float=2)          """ +        )          with capture: -            a, b, c = np.array([[1, 2, 3], [4, 5, 6]], order='F'), np.array([[2], [3]]), 2 +            a, b, c = ( +                np.array([[1, 2, 3], [4, 5, 6]], order="F"), +                np.array([[2], [3]]), +                2, +            )              assert np.allclose(f(a, b, c), a * b * c) -        assert capture == """ +        assert ( +            capture +            == """              my_func(x:int=1, y:float=2, z:float=2)              my_func(x:int=2, y:float=2, z:float=2)              my_func(x:int=3, y:float=2, z:float=2) @@ -81,36 +104,53 @@ def test_vectorize(capture):              my_func(x:int=5, y:float=3, z:float=2)              my_func(x:int=6, y:float=3, z:float=2)          """ +        )          with capture:              a, b, c = np.array([[1, 2, 3], [4, 5, 6]])[::, ::2], np.array([[2], [3]]), 2              assert np.allclose(f(a, b, c), a * b * c) -        assert capture == """ +        assert ( +            capture +            == """              my_func(x:int=1, y:float=2, z:float=2)              my_func(x:int=3, y:float=2, z:float=2)              my_func(x:int=4, y:float=3, z:float=2)              my_func(x:int=6, y:float=3, z:float=2)          """ +        )          with capture: -            a, b, c = np.array([[1, 2, 3], [4, 5, 6]], order='F')[::, ::2], np.array([[2], [3]]), 2 +            a, b, c = ( +                np.array([[1, 2, 3], [4, 5, 6]], order="F")[::, ::2], +                np.array([[2], [3]]), +                2, +            )              assert np.allclose(f(a, b, c), a * b * c) -        assert capture == """ +        assert ( +            capture +            == """              my_func(x:int=1, y:float=2, z:float=2)              my_func(x:int=3, y:float=2, z:float=2)              my_func(x:int=4, y:float=3, z:float=2)              my_func(x:int=6, y:float=3, z:float=2)          """ +        )  def test_type_selection():      assert m.selective_func(np.array([1], dtype=np.int32)) == "Int branch taken."      assert m.selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken." -    assert m.selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken." +    assert ( +        m.selective_func(np.array([1.0j], dtype=np.complex64)) +        == "Complex float branch taken." +    )  def test_docs(doc): -    assert doc(m.vectorized_func) == """ -        vectorized_func(arg0: numpy.ndarray[int32], arg1: numpy.ndarray[float32], arg2: numpy.ndarray[float64]) -> object +    assert ( +        doc(m.vectorized_func) +        == """ +        vectorized_func(arg0: numpy.ndarray[numpy.int32], arg1: numpy.ndarray[numpy.float32], arg2: numpy.ndarray[numpy.float64]) -> object      """  # noqa: E501 line too long +    )  def test_trivial_broadcasting(): @@ -118,16 +158,24 @@ def test_trivial_broadcasting():      assert vectorized_is_trivial(1, 2, 3) == trivial.c_trivial      assert vectorized_is_trivial(np.array(1), np.array(2), 3) == trivial.c_trivial -    assert vectorized_is_trivial(np.array([1, 3]), np.array([2, 4]), 3) == trivial.c_trivial +    assert ( +        vectorized_is_trivial(np.array([1, 3]), np.array([2, 4]), 3) +        == trivial.c_trivial +    )      assert trivial.c_trivial == vectorized_is_trivial( -        np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3) -    assert vectorized_is_trivial( -        np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2) == trivial.non_trivial -    assert vectorized_is_trivial( -        np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2) == trivial.non_trivial -    z1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype='int32') -    z2 = np.array(z1, dtype='float32') -    z3 = np.array(z1, dtype='float64') +        np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3 +    ) +    assert ( +        vectorized_is_trivial(np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2) +        == trivial.non_trivial +    ) +    assert ( +        vectorized_is_trivial(np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2) +        == trivial.non_trivial +    ) +    z1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype="int32") +    z2 = np.array(z1, dtype="float32") +    z3 = np.array(z1, dtype="float64")      assert vectorized_is_trivial(z1, z2, z3) == trivial.c_trivial      assert vectorized_is_trivial(1, z2, z3) == trivial.c_trivial      assert vectorized_is_trivial(z1, 1, z3) == trivial.c_trivial @@ -137,7 +185,7 @@ def test_trivial_broadcasting():      assert vectorized_is_trivial(1, 1, z3[::2, ::2]) == trivial.non_trivial      assert vectorized_is_trivial(z1, 1, z3[1::4, 1::4]) == trivial.c_trivial -    y1 = np.array(z1, order='F') +    y1 = np.array(z1, order="F")      y2 = np.array(y1)      y3 = np.array(y1)      assert vectorized_is_trivial(y1, y2, y3) == trivial.f_trivial @@ -158,30 +206,41 @@ def test_trivial_broadcasting():  def test_passthrough_arguments(doc):      assert doc(m.vec_passthrough) == ( -        "vec_passthrough(" + ", ".join([ -            "arg0: float", -            "arg1: numpy.ndarray[float64]", -            "arg2: numpy.ndarray[float64]", -            "arg3: numpy.ndarray[int32]", -            "arg4: int", -            "arg5: m.numpy_vectorize.NonPODClass", -            "arg6: numpy.ndarray[float64]"]) + ") -> object") - -    b = np.array([[10, 20, 30]], dtype='float64') +        "vec_passthrough(" +        + ", ".join( +            [ +                "arg0: float", +                "arg1: numpy.ndarray[numpy.float64]", +                "arg2: numpy.ndarray[numpy.float64]", +                "arg3: numpy.ndarray[numpy.int32]", +                "arg4: int", +                "arg5: m.numpy_vectorize.NonPODClass", +                "arg6: numpy.ndarray[numpy.float64]", +            ] +        ) +        + ") -> object" +    ) + +    b = np.array([[10, 20, 30]], dtype="float64")      c = np.array([100, 200])  # NOT a vectorized argument -    d = np.array([[1000], [2000], [3000]], dtype='int') -    g = np.array([[1000000, 2000000, 3000000]], dtype='int')  # requires casting +    d = np.array([[1000], [2000], [3000]], dtype="int") +    g = np.array([[1000000, 2000000, 3000000]], dtype="int")  # requires casting      assert np.all( -        m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g) == -        np.array([[1111111, 2111121, 3111131], -                  [1112111, 2112121, 3112131], -                  [1113111, 2113121, 3113131]])) +        m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g) +        == np.array( +            [ +                [1111111, 2111121, 3111131], +                [1112111, 2112121, 3112131], +                [1113111, 2113121, 3113131], +            ] +        ) +    )  def test_method_vectorization():      o = m.VectorizeTestClass(3) -    x = np.array([1, 2], dtype='int') -    y = np.array([[10], [20]], dtype='float32') +    x = np.array([1, 2], dtype="int") +    y = np.array([[10], [20]], dtype="float32")      assert np.all(o.method(x, y) == [[14, 15], [24, 25]]) @@ -190,7 +249,18 @@ def test_array_collapse():      assert not isinstance(m.vectorized_func(np.array(1), 2, 3), np.ndarray)      z = m.vectorized_func([1], 2, 3)      assert isinstance(z, np.ndarray) -    assert z.shape == (1, ) +    assert z.shape == (1,)      z = m.vectorized_func(1, [[[2]]], 3)      assert isinstance(z, np.ndarray)      assert z.shape == (1, 1, 1) + + +def test_vectorized_noreturn(): +    x = m.NonPODClass(0) +    assert x.value == 0 +    m.add_to(x, [1, 2, 3, 4]) +    assert x.value == 10 +    m.add_to(x, 1) +    assert x.value == 11 +    m.add_to(x, [[1, 1], [2, 3]]) +    assert x.value == 18 diff --git a/3rdparty/pybind11/tests/test_opaque_types.cpp b/3rdparty/pybind11/tests/test_opaque_types.cpp index 0d20d9a0..5a234316 100644 --- a/3rdparty/pybind11/tests/test_opaque_types.cpp +++ b/3rdparty/pybind11/tests/test_opaque_types.cpp @@ -60,8 +60,14 @@ TEST_SUBMODULE(opaque_types, m) {      m.def("get_null_str_value", [](char *ptr) { return reinterpret_cast<std::intptr_t>(ptr); });      m.def("return_unique_ptr", []() -> std::unique_ptr<StringList> { -        StringList *result = new StringList(); +        auto *result = new StringList();          result->push_back("some value");          return std::unique_ptr<StringList>(result);      }); + +    // test unions +    py::class_<IntFloat>(m, "IntFloat") +        .def(py::init<>()) +        .def_readwrite("i", &IntFloat::i) +        .def_readwrite("f", &IntFloat::f);  } diff --git a/3rdparty/pybind11/tests/test_opaque_types.py b/3rdparty/pybind11/tests/test_opaque_types.py index 6b3802fd..77379463 100644 --- a/3rdparty/pybind11/tests/test_opaque_types.py +++ b/3rdparty/pybind11/tests/test_opaque_types.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*-  import pytest  from pybind11_tests import opaque_types as m  from pybind11_tests import ConstructorStats, UserType @@ -31,12 +32,15 @@ def test_pointers(msg):      with pytest.raises(TypeError) as excinfo:          m.get_void_ptr_value([1, 2, 3])  # This should not work -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          get_void_ptr_value(): incompatible function arguments. The following argument types are supported:              1. (arg0: capsule) -> int          Invoked with: [1, 2, 3]      """  # noqa: E501 line too long +    )      assert m.return_null_str() is None      assert m.get_null_str_value(m.return_null_str()) is not None @@ -44,3 +48,11 @@ def test_pointers(msg):      ptr = m.return_unique_ptr()      assert "StringList" in repr(ptr)      assert m.print_opaque_list(ptr) == "Opaque list: [some value]" + + +def test_unions(): +    int_float_union = m.IntFloat() +    int_float_union.i = 42 +    assert int_float_union.i == 42 +    int_float_union.f = 3.0 +    assert int_float_union.f == 3.0 diff --git a/3rdparty/pybind11/tests/test_operator_overloading.cpp b/3rdparty/pybind11/tests/test_operator_overloading.cpp index 7b111704..0a27bfd5 100644 --- a/3rdparty/pybind11/tests/test_operator_overloading.cpp +++ b/3rdparty/pybind11/tests/test_operator_overloading.cpp @@ -43,6 +43,13 @@ public:      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; +    }  private:      float x, y;  }; @@ -55,12 +62,22 @@ int operator+(const C2 &, const C2 &) { return 22; }  int operator+(const C2 &, const C1 &) { return 21; }  int operator+(const C1 &, const C2 &) { return 12; } +// 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; }      }; +} // namespace std + +// Not a good abs function, but easy to test. +std::string abs(const Vector2&) { +    return "abs(Vector2)";  }  // MSVC warns about unknown pragmas, and warnings are errors. @@ -71,11 +88,11 @@ namespace std {    // Here, we suppress the warning using `#pragma diagnostic`.    // Taken from: https://github.com/RobotLocomotion/drake/commit/aaf84b46    // TODO(eric): This could be resolved using a function / functor (e.g. `py::self()`). -  #if (__APPLE__) && (__clang__) -    #if (__clang_major__ >= 10) && (__clang_minor__ >= 0) && (__clang_patchlevel__ >= 1) +  #if defined(__APPLE__) && defined(__clang__) +    #if (__clang_major__ >= 10)        #pragma GCC diagnostic ignored "-Wself-assign-overloaded"      #endif -  #elif (__clang__) +  #elif defined(__clang__)      #if (__clang_major__ >= 7)        #pragma GCC diagnostic ignored "-Wself-assign-overloaded"      #endif @@ -107,7 +124,13 @@ TEST_SUBMODULE(operators, m) {          .def(float() / py::self)          .def(-py::self)          .def("__str__", &Vector2::toString) -        .def(hash(py::self)) +        .def("__repr__", &Vector2::toString) +        .def(py::self == py::self) +        .def(py::self != py::self) +        .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); })          ;      m.attr("Vector") = m.attr("Vector2"); @@ -164,6 +187,38 @@ TEST_SUBMODULE(operators, m) {          .def(py::self *= int())          .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;} +    }; + +    struct Hashable : Comparable { +        explicit Hashable(int value): Comparable{value}{}; +        size_t hash() const { return static_cast<size_t>(value); } +    }; + +    struct Hashable2 : Hashable { +        using Hashable::Hashable; +    }; + +    py::class_<Comparable>(m, "Comparable") +        .def(py::init<int>()) +        .def(py::self == py::self); + +    py::class_<Hashable>(m, "Hashable") +        .def(py::init<int>()) +        .def(py::self == py::self) +        .def("__hash__", &Hashable::hash); + +    // define __hash__ before __eq__ +    py::class_<Hashable2>(m, "Hashable2") +        .def("__hash__", &Hashable::hash) +        .def(py::init<int>()) +        .def(py::self == py::self);  }  #ifndef _MSC_VER diff --git a/3rdparty/pybind11/tests/test_operator_overloading.py b/3rdparty/pybind11/tests/test_operator_overloading.py index bd36ac2a..5dbfb32c 100644 --- a/3rdparty/pybind11/tests/test_operator_overloading.py +++ b/3rdparty/pybind11/tests/test_operator_overloading.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*-  import pytest  from pybind11_tests import operators as m  from pybind11_tests import ConstructorStats @@ -6,6 +7,9 @@ from pybind11_tests import ConstructorStats  def test_operator_overloading():      v1 = m.Vector2(1, 2)      v2 = m.Vector(3, -1) +    v3 = m.Vector2(1, 2)  # Same value as v1, but different instance. +    assert v1 is not v3 +      assert str(v1) == "[1.000000, 2.000000]"      assert str(v2) == "[3.000000, -1.000000]" @@ -24,6 +28,12 @@ def test_operator_overloading():      assert str(v1 * v2) == "[3.000000, -2.000000]"      assert str(v2 / v1) == "[3.000000, -0.500000]" +    assert v1 == v3 +    assert v1 != v2 +    assert hash(v1) == 4 +    # TODO(eric.cousineau): Make this work. +    # assert abs(v1) == "abs(Vector2)" +      v1 += 2 * v2      assert str(v1) == "[7.000000, 0.000000]"      v1 -= v2 @@ -37,22 +47,33 @@ def test_operator_overloading():      v2 /= v1      assert str(v2) == "[2.000000, 8.000000]" -    assert hash(v1) == 4 -      cstats = ConstructorStats.get(m.Vector2) -    assert cstats.alive() == 2 +    assert cstats.alive() == 3      del v1 -    assert cstats.alive() == 1 +    assert cstats.alive() == 2      del v2 +    assert cstats.alive() == 1 +    del v3      assert cstats.alive() == 0 -    assert cstats.values() == ['[1.000000, 2.000000]', '[3.000000, -1.000000]', -                               '[-3.000000, 1.000000]', '[4.000000, 1.000000]', -                               '[-2.000000, 3.000000]', '[-7.000000, -6.000000]', -                               '[9.000000, 10.000000]', '[8.000000, 16.000000]', -                               '[0.125000, 0.250000]', '[7.000000, 6.000000]', -                               '[9.000000, 10.000000]', '[8.000000, 16.000000]', -                               '[8.000000, 4.000000]', '[3.000000, -2.000000]', -                               '[3.000000, -0.500000]', '[6.000000, -2.000000]'] +    assert cstats.values() == [ +        "[1.000000, 2.000000]", +        "[3.000000, -1.000000]", +        "[1.000000, 2.000000]", +        "[-3.000000, 1.000000]", +        "[4.000000, 1.000000]", +        "[-2.000000, 3.000000]", +        "[-7.000000, -6.000000]", +        "[9.000000, 10.000000]", +        "[8.000000, 16.000000]", +        "[0.125000, 0.250000]", +        "[7.000000, 6.000000]", +        "[9.000000, 10.000000]", +        "[8.000000, 16.000000]", +        "[8.000000, 4.000000]", +        "[3.000000, -2.000000]", +        "[3.000000, -0.500000]", +        "[6.000000, -2.000000]", +    ]      assert cstats.default_constructions == 0      assert cstats.copy_constructions == 0      assert cstats.move_constructions >= 10 @@ -106,3 +127,19 @@ def test_nested():      assert abase.value == 42      del abase, b      pytest.gc_collect() + + +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' + +    for hashable in (m.Hashable, m.Hashable2): +        assert hashable(15) is not hashable(15) +        assert hashable(15) == hashable(15) + +        assert hash(hashable(15)) == 15 +        assert hash(hashable(15)) == hash(hashable(15)) diff --git a/3rdparty/pybind11/tests/test_pickling.py b/3rdparty/pybind11/tests/test_pickling.py index 5ae05aaa..6b27a73a 100644 --- a/3rdparty/pybind11/tests/test_pickling.py +++ b/3rdparty/pybind11/tests/test_pickling.py @@ -1,4 +1,8 @@ +# -*- coding: utf-8 -*-  import pytest + +import env  # noqa: F401 +  from pybind11_tests import pickling as m  try: @@ -21,7 +25,7 @@ def test_roundtrip(cls_name):      assert p2.extra2() == p.extra2() -@pytest.unsupported_on_pypy +@pytest.mark.xfail("env.PYPY")  @pytest.mark.parametrize("cls_name", ["PickleableWithDict", "PickleableWithDictNew"])  def test_roundtrip_with_dict(cls_name):      cls = getattr(m, cls_name) @@ -38,5 +42,6 @@ def test_roundtrip_with_dict(cls_name):  def test_enum_pickle():      from pybind11_tests import enums as e +      data = pickle.dumps(e.EOne, 2)      assert e.EOne == pickle.loads(data) diff --git a/3rdparty/pybind11/tests/test_pytypes.cpp b/3rdparty/pybind11/tests/test_pytypes.cpp index 244e1db0..113cf5cb 100644 --- a/3rdparty/pybind11/tests/test_pytypes.cpp +++ b/3rdparty/pybind11/tests/test_pytypes.cpp @@ -11,6 +11,12 @@  TEST_SUBMODULE(pytypes, m) { +    // test_int +    m.def("get_int", []{return py::int_(0);}); +    // test_iterator +    m.def("get_iterator", []{return py::iterator();}); +    // test_iterable +    m.def("get_iterable", []{return py::iterable();});      // test_list      m.def("get_list", []() {          py::list list; @@ -26,6 +32,11 @@ TEST_SUBMODULE(pytypes, m) {          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)); +    });      // test_set      m.def("get_set", []() { @@ -69,6 +80,7 @@ TEST_SUBMODULE(pytypes, m) {      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_handle", [](py::handle h) { return py::str(h); });      m.def("str_format", []() {          auto s1 = "{} + {} = {}"_s.format(1, 2, 3); @@ -96,7 +108,7 @@ TEST_SUBMODULE(pytypes, m) {      });      m.def("return_capsule_with_name_and_destructor", []() { -        auto capsule = py::capsule((void *) 1234, "pointer type description", [](PyObject *ptr) { +        auto capsule = py::capsule((void *) 12345, "pointer type description", [](PyObject *ptr) {              if (ptr) {                  auto name = PyCapsule_GetName(ptr);                  py::print("destructing capsule ({}, '{}')"_s.format( @@ -104,8 +116,19 @@ TEST_SUBMODULE(pytypes, m) {                  ));              }          }); -        void *contents = capsule; -        py::print("created capsule ({}, '{}')"_s.format((size_t) contents, capsule.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>(); + +        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()));          return capsule;      }); @@ -116,7 +139,7 @@ TEST_SUBMODULE(pytypes, m) {          d["basic_attr"] = o.attr("basic_attr");          auto l = py::list(); -        for (const auto &item : o.attr("begin_end")) { +        for (auto item : o.attr("begin_end")) {              l.append(item);          }          d["begin_end"] = l; @@ -186,6 +209,7 @@ TEST_SUBMODULE(pytypes, m) {      // 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_(), @@ -199,6 +223,7 @@ TEST_SUBMODULE(pytypes, m) {      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"]), @@ -214,6 +239,7 @@ TEST_SUBMODULE(pytypes, m) {      m.def("cast_functions", [](py::dict d) {          // When converting between Python types, obj.cast<T>() should be the same as T(obj)          return py::dict( +            "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_>(), @@ -226,6 +252,21 @@ TEST_SUBMODULE(pytypes, m) {          );      }); +    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"); +    }); +      m.def("get_implicit_casting", []() {          py::dict d;          d["char*_i1"] = "abc"; @@ -272,7 +313,7 @@ TEST_SUBMODULE(pytypes, m) {          py::print("no new line here", "end"_a=" -- ");          py::print("next print"); -        auto py_stderr = py::module::import("sys").attr("stderr"); +        auto py_stderr = py::module_::import("sys").attr("stderr");          py::print("this goes to stderr", "file"_a=py_stderr);          py::print("flush", "flush"_a=true); @@ -307,4 +348,66 @@ TEST_SUBMODULE(pytypes, m) {      m.def("test_list_slicing", [](py::list a) {          return a[py::slice(0, -1, 2)];      }); + +    // See #2361 +    m.def("issue2361_str_implicit_copy_none", []() { +        py::str is_this_none = py::none(); +        return is_this_none; +    }); +    m.def("issue2361_dict_implicit_copy_none", []() { +        py::dict is_this_none = py::none(); +        return is_this_none; +    }); + +    m.def("test_memoryview_object", [](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_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) }); +    }); + +    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) }); +    }); + +    m.def("test_memoryview_from_buffer_empty_shape", []() { +        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 }, { }); +    }); + +    m.def("test_memoryview_from_buffer_nullptr", []() { +        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))); +    }); +#endif + +    // test_builtin_functions +    m.def("get_len", [](py::handle h) { return py::len(h); });  } diff --git a/3rdparty/pybind11/tests/test_pytypes.py b/3rdparty/pybind11/tests/test_pytypes.py index 0e8d6c33..9e5c302e 100644 --- a/3rdparty/pybind11/tests/test_pytypes.py +++ b/3rdparty/pybind11/tests/test_pytypes.py @@ -1,11 +1,26 @@ +# -*- coding: utf-8 -*-  from __future__ import division  import pytest  import sys +import env  # noqa: F401 +  from pybind11_tests import pytypes as m  from pybind11_tests import debug_enabled +def test_int(doc): +    assert doc(m.get_int) == "get_int() -> int" + + +def test_iterator(doc): +    assert doc(m.get_iterator) == "get_iterator() -> Iterator" + + +def test_iterable(doc): +    assert doc(m.get_iterable) == "get_iterable() -> Iterable" + +  def test_list(capture, doc):      with capture:          lst = m.get_list() @@ -13,18 +28,26 @@ def test_list(capture, doc):          lst.append("value2")          m.print_list(lst) -    assert capture.unordered == """ +    assert ( +        capture.unordered +        == """          Entry at position 0: value          list item 0: inserted-0          list item 1: overwritten          list item 2: inserted-2          list item 3: value2      """ +    )      assert doc(m.get_list) == "get_list() -> list"      assert doc(m.print_list) == "print_list(arg0: list) -> None" +def test_none(capture, doc): +    assert doc(m.get_none) == "get_none() -> None" +    assert doc(m.print_none) == "print_none(arg0: None) -> None" + +  def test_set(capture, doc):      s = m.get_set()      assert s == {"key1", "key2", "key3"} @@ -32,12 +55,15 @@ def test_set(capture, doc):      with capture:          s.add("key4")          m.print_set(s) -    assert capture.unordered == """ +    assert ( +        capture.unordered +        == """          key: key1          key: key2          key: key3          key: key4      """ +    )      assert not m.set_contains(set([]), 42)      assert m.set_contains({42}, 42) @@ -54,10 +80,13 @@ def test_dict(capture, doc):      with capture:          d["key2"] = "value2"          m.print_dict(d) -    assert capture.unordered == """ +    assert ( +        capture.unordered +        == """          key: key, value=value          key: key2, value=value2      """ +    )      assert not m.dict_contains({}, 42)      assert m.dict_contains({42: None}, 42) @@ -84,18 +113,30 @@ def test_str(doc):      assert m.str_from_object(A()) == "this is a str"      assert m.repr_from_object(A()) == "this is a repr" +    assert m.str_from_handle(A()) == "this is a str"      s1, s2 = m.str_format()      assert s1 == "1 + 2 = 3"      assert s1 == s2 +    malformed_utf8 = b"\x80" +    assert m.str_from_object(malformed_utf8) is malformed_utf8  # To be fixed; see #2380 +    if env.PY2: +        # with pytest.raises(UnicodeDecodeError): +        #     m.str_from_object(malformed_utf8) +        with pytest.raises(UnicodeDecodeError): +            m.str_from_handle(malformed_utf8) +    else: +        # assert m.str_from_object(malformed_utf8) == "b'\\x80'" +        assert m.str_from_handle(malformed_utf8) == "b'\\x80'" +  def test_bytes(doc):      assert m.bytes_from_string().decode() == "foo"      assert m.bytes_from_str().decode() == "bar"      assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format( -        "bytes" if sys.version_info[0] == 3 else "str" +        "str" if env.PY2 else "bytes"      ) @@ -105,28 +146,37 @@ def test_capsule(capture):          a = m.return_capsule_with_destructor()          del a          pytest.gc_collect() -    assert capture.unordered == """ +    assert ( +        capture.unordered +        == """          creating capsule          destructing capsule      """ +    )      with capture:          a = m.return_capsule_with_destructor_2()          del a          pytest.gc_collect() -    assert capture.unordered == """ +    assert ( +        capture.unordered +        == """          creating capsule          destructing capsule: 1234      """ +    )      with capture:          a = m.return_capsule_with_name_and_destructor()          del a          pytest.gc_collect() -    assert capture.unordered == """ +    assert ( +        capture.unordered +        == """          created capsule (1234, 'pointer type description')          destructing capsule (1234, 'pointer type description')      """ +    )  def test_accessors(): @@ -170,11 +220,17 @@ def test_accessors():  def test_constructors():      """C++ default and converting constructors are equivalent to type calls in Python""" -    types = [str, bool, int, float, tuple, list, dict, set] +    types = [bytes, str, bool, int, float, tuple, list, dict, set]      expected = {t.__name__: t() for t in types} +    if env.PY2: +        # Note that bytes.__name__ == 'str' in Python 2. +        # pybind11::str is unicode even under Python 2. +        expected["bytes"] = bytes() +        expected["str"] = unicode()  # noqa: F821      assert m.default_constructors() == expected      data = { +        bytes: b"41",  # Currently no supported or working conversions.          str: 42,          bool: "Not empty",          int: "42", @@ -183,10 +239,15 @@ def test_constructors():          list: range(3),          dict: [("two", 2), ("one", 1), ("three", 3)],          set: [4, 4, 5, 6, 6, 6], -        memoryview: b'abc' +        memoryview: b"abc",      }      inputs = {k.__name__: v for k, v in data.items()}      expected = {k.__name__: k(v) for k, v in data.items()} +    if env.PY2:  # Similar to the above. See comments above. +        inputs["bytes"] = b"41" +        inputs["str"] = 42 +        expected["bytes"] = b"41" +        expected["str"] = u"42"      assert m.converting_constructors(inputs) == expected      assert m.cast_functions(inputs) == expected @@ -202,21 +263,79 @@ def test_constructors():          assert noconv2[k] is expected[k] +def test_non_converting_constructors(): +    non_converting_test_cases = [ +        ("bytes", range(10)), +        ("none", 42), +        ("ellipsis", 42), +    ] +    for t, v in non_converting_test_cases: +        with pytest.raises(TypeError) as excinfo: +            m.nonconverting_constructor(t, v) +        expected_error = "Object of type '{}' is not an instance of '{}'".format( +            type(v).__name__, t +        ) +        assert str(excinfo.value) == expected_error + + +def test_pybind11_str_raw_str(): +    # specifically to exercise pybind11::str::raw_str +    cvt = m.convert_to_pybind11_str +    assert cvt(u"Str") == u"Str" +    assert cvt(b"Bytes") == u"Bytes" if env.PY2 else "b'Bytes'" +    assert cvt(None) == u"None" +    assert cvt(False) == u"False" +    assert cvt(True) == u"True" +    assert cvt(42) == u"42" +    assert cvt(2 ** 65) == u"36893488147419103232" +    assert cvt(-1.50) == u"-1.5" +    assert cvt(()) == u"()" +    assert cvt((18,)) == u"(18,)" +    assert cvt([]) == u"[]" +    assert cvt([28]) == u"[28]" +    assert cvt({}) == u"{}" +    assert cvt({3: 4}) == u"{3: 4}" +    assert cvt(set()) == u"set([])" if env.PY2 else "set()" +    assert cvt({3, 3}) == u"set([3])" if env.PY2 else "{3}" + +    valid_orig = u"DZ" +    valid_utf8 = valid_orig.encode("utf-8") +    valid_cvt = cvt(valid_utf8) +    assert type(valid_cvt) == bytes  # Probably surprising. +    assert valid_cvt == b"\xc7\xb1" + +    malformed_utf8 = b"\x80" +    malformed_cvt = cvt(malformed_utf8) +    assert type(malformed_cvt) == bytes  # Probably surprising. +    assert malformed_cvt == b"\x80" + +  def test_implicit_casting():      """Tests implicit casting when assigning or appending to dicts and lists."""      z = m.get_implicit_casting() -    assert z['d'] == { -        'char*_i1': 'abc', 'char*_i2': 'abc', 'char*_e': 'abc', 'char*_p': 'abc', -        'str_i1': 'str', 'str_i2': 'str1', 'str_e': 'str2', 'str_p': 'str3', -        'int_i1': 42, 'int_i2': 42, 'int_e': 43, 'int_p': 44 +    assert z["d"] == { +        "char*_i1": "abc", +        "char*_i2": "abc", +        "char*_e": "abc", +        "char*_p": "abc", +        "str_i1": "str", +        "str_i2": "str1", +        "str_e": "str2", +        "str_p": "str3", +        "int_i1": 42, +        "int_i2": 42, +        "int_e": 43, +        "int_p": 44,      } -    assert z['l'] == [3, 6, 9, 12, 15] +    assert z["l"] == [3, 6, 9, 12, 15]  def test_print(capture):      with capture:          m.print_function() -    assert capture == """ +    assert ( +        capture +        == """          Hello, World!          1 2.0 three True -- multiple args          *args-and-a-custom-separator @@ -224,14 +343,15 @@ def test_print(capture):          flush          py::print + str.format = this      """ +    )      assert capture.stderr == "this goes to stderr"      with pytest.raises(RuntimeError) as excinfo:          m.print_failure()      assert str(excinfo.value) == "make_tuple(): unable to convert " + (          "argument of type 'UnregisteredType' to Python object" -        if debug_enabled else -        "arguments to Python object (compile in debug mode for details)" +        if debug_enabled +        else "arguments to Python object (compile in debug mode for details)"      ) @@ -253,11 +373,116 @@ def test_hash():  def test_number_protocol():      for a, b in [(1, 1), (3, 5)]: -        li = [a == b, a != b, a < b, a <= b, a > b, a >= b, a + b, -              a - b, a * b, a / b, a | b, a & b, a ^ b, a >> b, a << b] +        li = [ +            a == b, +            a != b, +            a < b, +            a <= b, +            a > b, +            a >= b, +            a + b, +            a - b, +            a * b, +            a / b, +            a | b, +            a & b, +            a ^ b, +            a >> b, +            a << b, +        ]          assert m.test_number_protocol(a, b) == li  def test_list_slicing():      li = list(range(100))      assert li[::2] == m.test_list_slicing(li) + + +def test_issue2361(): +    # See issue #2361 +    assert m.issue2361_str_implicit_copy_none() == "None" +    with pytest.raises(TypeError) as excinfo: +        assert m.issue2361_dict_implicit_copy_none() +    assert "'NoneType' object is not iterable" in str(excinfo.value) + + +@pytest.mark.parametrize( +    "method, args, fmt, expected_view", +    [ +        (m.test_memoryview_object, (b"red",), "B", b"red"), +        (m.test_memoryview_buffer_info, (b"green",), "B", b"green"), +        (m.test_memoryview_from_buffer, (False,), "h", [3, 1, 4, 1, 5]), +        (m.test_memoryview_from_buffer, (True,), "H", [2, 7, 1, 8]), +        (m.test_memoryview_from_buffer_nativeformat, (), "@i", [4, 7, 5]), +    ], +) +def test_memoryview(method, args, fmt, expected_view): +    view = method(*args) +    assert isinstance(view, memoryview) +    assert view.format == fmt +    if isinstance(expected_view, bytes) or not env.PY2: +        view_as_list = list(view) +    else: +        # Using max to pick non-zero byte (big-endian vs little-endian). +        view_as_list = [max([ord(c) for c in s]) for s in view] +    assert view_as_list == list(expected_view) + + +@pytest.mark.xfail("env.PYPY", reason="getrefcount is not available") +@pytest.mark.parametrize( +    "method", +    [ +        m.test_memoryview_object, +        m.test_memoryview_buffer_info, +    ], +) +def test_memoryview_refcount(method): +    buf = b"\x0a\x0b\x0c\x0d" +    ref_before = sys.getrefcount(buf) +    view = method(buf) +    ref_after = sys.getrefcount(buf) +    assert ref_before < ref_after +    assert list(view) == list(buf) + + +def test_memoryview_from_buffer_empty_shape(): +    view = m.test_memoryview_from_buffer_empty_shape() +    assert isinstance(view, memoryview) +    assert view.format == "B" +    if env.PY2: +        # Python 2 behavior is weird, but Python 3 (the future) is fine. +        # PyPy3 has <memoryview, while CPython 2 has <memory +        assert bytes(view).startswith(b"<memory") +    else: +        assert bytes(view) == b"" + + +def test_test_memoryview_from_buffer_invalid_strides(): +    with pytest.raises(RuntimeError): +        m.test_memoryview_from_buffer_invalid_strides() + + +def test_test_memoryview_from_buffer_nullptr(): +    if env.PY2: +        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) +    assert view.format == "B" +    assert bytes(view) == b"\xff\xe1\xab\x37" + + +def test_builtin_functions(): +    assert m.get_len([i for i in range(42)]) == 42 +    with pytest.raises(TypeError) as exc_info: +        m.get_len(i for i in range(42)) +    assert str(exc_info.value) in [ +        "object of type 'generator' has no len()", +        "'generator' has no length", +    ]  # PyPy diff --git a/3rdparty/pybind11/tests/test_sequences_and_iterators.cpp b/3rdparty/pybind11/tests/test_sequences_and_iterators.cpp index 87ccf99d..d318052a 100644 --- a/3rdparty/pybind11/tests/test_sequences_and_iterators.cpp +++ b/3rdparty/pybind11/tests/test_sequences_and_iterators.cpp @@ -13,6 +13,8 @@  #include <pybind11/operators.h>  #include <pybind11/stl.h> +#include <algorithm> +  template<typename T>  class NonZeroIterator {      const T* ptr_; @@ -81,7 +83,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) {      py::class_<Sliceable>(m,"Sliceable")          .def(py::init<int>())          .def("__getitem__",[](const Sliceable &s, py::slice slice) { -          ssize_t start, stop, step, slicelength; +          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); @@ -198,7 +200,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) {              size_t start, stop, step, slicelength;              if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))                  throw py::error_already_set(); -            Sequence *seq = new Sequence(slicelength); +            auto *seq = new Sequence(slicelength);              for (size_t i = 0; i < slicelength; ++i) {                  (*seq)[i] = s[start]; start += step;              } @@ -319,6 +321,9 @@ TEST_SUBMODULE(sequences_and_iterators, m) {          return l;      }); +    // test_sequence_length: check that Python sequences can be converted to py::sequence. +    m.def("sequence_length", [](py::sequence seq) { return seq.size(); }); +      // Make sure that py::iterator works with std algorithms      m.def("count_none", [](py::object o) {          return std::count_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); diff --git a/3rdparty/pybind11/tests/test_sequences_and_iterators.py b/3rdparty/pybind11/tests/test_sequences_and_iterators.py index 6bd16064..c3b608c4 100644 --- a/3rdparty/pybind11/tests/test_sequences_and_iterators.py +++ b/3rdparty/pybind11/tests/test_sequences_and_iterators.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*-  import pytest  from pybind11_tests import sequences_and_iterators as m  from pybind11_tests import ConstructorStats @@ -9,7 +10,9 @@ def isclose(a, b, rel_tol=1e-05, abs_tol=0.0):  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)) +    return all( +        isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) for a, b in zip(a_list, b_list) +    )  def test_generalized_iterators(): @@ -50,7 +53,7 @@ def test_sequence():      cstats = ConstructorStats.get(m.Sequence)      s = m.Sequence(5) -    assert cstats.values() == ['of size', '5'] +    assert cstats.values() == ["of size", "5"]      assert "Sequence" in repr(s)      assert len(s) == 5 @@ -61,16 +64,16 @@ def test_sequence():      assert isclose(s[0], 12.34) and isclose(s[3], 56.78)      rev = reversed(s) -    assert cstats.values() == ['of size', '5'] +    assert cstats.values() == ["of size", "5"]      rev2 = s[::-1] -    assert cstats.values() == ['of size', '5'] +    assert cstats.values() == ["of size", "5"]      it = iter(m.Sequence(0))      for _ in range(3):  # __next__ must continue to raise StopIteration          with pytest.raises(StopIteration):              next(it) -    assert cstats.values() == ['of size', '0'] +    assert cstats.values() == ["of size", "0"]      expected = [0, 56.78, 0, 0, 12.34]      assert allclose(rev, expected) @@ -78,7 +81,7 @@ def test_sequence():      assert rev == rev2      rev[0::2] = m.Sequence([2.0, 2.0, 2.0]) -    assert cstats.values() == ['of size', '3', 'from std::vector'] +    assert cstats.values() == ["of size", "3", "from std::vector"]      assert allclose(rev, [2, 56.78, 2, 0, 2]) @@ -100,18 +103,38 @@ def test_sequence():      assert cstats.move_assignments == 0 +def test_sequence_length(): +    """#2076: Exception raised by len(arg) should be propagated """ + +    class BadLen(RuntimeError): +        pass + +    class SequenceLike: +        def __getitem__(self, i): +            return None + +        def __len__(self): +            raise BadLen() + +    with pytest.raises(BadLen): +        m.sequence_length(SequenceLike()) + +    assert m.sequence_length([1, 2, 3]) == 3 +    assert m.sequence_length("hello") == 5 + +  def test_map_iterator(): -    sm = m.StringMap({'hi': 'bye', 'black': 'white'}) -    assert sm['hi'] == 'bye' +    sm = m.StringMap({"hi": "bye", "black": "white"}) +    assert sm["hi"] == "bye"      assert len(sm) == 2 -    assert sm['black'] == 'white' +    assert sm["black"] == "white"      with pytest.raises(KeyError): -        assert sm['orange'] -    sm['orange'] = 'banana' -    assert sm['orange'] == 'banana' +        assert sm["orange"] +    sm["orange"] = "banana" +    assert sm["orange"] == "banana" -    expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'} +    expected = {"hi": "bye", "black": "white", "orange": "banana"}      for k in sm:          assert sm[k] == expected[k]      for k, v in sm.items(): @@ -159,7 +182,8 @@ def test_iterator_passthrough():      """#181: iterator passthrough did not compile"""      from pybind11_tests.sequences_and_iterators import iterator_passthrough -    assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15] +    values = [3, 5, 7, 9, 11, 13, 15] +    assert list(iterator_passthrough(iter(values))) == values  def test_iterator_rvp(): diff --git a/3rdparty/pybind11/tests/test_smart_ptr.cpp b/3rdparty/pybind11/tests/test_smart_ptr.cpp index 87c9be8c..60c2e692 100644 --- a/3rdparty/pybind11/tests/test_smart_ptr.cpp +++ b/3rdparty/pybind11/tests/test_smart_ptr.cpp @@ -27,7 +27,8 @@ namespace pybind11 { namespace detail {      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>); @@ -97,9 +98,9 @@ TEST_SUBMODULE(smart_ptr, m) {      class MyObject1 : public Object {      public:          MyObject1(int value) : value(value) { print_created(this, toString()); } -        std::string toString() const { return "MyObject1[" + std::to_string(value) + "]"; } +        std::string toString() const override { return "MyObject1[" + std::to_string(value) + "]"; }      protected: -        virtual ~MyObject1() { print_destroyed(this); } +        ~MyObject1() override { print_destroyed(this); }      private:          int value;      }; @@ -207,7 +208,7 @@ TEST_SUBMODULE(smart_ptr, m) {      class MyObject4b : public MyObject4a {      public:          MyObject4b(int i) : MyObject4a(i) { print_created(this); } -        ~MyObject4b() { print_destroyed(this); } +        ~MyObject4b() override { print_destroyed(this); }      };      py::class_<MyObject4b, MyObject4a>(m, "MyObject4b")          .def(py::init<int>()); @@ -291,7 +292,8 @@ TEST_SUBMODULE(smart_ptr, m) {          ~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", []() { 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 { @@ -337,7 +339,9 @@ TEST_SUBMODULE(smart_ptr, m) {      // test_shared_ptr_gc      // #187: issue involving std::shared_ptr<> return value policy & garbage collection      struct ElementBase { -        virtual ~ElementBase() { } /* Force creation of virtual table */ +        virtual ~ElementBase() = default; /* Force creation of virtual table */ +        ElementBase() = default; +        ElementBase(const ElementBase&) = delete;      };      py::class_<ElementBase, std::shared_ptr<ElementBase>>(m, "ElementBase"); diff --git a/3rdparty/pybind11/tests/test_smart_ptr.py b/3rdparty/pybind11/tests/test_smart_ptr.py index c6627043..c55bffba 100644 --- a/3rdparty/pybind11/tests/test_smart_ptr.py +++ b/3rdparty/pybind11/tests/test_smart_ptr.py @@ -1,11 +1,15 @@ +# -*- coding: utf-8 -*-  import pytest -from pybind11_tests import smart_ptr as m -from pybind11_tests import ConstructorStats + +m = pytest.importorskip("pybind11_tests.smart_ptr") +from pybind11_tests import ConstructorStats  # noqa: E402  def test_smart_ptr(capture):      # Object1 -    for i, o in enumerate([m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1): +    for i, o in enumerate( +        [m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1 +    ):          assert o.getRefCount() == 1          with capture:              m.print_object_1(o) @@ -14,8 +18,9 @@ def test_smart_ptr(capture):              m.print_object_4(o)          assert capture == "MyObject1[{i}]\n".format(i=i) * 4 -    for i, o in enumerate([m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], -                          start=4): +    for i, o in enumerate( +        [m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], start=4 +    ):          print(o)          with capture:              if not isinstance(o, int): @@ -27,11 +32,15 @@ def test_smart_ptr(capture):              m.print_myobject1_2(o)              m.print_myobject1_3(o)              m.print_myobject1_4(o) -        assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8) + +        times = 4 if isinstance(o, int) else 8 +        assert capture == "MyObject1[{i}]\n".format(i=i) * 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 = ["MyObject1[{}]".format(i) for i in range(1, 7)] + [ +        "MyObject1[7]" +    ] * 4      assert cstats.values() == expected_values      assert cstats.default_constructions == 0      assert cstats.copy_constructions == 0 @@ -40,7 +49,9 @@ def test_smart_ptr(capture):      assert cstats.move_assignments == 0      # Object2 -    for i, o in zip([8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]): +    for i, o in zip( +        [8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()] +    ):          print(o)          with capture:              m.print_myobject2_1(o) @@ -53,7 +64,7 @@ def test_smart_ptr(capture):      assert cstats.alive() == 1      o = None      assert cstats.alive() == 0 -    assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]'] +    assert cstats.values() == ["MyObject2[8]", "MyObject2[6]", "MyObject2[7]"]      assert cstats.default_constructions == 0      assert cstats.copy_constructions == 0      # assert cstats.move_constructions >= 0 # Doesn't invoke any @@ -61,7 +72,9 @@ def test_smart_ptr(capture):      assert cstats.move_assignments == 0      # Object3 -    for i, o in zip([9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]): +    for i, o in zip( +        [9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()] +    ):          print(o)          with capture:              m.print_myobject3_1(o) @@ -74,7 +87,7 @@ def test_smart_ptr(capture):      assert cstats.alive() == 1      o = None      assert cstats.alive() == 0 -    assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]'] +    assert cstats.values() == ["MyObject3[9]", "MyObject3[8]", "MyObject3[9]"]      assert cstats.default_constructions == 0      assert cstats.copy_constructions == 0      # assert cstats.move_constructions >= 0 # Doesn't invoke any @@ -94,7 +107,7 @@ def test_smart_ptr(capture):      # ref<>      cstats = m.cstats_ref()      assert cstats.alive() == 0 -    assert cstats.values() == ['from pointer'] * 10 +    assert cstats.values() == ["from pointer"] * 10      assert cstats.default_constructions == 30      assert cstats.copy_constructions == 12      # assert cstats.move_constructions >= 0 # Doesn't invoke any @@ -184,7 +197,9 @@ def test_shared_ptr_from_this_and_references():      ref = s.ref  # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)      assert stats.alive() == 2      assert s.set_ref(ref) -    assert s.set_holder(ref)  # std::enable_shared_from_this can create a holder from a reference +    assert s.set_holder( +        ref +    )  # std::enable_shared_from_this can create a holder from a reference      bad_wp = s.bad_wp  # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)      assert stats.alive() == 2 @@ -198,12 +213,16 @@ def test_shared_ptr_from_this_and_references():      assert s.set_ref(copy)      assert s.set_holder(copy) -    holder_ref = s.holder_ref  # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false) +    holder_ref = ( +        s.holder_ref +    )  # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)      assert stats.alive() == 3      assert s.set_ref(holder_ref)      assert s.set_holder(holder_ref) -    holder_copy = s.holder_copy  # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false) +    holder_copy = ( +        s.holder_copy +    )  # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)      assert stats.alive() == 3      assert s.set_ref(holder_copy)      assert s.set_holder(holder_copy) @@ -218,7 +237,10 @@ def test_shared_ptr_from_this_and_references():  def test_move_only_holder():      a = m.TypeWithMoveOnlyHolder.make() +    b = m.TypeWithMoveOnlyHolder.make_as_object()      stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder) +    assert stats.alive() == 2 +    del b      assert stats.alive() == 1      del a      assert stats.alive() == 0 @@ -272,8 +294,10 @@ def test_smart_ptr_from_default():      instance = m.HeldByDefaultHolder()      with pytest.raises(RuntimeError) as excinfo:          m.HeldByDefaultHolder.load_shared_ptr(instance) -    assert "Unable to load a custom holder type from a " \ -           "default-holder instance" in str(excinfo.value) +    assert ( +        "Unable to load a custom holder type from a " +        "default-holder instance" in str(excinfo.value) +    )  def test_shared_ptr_gc(): diff --git a/3rdparty/pybind11/tests/test_stl.cpp b/3rdparty/pybind11/tests/test_stl.cpp index 207c9fb2..05901627 100644 --- a/3rdparty/pybind11/tests/test_stl.cpp +++ b/3rdparty/pybind11/tests/test_stl.cpp @@ -15,7 +15,7 @@  #include <string>  // Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14 -#if PYBIND11_HAS_VARIANT +#if defined(PYBIND11_HAS_VARIANT)  using std::variant;  #elif defined(PYBIND11_TEST_BOOST) && (!defined(_MSC_VER) || _MSC_VER >= 1910)  #  include <boost/variant.hpp> @@ -47,7 +47,18 @@ struct TplCtorClass {  namespace std {      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; +    } +    OptionalImpl<T> member = T{}; +};  TEST_SUBMODULE(stl, m) { @@ -154,6 +165,23 @@ TEST_SUBMODULE(stl, m) {          .def(py::init<>())          .def(py::init<int>()); + +    struct MoveOutDetector +    { +        MoveOutDetector() = default; +        MoveOutDetector(const MoveOutDetector&) = default; +        MoveOutDetector(MoveOutDetector&& other) noexcept +         : initialized(other.initialized) { +            // steal underlying resource +            other.initialized = false; +        } +        bool initialized = true; +    }; +    py::class_<MoveOutDetector>(m, "MoveOutDetector", "Class with move tracking") +        .def(py::init<>()) +        .def_readonly("initialized", &MoveOutDetector::initialized); + +  #ifdef PYBIND11_HAS_OPTIONAL      // test_optional      m.attr("has_optional") = true; @@ -175,6 +203,12 @@ TEST_SUBMODULE(stl, m) {      m.def("nodefer_none_optional", [](std::optional<int>) { return true; });      m.def("nodefer_none_optional", [](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);  #endif  #ifdef PYBIND11_HAS_EXP_OPTIONAL @@ -195,6 +229,12 @@ TEST_SUBMODULE(stl, m) {      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);  #endif  #ifdef PYBIND11_HAS_VARIANT diff --git a/3rdparty/pybind11/tests/test_stl.py b/3rdparty/pybind11/tests/test_stl.py index 2335cb9f..33001754 100644 --- a/3rdparty/pybind11/tests/test_stl.py +++ b/3rdparty/pybind11/tests/test_stl.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*-  import pytest  from pybind11_tests import stl as m @@ -87,7 +88,7 @@ def test_recursive_casting():      assert m.cast_rv_nested() == [[[{"b": "rvalue", "c": "rvalue"}], [{"a": "rvalue"}]]]      assert m.cast_lv_nested() == {          "a": [[["lvalue", "lvalue"]], [["lvalue", "lvalue"]]], -        "b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]] +        "b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]],      }      # Issue #853 test case: @@ -105,15 +106,15 @@ def test_move_out_container():      assert [x.value for x in moved_out_list] == [0, 1, 2] -@pytest.mark.skipif(not hasattr(m, "has_optional"), reason='no <optional>') +@pytest.mark.skipif(not hasattr(m, "has_optional"), reason="no <optional>")  def test_optional():      assert m.double_or_zero(None) == 0      assert m.double_or_zero(42) == 84 -    pytest.raises(TypeError, m.double_or_zero, 'foo') +    pytest.raises(TypeError, m.double_or_zero, "foo")      assert m.half_or_none(0) is None      assert m.half_or_none(42) == 21 -    pytest.raises(TypeError, m.half_or_none, 'foo') +    pytest.raises(TypeError, m.half_or_none, "foo")      assert m.test_nullopt() == 42      assert m.test_nullopt(None) == 42 @@ -127,16 +128,23 @@ def test_optional():      assert m.nodefer_none_optional(None) +    holder = m.OptionalHolder() +    mvalue = holder.member +    assert mvalue.initialized +    assert holder.member_initialized() -@pytest.mark.skipif(not hasattr(m, "has_exp_optional"), reason='no <experimental/optional>') + +@pytest.mark.skipif( +    not hasattr(m, "has_exp_optional"), reason="no <experimental/optional>" +)  def test_exp_optional():      assert m.double_or_zero_exp(None) == 0      assert m.double_or_zero_exp(42) == 84 -    pytest.raises(TypeError, m.double_or_zero_exp, 'foo') +    pytest.raises(TypeError, m.double_or_zero_exp, "foo")      assert m.half_or_none_exp(0) is None      assert m.half_or_none_exp(42) == 21 -    pytest.raises(TypeError, m.half_or_none_exp, 'foo') +    pytest.raises(TypeError, m.half_or_none_exp, "foo")      assert m.test_nullopt_exp() == 42      assert m.test_nullopt_exp(None) == 42 @@ -148,8 +156,13 @@ def test_exp_optional():      assert m.test_no_assign_exp(m.NoAssign(43)) == 43      pytest.raises(TypeError, m.test_no_assign_exp, 43) +    holder = m.OptionalExpHolder() +    mvalue = holder.member +    assert mvalue.initialized +    assert holder.member_initialized() + -@pytest.mark.skipif(not hasattr(m, "load_variant"), reason='no <variant>') +@pytest.mark.skipif(not hasattr(m, "load_variant"), reason="no <variant>")  def test_variant(doc):      assert m.load_variant(1) == "int"      assert m.load_variant("1") == "std::string" @@ -161,34 +174,44 @@ def test_variant(doc):      assert m.cast_variant() == (5, "Hello") -    assert doc(m.load_variant) == "load_variant(arg0: Union[int, str, float, None]) -> str" +    assert ( +        doc(m.load_variant) == "load_variant(arg0: Union[int, str, float, None]) -> str" +    )  def test_vec_of_reference_wrapper():      """#171: Can't return reference wrappers (or STL structures containing them)""" -    assert str(m.return_vec_of_reference_wrapper(UserType(4))) == \ -        "[UserType(1), UserType(2), UserType(3), UserType(4)]" +    assert ( +        str(m.return_vec_of_reference_wrapper(UserType(4))) +        == "[UserType(1), UserType(2), UserType(3), UserType(4)]" +    )  def test_stl_pass_by_pointer(msg):      """Passing nullptr or None to an STL container pointer is not expected to work"""      with pytest.raises(TypeError) as excinfo:          m.stl_pass_by_pointer()  # default value is `nullptr` -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:              1. (v: List[int] = None) -> List[int]          Invoked with:      """  # noqa: E501 line too long +    )      with pytest.raises(TypeError) as excinfo:          m.stl_pass_by_pointer(None) -    assert msg(excinfo.value) == """ +    assert ( +        msg(excinfo.value) +        == """          stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:              1. (v: List[int] = None) -> List[int]          Invoked with: None      """  # noqa: E501 line too long +    )      assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3] @@ -198,10 +221,12 @@ def test_missing_header_message():      <pybind11/stl.h> should result in a helpful suggestion in the error message"""      import pybind11_cross_module_tests as cm -    expected_message = ("Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,\n" -                        "<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic\n" -                        "conversions are optional and require extra headers to be included\n" -                        "when compiling your pybind11 module.") +    expected_message = ( +        "Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,\n" +        "<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic\n" +        "conversions are optional and require extra headers to be included\n" +        "when compiling your pybind11 module." +    )      with pytest.raises(TypeError) as excinfo:          cm.missing_header_arg([1.0, 2.0, 3.0]) @@ -215,9 +240,9 @@ def test_missing_header_message():  def test_function_with_string_and_vector_string_arg():      """Check if a string is NOT implicitly converted to a list, which was the      behavior before fix of issue #1258""" -    assert m.func_with_string_or_vector_string_arg_overload(('A', 'B', )) == 2 -    assert m.func_with_string_or_vector_string_arg_overload(['A', 'B']) == 2 -    assert m.func_with_string_or_vector_string_arg_overload('A') == 3 +    assert m.func_with_string_or_vector_string_arg_overload(("A", "B")) == 2 +    assert m.func_with_string_or_vector_string_arg_overload(["A", "B"]) == 2 +    assert m.func_with_string_or_vector_string_arg_overload("A") == 3  def test_stl_ownership(): @@ -236,6 +261,6 @@ def test_array_cast_sequence():  def test_issue_1561():      """ check fix for issue #1561 """      bar = m.Issue1561Outer() -    bar.list = [m.Issue1561Inner('bar')] +    bar.list = [m.Issue1561Inner("bar")]      bar.list -    assert bar.list[0].data == 'bar' +    assert bar.list[0].data == "bar" diff --git a/3rdparty/pybind11/tests/test_stl_binders.cpp b/3rdparty/pybind11/tests/test_stl_binders.cpp index 86888740..1c0df984 100644 --- a/3rdparty/pybind11/tests/test_stl_binders.cpp +++ b/3rdparty/pybind11/tests/test_stl_binders.cpp @@ -117,7 +117,7 @@ TEST_SUBMODULE(stl_binders, m) {      });      // The rest depends on numpy: -    try { py::module::import("numpy"); } +    try { py::module_::import("numpy"); }      catch (...) { return; }      // test_vector_buffer_numpy diff --git a/3rdparty/pybind11/tests/test_stl_binders.py b/3rdparty/pybind11/tests/test_stl_binders.py index c7b7e853..84132a2b 100644 --- a/3rdparty/pybind11/tests/test_stl_binders.py +++ b/3rdparty/pybind11/tests/test_stl_binders.py @@ -1,9 +1,9 @@ +# -*- coding: utf-8 -*-  import pytest -import sys -from pybind11_tests import stl_binders as m -with pytest.suppress(ImportError): -    import numpy as np +import env  # noqa: F401 + +from pybind11_tests import stl_binders as m  def test_vector_int(): @@ -45,7 +45,7 @@ def test_vector_int():      # test error handling, and that the vector is unchanged      with pytest.raises(RuntimeError): -        v_int2.extend([8, 'a']) +        v_int2.extend([8, "a"])      assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7]) @@ -67,30 +67,34 @@ def test_vector_int():      v_int2.clear()      assert len(v_int2) == 0 -# related to the PyPy's buffer protocol. -@pytest.unsupported_on_pypy + +# Older PyPy's failed here, related to the PyPy's buffer protocol.  def test_vector_buffer():      b = bytearray([1, 2, 3, 4])      v = m.VectorUChar(b)      assert v[1] == 2      v[2] = 5      mv = memoryview(v)  # We expose the buffer interface -    if sys.version_info.major > 2: +    if not env.PY2:          assert mv[2] == 5          mv[2] = 6      else: -        assert mv[2] == '\x05' -        mv[2] = '\x06' +        assert mv[2] == "\x05" +        mv[2] = "\x06"      assert v[2] == 6 +    if not env.PY2: +        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      assert "NumPy type info missing for " in str(excinfo.value) -@pytest.unsupported_on_pypy -@pytest.requires_numpy  def test_vector_buffer_numpy(): +    np = pytest.importorskip("numpy")      a = np.array([1, 2, 3, 4], dtype=np.int32)      with pytest.raises(TypeError):          m.VectorInt(a) @@ -110,13 +114,23 @@ def test_vector_buffer_numpy():      v = m.get_vectorstruct()      assert v[0].x == 5      ma = np.asarray(v) -    ma[1]['x'] = 99 +    ma[1]["x"] = 99      assert v[1].x == 99 -    v = m.VectorStruct(np.zeros(3, dtype=np.dtype([('w', 'bool'), ('x', 'I'), -                                                   ('y', 'float64'), ('z', 'bool')], align=True))) +    v = m.VectorStruct( +        np.zeros( +            3, +            dtype=np.dtype( +                [("w", "bool"), ("x", "I"), ("y", "float64"), ("z", "bool")], align=True +            ), +        ) +    )      assert len(v) == 3 +    b = np.array([1, 2, 3, 4], dtype=np.uint8) +    v = m.VectorUChar(b[::2]) +    assert v[1] == 3 +  def test_vector_bool():      import pybind11_cross_module_tests as cm @@ -143,31 +157,31 @@ def test_vector_custom():  def test_map_string_double():      mm = m.MapStringDouble() -    mm['a'] = 1 -    mm['b'] = 2.5 +    mm["a"] = 1 +    mm["b"] = 2.5 -    assert list(mm) == ['a', 'b'] -    assert list(mm.items()) == [('a', 1), ('b', 2.5)] +    assert list(mm) == ["a", "b"] +    assert list(mm.items()) == [("a", 1), ("b", 2.5)]      assert str(mm) == "MapStringDouble{a: 1, b: 2.5}"      um = m.UnorderedMapStringDouble() -    um['ua'] = 1.1 -    um['ub'] = 2.6 +    um["ua"] = 1.1 +    um["ub"] = 2.6 -    assert sorted(list(um)) == ['ua', 'ub'] -    assert sorted(list(um.items())) == [('ua', 1.1), ('ub', 2.6)] +    assert sorted(list(um)) == ["ua", "ub"] +    assert sorted(list(um.items())) == [("ua", 1.1), ("ub", 2.6)]      assert "UnorderedMapStringDouble" in str(um)  def test_map_string_double_const():      mc = m.MapStringDoubleConst() -    mc['a'] = 10 -    mc['b'] = 20.5 +    mc["a"] = 10 +    mc["b"] = 20.5      assert str(mc) == "MapStringDoubleConst{a: 10, b: 20.5}"      umc = m.UnorderedMapStringDoubleConst() -    umc['a'] = 11 -    umc['b'] = 21.5 +    umc["a"] = 11 +    umc["b"] = 21.5      str(umc) @@ -188,7 +202,7 @@ def test_noncopyable_containers():      i = 1      for j in dnc: -        assert(j.value == i) +        assert j.value == i          i += 1      # std::map @@ -221,7 +235,8 @@ def test_noncopyable_containers():          for j in range(0, 5):              assert nvnc[i][j].value == j + 1 -    for k, v in nvnc.items(): +    # Note: maps do not have .values() +    for _, v in nvnc.items():          for i, j in enumerate(v, start=1):              assert j.value == i @@ -232,7 +247,7 @@ def test_noncopyable_containers():              assert nmnc[i][j].value == 10 * j      vsum = 0 -    for k_o, v_o in nmnc.items(): +    for _, v_o in nmnc.items():          for k_i, v_i in v_o.items():              assert v_i.value == 10 * k_i              vsum += v_i.value @@ -246,7 +261,7 @@ def test_noncopyable_containers():              assert numnc[i][j].value == 10 * j      vsum = 0 -    for k_o, v_o in numnc.items(): +    for _, v_o in numnc.items():          for k_i, v_i in v_o.items():              assert v_i.value == 10 * k_i              vsum += v_i.value @@ -256,21 +271,21 @@ def test_noncopyable_containers():  def test_map_delitem():      mm = m.MapStringDouble() -    mm['a'] = 1 -    mm['b'] = 2.5 +    mm["a"] = 1 +    mm["b"] = 2.5 -    assert list(mm) == ['a', 'b'] -    assert list(mm.items()) == [('a', 1), ('b', 2.5)] -    del mm['a'] -    assert list(mm) == ['b'] -    assert list(mm.items()) == [('b', 2.5)] +    assert list(mm) == ["a", "b"] +    assert list(mm.items()) == [("a", 1), ("b", 2.5)] +    del mm["a"] +    assert list(mm) == ["b"] +    assert list(mm.items()) == [("b", 2.5)]      um = m.UnorderedMapStringDouble() -    um['ua'] = 1.1 -    um['ub'] = 2.6 - -    assert sorted(list(um)) == ['ua', 'ub'] -    assert sorted(list(um.items())) == [('ua', 1.1), ('ub', 2.6)] -    del um['ua'] -    assert sorted(list(um)) == ['ub'] -    assert sorted(list(um.items())) == [('ub', 2.6)] +    um["ua"] = 1.1 +    um["ub"] = 2.6 + +    assert sorted(list(um)) == ["ua", "ub"] +    assert sorted(list(um.items())) == [("ua", 1.1), ("ub", 2.6)] +    del um["ua"] +    assert sorted(list(um)) == ["ub"] +    assert sorted(list(um.items())) == [("ub", 2.6)] diff --git a/3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp b/3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp index 272e460c..838a168d 100644 --- a/3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp +++ b/3rdparty/pybind11/tests/test_tagbased_polymorphic.cpp @@ -12,6 +12,12 @@  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/). +    virtual ~Animal() = default; + +    // Enum for tag-based polymorphism.      enum class Kind {          Unknown = 0,          Dog = 100, Labrador, Chihuahua, LastDog = 199, @@ -111,7 +117,7 @@ namespace pybind11 {          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  TEST_SUBMODULE(tagbased_polymorphic, m) {      py::class_<Animal>(m, "Animal") diff --git a/3rdparty/pybind11/tests/test_tagbased_polymorphic.py b/3rdparty/pybind11/tests/test_tagbased_polymorphic.py index 2574d7de..64eb8a3c 100644 --- a/3rdparty/pybind11/tests/test_tagbased_polymorphic.py +++ b/3rdparty/pybind11/tests/test_tagbased_polymorphic.py @@ -1,19 +1,28 @@ +# -*- coding: utf-8 -*-  from pybind11_tests import tagbased_polymorphic as m  def test_downcast():      zoo = m.create_zoo()      assert [type(animal) for animal in zoo] == [ -        m.Labrador, m.Dog, m.Chihuahua, m.Cat, m.Panther +        m.Labrador, +        m.Dog, +        m.Chihuahua, +        m.Cat, +        m.Panther,      ]      assert [animal.name for animal in zoo] == [ -        "Fido", "Ginger", "Hertzl", "Tiger", "Leo" +        "Fido", +        "Ginger", +        "Hertzl", +        "Tiger", +        "Leo",      ]      zoo[1].sound = "woooooo"      assert [dog.bark() for dog in zoo[:3]] == [          "Labrador Fido goes WOOF!",          "Dog Ginger goes woooooo", -        "Chihuahua Hertzl goes iyiyiyiyiyi and runs in circles" +        "Chihuahua Hertzl goes iyiyiyiyiyi and runs in circles",      ]      assert [cat.purr() for cat in zoo[3:]] == ["mrowr", "mrrrRRRRRR"]      zoo[0].excitement -= 1000 diff --git a/3rdparty/pybind11/tests/test_union.py b/3rdparty/pybind11/tests/test_union.py index e1866e70..2a2c12fb 100644 --- a/3rdparty/pybind11/tests/test_union.py +++ b/3rdparty/pybind11/tests/test_union.py @@ -1,3 +1,4 @@ +# -*- 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 ccf018d9..685d64a7 100644 --- a/3rdparty/pybind11/tests/test_virtual_functions.cpp +++ b/3rdparty/pybind11/tests/test_virtual_functions.cpp @@ -47,7 +47,7 @@ public:      int run(int value) override {          /* Generate wrapping code that enables native function overloading */ -        PYBIND11_OVERLOAD( +        PYBIND11_OVERRIDE(              int,         /* Return type */              ExampleVirt, /* Parent class */              run,         /* Name of function */ @@ -56,7 +56,7 @@ public:      }      bool run_bool() override { -        PYBIND11_OVERLOAD_PURE( +        PYBIND11_OVERRIDE_PURE(              bool,         /* Return type */              ExampleVirt,  /* Parent class */              run_bool,     /* Name of function */ @@ -66,7 +66,7 @@ public:      }      void pure_virtual() override { -        PYBIND11_OVERLOAD_PURE( +        PYBIND11_OVERRIDE_PURE(              void,         /* Return type */              ExampleVirt,  /* Parent class */              pure_virtual, /* Name of function */ @@ -78,7 +78,7 @@ public:      // We can return reference types for compatibility with C++ virtual interfaces that do so, but      // note they have some significant limitations (see the documentation).      const std::string &get_string1() override { -        PYBIND11_OVERLOAD( +        PYBIND11_OVERRIDE(              const std::string &, /* Return type */              ExampleVirt,         /* Parent class */              get_string1,         /* Name of function */ @@ -87,7 +87,7 @@ public:      }      const std::string *get_string2() override { -        PYBIND11_OVERLOAD( +        PYBIND11_OVERRIDE(              const std::string *, /* Return type */              ExampleVirt,         /* Parent class */              get_string2,         /* Name of function */ @@ -129,7 +129,9 @@ private:  class NCVirt {  public: -    virtual ~NCVirt() { } +    virtual ~NCVirt() = default; +    NCVirt() = default; +    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; @@ -137,13 +139,13 @@ public:      std::string print_movable(int a, int b) { return get_movable(a, b).get_value(); }  };  class NCVirtTrampoline : public NCVirt { -#if !defined(__INTEL_COMPILER) +#if !defined(__INTEL_COMPILER) && !defined(__CUDACC__) && !defined(__PGIC__)      NonCopyable get_noncopyable(int a, int b) override { -        PYBIND11_OVERLOAD(NonCopyable, NCVirt, get_noncopyable, a, b); +        PYBIND11_OVERRIDE(NonCopyable, NCVirt, get_noncopyable, a, b);      }  #endif      Movable get_movable(int a, int b) override { -        PYBIND11_OVERLOAD_PURE(Movable, NCVirt, get_movable, a, b); +        PYBIND11_OVERRIDE_PURE(Movable, NCVirt, get_movable, a, b);      }  }; @@ -151,11 +153,13 @@ struct Base {      /* for some reason MSVC2015 can't compile this if the function is pure virtual */      virtual std::string dispatch() const { return {}; };      virtual ~Base() = default; +    Base() = default; +    Base(const Base&) = delete;  };  struct DispatchIssue : Base { -    virtual std::string dispatch() const { -        PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */); +    std::string dispatch() const override { +        PYBIND11_OVERRIDE_PURE(std::string, Base, dispatch, /* no arguments */);      }  }; @@ -183,7 +187,7 @@ static void test_gil_from_thread() {  // 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); +void initialize_inherited_virtuals(py::module_ &m);  TEST_SUBMODULE(virtual_functions, m) {      // test_override @@ -201,7 +205,7 @@ TEST_SUBMODULE(virtual_functions, m) {          .def(py::init<int, int>());      // test_move_support -#if !defined(__INTEL_COMPILER) +#if !defined(__INTEL_COMPILER) && !defined(__CUDACC__) && !defined(__PGIC__)      py::class_<NCVirt, NCVirtTrampoline>(m, "NCVirt")          .def(py::init<>())          .def("get_noncopyable", &NCVirt::get_noncopyable) @@ -221,19 +225,22 @@ TEST_SUBMODULE(virtual_functions, m) {      // don't invoke Python dispatch classes by default when instantiating C++ classes      // that were not extended on the Python side      struct A { -        virtual ~A() {} +        A() = default; +        A(const A&) = delete; +        virtual ~A() = default;          virtual void f() { py::print("A.f()"); }      };      struct PyA : A {          PyA() { py::print("PyA.PyA()"); } -        ~PyA() { py::print("PyA.~PyA()"); } +        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 , -            PYBIND11_OVERLOAD(PYBIND11_TYPE(typename std::enable_if<true, void>::type), A, f); +            PYBIND11_OVERRIDE(PYBIND11_TYPE(typename std::enable_if<true, void>::type), A, f);          }      }; @@ -246,16 +253,19 @@ TEST_SUBMODULE(virtual_functions, m) {      // test_alias_delay_initialization2      // ... unless we explicitly request it, as in this example:      struct A2 { -        virtual ~A2() {} +        A2() = default; +        A2(const A2&) = delete; +        virtual ~A2() = default;          virtual void f() { py::print("A2.f()"); }      };      struct PyA2 : A2 {          PyA2() { py::print("PyA2.PyA2()"); } -        ~PyA2() { py::print("PyA2.~PyA2()"); } +        PyA2(const PyA2&) = delete; +        ~PyA2() override { py::print("PyA2.~PyA2()"); }          void f() override {              py::print("PyA2.f()"); -            PYBIND11_OVERLOAD(void, A2, f); +            PYBIND11_OVERRIDE(void, A2, f);          }      }; @@ -282,6 +292,8 @@ TEST_SUBMODULE(virtual_functions, m) {          std::string v;          A a;          explicit OverrideTest(const std::string &v) : v{v} {} +        OverrideTest() = default; +        OverrideTest(const OverrideTest&) = delete;          virtual std::string str_value() { return v; }          virtual std::string &str_ref() { return v; }          virtual A A_value() { return a; } @@ -292,19 +304,19 @@ TEST_SUBMODULE(virtual_functions, m) {      class PyOverrideTest : public OverrideTest {      public:          using OverrideTest::OverrideTest; -        std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); } +        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_OVERLOAD(std::string &, OverrideTest, str_ref); } +//      std::string &str_ref() override { PYBIND11_OVERRIDE(std::string &, OverrideTest, str_ref); }          // But we can work around it like this:      private:          std::string _tmp; -        std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); } +        std::string str_ref_helper() { PYBIND11_OVERRIDE(std::string, OverrideTest, str_ref); }      public:          std::string &str_ref() override { return _tmp = str_ref_helper(); } -        A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); } -        A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); } +        A A_value() override { PYBIND11_OVERRIDE(A, OverrideTest, A_value); } +        A &A_ref() override { PYBIND11_OVERRIDE(A &, OverrideTest, A_ref); }      };      py::class_<OverrideTest::A>(m, "OverrideTest_A") @@ -339,6 +351,8 @@ public: \          return say_something(1) + " " + std::to_string(unlucky_number()); \      }  A_METHODS +    A_Repeat() = default; +    A_Repeat(const A_Repeat&) = delete;      virtual ~A_Repeat() = default;  };  class B_Repeat : public A_Repeat { @@ -364,7 +378,12 @@ D_METHODS  };  // Base classes for templated inheritance trampolines.  Identical to the repeat-everything version: -class A_Tpl { A_METHODS; virtual ~A_Tpl() = default; }; +class A_Tpl { +    A_METHODS; +    A_Tpl() = default; +    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 }; @@ -374,29 +393,29 @@ class D_Tpl : public C_Tpl { D_METHODS };  class PyA_Repeat : public A_Repeat {  public:      using A_Repeat::A_Repeat; -    int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, A_Repeat, unlucky_number, ); } -    std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, A_Repeat, say_something, times); } +    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); }  };  class PyB_Repeat : public B_Repeat {  public:      using B_Repeat::B_Repeat; -    int unlucky_number() override { PYBIND11_OVERLOAD(int, B_Repeat, unlucky_number, ); } -    std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, B_Repeat, say_something, times); } -    double lucky_number() override { PYBIND11_OVERLOAD(double, B_Repeat, lucky_number, ); } +    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); } +    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_OVERLOAD(int, C_Repeat, unlucky_number, ); } -    std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, C_Repeat, say_something, times); } -    double lucky_number() override { PYBIND11_OVERLOAD(double, C_Repeat, lucky_number, ); } +    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); } +    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_OVERLOAD(int, D_Repeat, unlucky_number, ); } -    std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, D_Repeat, say_something, times); } -    double lucky_number() override { PYBIND11_OVERLOAD(double, D_Repeat, lucky_number, ); } +    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); } +    double lucky_number() override { PYBIND11_OVERRIDE(double, D_Repeat, lucky_number, ); }  };  // Inheritance approach 2: templated trampoline classes. @@ -417,15 +436,15 @@ template <class Base = A_Tpl>  class PyA_Tpl : public Base {  public:      using Base::Base; // Inherit constructors -    int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, Base, unlucky_number, ); } -    std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, Base, say_something, times); } +    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); }  };  template <class Base = B_Tpl>  class PyB_Tpl : public PyA_Tpl<Base> {  public:      using PyA_Tpl<Base>::PyA_Tpl; // Inherit constructors (via PyA_Tpl's inherited constructors) -    int unlucky_number() override { PYBIND11_OVERLOAD(int, Base, unlucky_number, ); } -    double lucky_number() override { PYBIND11_OVERLOAD(double, Base, lucky_number, ); } +    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): @@ -440,7 +459,7 @@ public:  };  */ -void initialize_inherited_virtuals(py::module &m) { +void initialize_inherited_virtuals(py::module_ &m) {      // test_inherited_virtuals      // Method 1: repeat diff --git a/3rdparty/pybind11/tests/test_virtual_functions.py b/3rdparty/pybind11/tests/test_virtual_functions.py index 5ce9abd3..ae199301 100644 --- a/3rdparty/pybind11/tests/test_virtual_functions.py +++ b/3rdparty/pybind11/tests/test_virtual_functions.py @@ -1,7 +1,10 @@ +# -*- coding: utf-8 -*-  import pytest -from pybind11_tests import virtual_functions as m -from pybind11_tests import ConstructorStats +import env  # noqa: F401 + +m = pytest.importorskip("pybind11_tests.virtual_functions") +from pybind11_tests import ConstructorStats  # noqa: E402  def test_override(capture, msg): @@ -11,18 +14,18 @@ def test_override(capture, msg):              self.data = "Hello world"          def run(self, value): -            print('ExtendedExampleVirt::run(%i), calling parent..' % value) +            print("ExtendedExampleVirt::run(%i), calling parent.." % value)              return super(ExtendedExampleVirt, self).run(value + 1)          def run_bool(self): -            print('ExtendedExampleVirt::run_bool()') +            print("ExtendedExampleVirt::run_bool()")              return False          def get_string1(self):              return "override1"          def pure_virtual(self): -            print('ExtendedExampleVirt::pure_virtual(): %s' % self.data) +            print("ExtendedExampleVirt::pure_virtual(): %s" % self.data)      class ExtendedExampleVirt2(ExtendedExampleVirt):          def __init__(self, state): @@ -34,21 +37,30 @@ def test_override(capture, msg):      ex12 = m.ExampleVirt(10)      with capture:          assert m.runExampleVirt(ex12, 20) == 30 -    assert capture == """ +    assert ( +        capture +        == """          Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)      """  # noqa: E501 line too long +    )      with pytest.raises(RuntimeError) as excinfo:          m.runExampleVirtVirtual(ex12) -    assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"' +    assert ( +        msg(excinfo.value) +        == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"' +    )      ex12p = ExtendedExampleVirt(10)      with capture:          assert m.runExampleVirt(ex12p, 20) == 32 -    assert capture == """ +    assert ( +        capture +        == """          ExtendedExampleVirt::run(20), calling parent..          Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)      """  # noqa: E501 line too long +    )      with capture:          assert m.runExampleVirtBool(ex12p) is False      assert capture == "ExtendedExampleVirt::run_bool()" @@ -59,16 +71,19 @@ def test_override(capture, msg):      ex12p2 = ExtendedExampleVirt2(15)      with capture:          assert m.runExampleVirt(ex12p2, 50) == 68 -    assert capture == """ +    assert ( +        capture +        == """          ExtendedExampleVirt::run(50), calling parent..          Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)      """  # noqa: E501 line too long +    )      cstats = ConstructorStats.get(m.ExampleVirt)      assert cstats.alive() == 3      del ex12, ex12p, ex12p2      assert cstats.alive() == 0 -    assert cstats.values() == ['10', '11', '17'] +    assert cstats.values() == ["10", "11", "17"]      assert cstats.copy_constructions == 0      assert cstats.move_constructions >= 0 @@ -79,6 +94,7 @@ def test_alias_delay_initialization1(capture):      If we just create and use an A instance directly, the trampoline initialization is      bypassed and we only initialize an A() instead (for performance reasons).      """ +      class B(m.A):          def __init__(self):              super(B, self).__init__() @@ -100,12 +116,15 @@ def test_alias_delay_initialization1(capture):          m.call_f(b)          del b          pytest.gc_collect() -    assert capture == """ +    assert ( +        capture +        == """          PyA.PyA()          PyA.f()          In python f()          PyA.~PyA()      """ +    )  def test_alias_delay_initialization2(capture): @@ -115,6 +134,7 @@ def test_alias_delay_initialization2(capture):      performance penalty, it also allows us to do more things with the trampoline      class such as defining local variables and performing construction/destruction.      """ +      class B2(m.A2):          def __init__(self):              super(B2, self).__init__() @@ -132,7 +152,9 @@ def test_alias_delay_initialization2(capture):          m.call_f(a3)          del a3          pytest.gc_collect() -    assert capture == """ +    assert ( +        capture +        == """          PyA2.PyA2()          PyA2.f()          A2.f() @@ -142,6 +164,7 @@ def test_alias_delay_initialization2(capture):          A2.f()          PyA2.~PyA2()      """ +    )      # Python subclass version      with capture: @@ -149,18 +172,23 @@ def test_alias_delay_initialization2(capture):          m.call_f(b2)          del b2          pytest.gc_collect() -    assert capture == """ +    assert ( +        capture +        == """          PyA2.PyA2()          PyA2.f()          In python B2.f()          PyA2.~PyA2()      """ +    )  # PyPy: Reference count > 1 causes call with noncopyable instance  # to fail in ncv1.print_nc() -@pytest.unsupported_on_pypy -@pytest.mark.skipif(not hasattr(m, "NCVirt"), reason="NCVirt test broken on ICPC") +@pytest.mark.xfail("env.PYPY") +@pytest.mark.skipif( +    not hasattr(m, "NCVirt"), reason="NCVirt does not work on Intel/PGI/NVCC compilers" +)  def test_move_support():      class NCVirtExt(m.NCVirt):          def get_noncopyable(self, a, b): @@ -199,8 +227,8 @@ def test_move_support():      del ncv1, ncv2      assert nc_stats.alive() == 0      assert mv_stats.alive() == 0 -    assert nc_stats.values() == ['4', '9', '9', '9'] -    assert mv_stats.values() == ['4', '5', '7', '7'] +    assert nc_stats.values() == ["4", "9", "9", "9"] +    assert mv_stats.values() == ["4", "5", "7", "7"]      assert nc_stats.copy_constructions == 0      assert mv_stats.copy_constructions == 1      assert nc_stats.move_constructions >= 0 @@ -209,6 +237,7 @@ def test_move_support():  def test_dispatch_issue(msg):      """#159: virtual function dispatch has problems with similar-named functions""" +      class PyClass1(m.DispatchIssue):          def dispatch(self):              return "Yay.." @@ -217,7 +246,10 @@ def test_dispatch_issue(msg):          def dispatch(self):              with pytest.raises(RuntimeError) as excinfo:                  super(PyClass2, self).dispatch() -            assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"' +            assert ( +                msg(excinfo.value) +                == 'Tried to call pure virtual function "Base::dispatch"' +            )              p = PyClass1()              return m.dispatch_issue_go(p) @@ -333,7 +365,7 @@ def test_inherited_virtuals():      class DT(m.D_Tpl):          def say_something(self, times): -            return "DT says:" + (' quack' * times) +            return "DT says:" + (" quack" * times)          def unlucky_number(self):              return 1234 @@ -349,7 +381,7 @@ def test_inherited_virtuals():      class DT2(DT):          def say_something(self, times): -            return "DT2: " + ('QUACK' * times) +            return "DT2: " + ("QUACK" * times)          def unlucky_number(self):              return -3 | 
