From 84c7cc6c21455a9e6587571cfd43f1f579fd3e44 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Mon, 30 Aug 2021 15:58:05 -0700 Subject: [PATCH] Update to pybind11 v2.7.1 --- thirdparty/pybind11/CMakeLists.txt | 9 +- .../pybind11/docs/advanced/cast/overview.rst | 6 + thirdparty/pybind11/docs/advanced/classes.rst | 4 +- .../pybind11/docs/advanced/exceptions.rst | 4 + .../pybind11/docs/advanced/functions.rst | 14 +- .../pybind11/docs/advanced/pycpp/numpy.rst | 2 +- .../docs/advanced/pycpp/utilities.rst | 11 + thirdparty/pybind11/docs/changelog.rst | 210 ++++++++++++++- thirdparty/pybind11/docs/compiling.rst | 21 +- thirdparty/pybind11/docs/faq.rst | 6 +- thirdparty/pybind11/docs/limitations.rst | 20 +- thirdparty/pybind11/docs/release.rst | 64 ++--- thirdparty/pybind11/docs/requirements.txt | 5 +- thirdparty/pybind11/docs/upgrade.rst | 2 +- thirdparty/pybind11/include/pybind11/attr.h | 5 +- .../pybind11/include/pybind11/buffer_info.h | 8 +- thirdparty/pybind11/include/pybind11/cast.h | 187 ++++++++------ thirdparty/pybind11/include/pybind11/chrono.h | 39 ++- .../pybind11/include/pybind11/detail/class.h | 13 +- .../pybind11/include/pybind11/detail/common.h | 56 +++- .../pybind11/include/pybind11/detail/descr.h | 28 +- .../pybind11/include/pybind11/detail/init.h | 10 +- .../include/pybind11/detail/internals.h | 4 +- .../pybind11/detail/type_caster_base.h | 40 +-- thirdparty/pybind11/include/pybind11/eigen.h | 9 +- thirdparty/pybind11/include/pybind11/embed.h | 4 +- thirdparty/pybind11/include/pybind11/eval.h | 12 +- .../pybind11/include/pybind11/functional.h | 37 ++- .../pybind11/include/pybind11/iostream.h | 119 ++++++--- thirdparty/pybind11/include/pybind11/numpy.h | 53 ++-- .../pybind11/include/pybind11/pybind11.h | 242 ++++++++++-------- .../pybind11/include/pybind11/pytypes.h | 127 ++++++--- thirdparty/pybind11/include/pybind11/stl.h | 18 +- .../include/pybind11/stl/filesystem.h | 103 ++++++++ .../pybind11/include/pybind11/stl_bind.h | 95 ++++--- thirdparty/pybind11/pybind11/_version.py | 2 +- thirdparty/pybind11/pybind11/setup_helpers.py | 46 +++- .../pybind11/pybind11/setup_helpers.pyi | 5 +- thirdparty/pybind11/tests/CMakeLists.txt | 48 +++- thirdparty/pybind11/tests/env.py | 19 ++ .../tests/extra_python_package/test_files.py | 47 ++-- .../extra_setuptools/test_setuphelper.py | 42 +++ thirdparty/pybind11/tests/local_bindings.h | 6 +- thirdparty/pybind11/tests/object.h | 4 +- .../tests/pybind11_cross_module_tests.cpp | 18 +- thirdparty/pybind11/tests/pybind11_tests.h | 7 +- thirdparty/pybind11/tests/requirements.txt | 3 +- thirdparty/pybind11/tests/test_buffers.cpp | 46 ++-- .../pybind11/tests/test_builtin_casters.cpp | 25 +- .../pybind11/tests/test_builtin_casters.py | 8 +- .../pybind11/tests/test_call_policies.cpp | 8 +- .../pybind11/tests/test_call_policies.py | 30 +++ thirdparty/pybind11/tests/test_callbacks.cpp | 65 +++-- thirdparty/pybind11/tests/test_callbacks.py | 49 +++- thirdparty/pybind11/tests/test_chrono.py | 35 +-- thirdparty/pybind11/tests/test_class.cpp | 28 +- thirdparty/pybind11/tests/test_class.py | 2 +- .../tests/test_constants_and_functions.cpp | 38 ++- thirdparty/pybind11/tests/test_copy_move.cpp | 38 ++- .../tests/test_custom_type_casters.cpp | 23 +- thirdparty/pybind11/tests/test_eigen.cpp | 56 ++-- .../tests/test_embed/test_interpreter.cpp | 7 +- thirdparty/pybind11/tests/test_eval.cpp | 6 +- thirdparty/pybind11/tests/test_exceptions.cpp | 33 ++- thirdparty/pybind11/tests/test_exceptions.h | 12 + thirdparty/pybind11/tests/test_exceptions.py | 14 + .../tests/test_factory_constructors.cpp | 134 ++++++---- .../tests/test_factory_constructors.py | 10 +- thirdparty/pybind11/tests/test_gil_scoped.cpp | 27 +- thirdparty/pybind11/tests/test_iostream.cpp | 41 +-- thirdparty/pybind11/tests/test_iostream.py | 90 +++++++ .../tests/test_kwargs_and_defaults.cpp | 39 ++- .../pybind11/tests/test_local_bindings.cpp | 8 +- .../tests/test_methods_and_attributes.cpp | 107 +++++--- .../tests/test_methods_and_attributes.py | 11 + thirdparty/pybind11/tests/test_modules.cpp | 3 +- .../tests/test_multiple_inheritance.cpp | 52 ++-- .../pybind11/tests/test_numpy_array.cpp | 150 ++++++----- thirdparty/pybind11/tests/test_numpy_array.py | 13 + .../pybind11/tests/test_numpy_dtypes.cpp | 15 +- .../pybind11/tests/test_numpy_vectorize.cpp | 60 +++-- .../pybind11/tests/test_opaque_types.cpp | 2 +- .../tests/test_operator_overloading.cpp | 19 +- thirdparty/pybind11/tests/test_pickling.cpp | 113 +++++--- thirdparty/pybind11/tests/test_pickling.py | 36 +++ thirdparty/pybind11/tests/test_pytypes.cpp | 115 ++++----- thirdparty/pybind11/tests/test_pytypes.py | 18 +- .../tests/test_sequences_and_iterators.cpp | 146 ++++++----- .../tests/test_sequences_and_iterators.py | 4 +- thirdparty/pybind11/tests/test_smart_ptr.cpp | 58 +++-- thirdparty/pybind11/tests/test_stl.cpp | 37 ++- thirdparty/pybind11/tests/test_stl.py | 28 +- .../pybind11/tests/test_stl_binders.cpp | 4 +- .../pybind11/tests/test_virtual_functions.cpp | 19 +- .../pybind11/tests/valgrind-numpy-scipy.supp | 4 +- .../pybind11/tools/FindPythonLibsNew.cmake | 19 +- thirdparty/pybind11/tools/check-style.sh | 6 +- thirdparty/pybind11/tools/make_changelog.py | 7 +- .../pybind11/tools/pybind11Common.cmake | 7 +- .../pybind11/tools/pybind11Config.cmake.in | 5 +- .../pybind11/tools/pybind11NewTools.cmake | 2 +- thirdparty/pybind11/tools/pybind11Tools.cmake | 16 +- thirdparty/pybind11/tools/setup_global.py.in | 4 +- thirdparty/pybind11/tools/setup_main.py.in | 5 + 104 files changed, 2597 insertions(+), 1194 deletions(-) create mode 100644 thirdparty/pybind11/include/pybind11/stl/filesystem.h create mode 100644 thirdparty/pybind11/tests/test_exceptions.h diff --git a/thirdparty/pybind11/CMakeLists.txt b/thirdparty/pybind11/CMakeLists.txt index 152763eb42..b04311fd85 100644 --- a/thirdparty/pybind11/CMakeLists.txt +++ b/thirdparty/pybind11/CMakeLists.txt @@ -125,7 +125,8 @@ set(PYBIND11_HEADERS include/pybind11/pybind11.h include/pybind11/pytypes.h include/pybind11/stl.h - include/pybind11/stl_bind.h) + include/pybind11/stl_bind.h + include/pybind11/stl/filesystem.h) # Compare with grep and warn if mismatched if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12) @@ -202,6 +203,12 @@ if(PYBIND11_INSTALL) "${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}" CACHE STRING "install path for pybind11Config.cmake") + if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") + set(pybind11_INCLUDEDIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}") + else() + set(pybind11_INCLUDEDIR "\$\{PACKAGE_PREFIX_DIR\}/${CMAKE_INSTALL_INCLUDEDIR}") + endif() + configure_package_config_file( tools/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) diff --git a/thirdparty/pybind11/docs/advanced/cast/overview.rst b/thirdparty/pybind11/docs/advanced/cast/overview.rst index b0e32a52f9..6341fce6d4 100644 --- a/thirdparty/pybind11/docs/advanced/cast/overview.rst +++ b/thirdparty/pybind11/docs/advanced/cast/overview.rst @@ -151,6 +151,8 @@ as arguments and return values, refer to the section on binding :ref:`classes`. +------------------------------------+---------------------------+-------------------------------+ | ``std::variant<...>`` | Type-safe union (C++17) | :file:`pybind11/stl.h` | +------------------------------------+---------------------------+-------------------------------+ +| ``std::filesystem::path`` | STL path (C++17) [#]_ | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ | ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` | +------------------------------------+---------------------------+-------------------------------+ | ``std::chrono::duration<...>`` | STL time duration | :file:`pybind11/chrono.h` | @@ -163,3 +165,7 @@ as arguments and return values, refer to the section on binding :ref:`classes`. +------------------------------------+---------------------------+-------------------------------+ | ``Eigen::SparseMatrix<...>`` | Eigen: sparse matrix | :file:`pybind11/eigen.h` | +------------------------------------+---------------------------+-------------------------------+ + +.. [#] ``std::filesystem::path`` is converted to ``pathlib.Path`` and + ``os.PathLike`` is converted to ``std::filesystem::path``, but this requires + Python 3.6 (for ``__fspath__`` support). diff --git a/thirdparty/pybind11/docs/advanced/classes.rst b/thirdparty/pybind11/docs/advanced/classes.rst index 4927902069..9d1b1f0d9b 100644 --- a/thirdparty/pybind11/docs/advanced/classes.rst +++ b/thirdparty/pybind11/docs/advanced/classes.rst @@ -259,7 +259,7 @@ override the ``name()`` method): .. note:: - Note the trailing commas in the ``PYBIND11_OVERIDE`` calls to ``name()`` + Note the trailing commas in the ``PYBIND11_OVERRIDE`` calls to ``name()`` and ``bark()``. These are needed to portably implement a trampoline for a function that does not take any arguments. For functions that take a nonzero number of arguments, the trailing comma must be omitted. @@ -804,7 +804,7 @@ to bind these two functions: } )); -The ``__setstate__`` part of the ``py::picke()`` definition follows the same +The ``__setstate__`` part of the ``py::pickle()`` definition follows the same rules as the single-argument version of ``py::init()``. The return type can be a value, pointer or holder type. See :ref:`custom_constructors` for details. diff --git a/thirdparty/pybind11/docs/advanced/exceptions.rst b/thirdparty/pybind11/docs/advanced/exceptions.rst index 7a4d6cbc6e..f70c202fd5 100644 --- a/thirdparty/pybind11/docs/advanced/exceptions.rst +++ b/thirdparty/pybind11/docs/advanced/exceptions.rst @@ -164,6 +164,10 @@ section. may be explicitly (re-)thrown to delegate it to the other, previously-declared existing exception translators. + Note that ``libc++`` and ``libstdc++`` `behave differently `_ + with ``-fvisibility=hidden``. Therefore exceptions that are used across ABI boundaries need to be explicitly exported, as exercised in ``tests/test_exceptions.h``. + See also: "Problems with C++ exceptions" under `GCC Wiki `_. + .. _handling_python_exceptions_cpp: Handling exceptions from Python in C++ diff --git a/thirdparty/pybind11/docs/advanced/functions.rst b/thirdparty/pybind11/docs/advanced/functions.rst index 6a93ab9da8..a537cb65ee 100644 --- a/thirdparty/pybind11/docs/advanced/functions.rst +++ b/thirdparty/pybind11/docs/advanced/functions.rst @@ -90,17 +90,18 @@ The following table provides an overview of available policies: | | return value is referenced by Python. This is the default policy for | | | property getters created via ``def_property``, ``def_readwrite``, etc. | +--------------------------------------------------+----------------------------------------------------------------------------+ -| :enum:`return_value_policy::automatic` | **Default policy.** This policy falls back to the policy | +| :enum:`return_value_policy::automatic` | This policy falls back to the policy | | | :enum:`return_value_policy::take_ownership` when the return value is a | | | pointer. Otherwise, it uses :enum:`return_value_policy::move` or | | | :enum:`return_value_policy::copy` for rvalue and lvalue references, | | | respectively. See above for a description of what all of these different | -| | policies do. | +| | policies do. This is the default policy for ``py::class_``-wrapped types. | +--------------------------------------------------+----------------------------------------------------------------------------+ | :enum:`return_value_policy::automatic_reference` | As above, but use policy :enum:`return_value_policy::reference` when the | | | return value is a pointer. This is the default conversion policy for | | | function arguments when calling Python functions manually from C++ code | -| | (i.e. via handle::operator()). You probably won't need to use this. | +| | (i.e. via ``handle::operator()``) and the casters in ``pybind11/stl.h``. | +| | You probably won't need to use this explicitly. | +--------------------------------------------------+----------------------------------------------------------------------------+ Return value policies can also be applied to properties: @@ -182,6 +183,9 @@ relies on the ability to create a *weak reference* to the nurse object. When the nurse object is not a pybind11-registered type and does not support weak references, an exception will be thrown. +If you use an incorrect argument index, you will get a ``RuntimeError`` saying +``Could not activate keep_alive!``. You should review the indices you're using. + Consider the following example: here, the binding code for a list append operation ties the lifetime of the newly added element to the underlying container: @@ -251,7 +255,7 @@ For instance, the following statement iterates over a Python ``dict``: .. code-block:: cpp - void print_dict(py::dict dict) { + void print_dict(const py::dict& dict) { /* Easily interact with Python types */ for (auto item : dict) std::cout << "key=" << std::string(py::str(item.first)) << ", " @@ -289,7 +293,7 @@ Such functions can also be created using pybind11: .. code-block:: cpp - void generic(py::args args, py::kwargs kwargs) { + void generic(py::args args, const py::kwargs& kwargs) { /// .. do something with args if (kwargs) /// .. do something with kwargs diff --git a/thirdparty/pybind11/docs/advanced/pycpp/numpy.rst b/thirdparty/pybind11/docs/advanced/pycpp/numpy.rst index 0a81aa8fd5..53ec8c1a3c 100644 --- a/thirdparty/pybind11/docs/advanced/pycpp/numpy.rst +++ b/thirdparty/pybind11/docs/advanced/pycpp/numpy.rst @@ -390,7 +390,7 @@ operation on the C++ side: py::array b = a[py::make_tuple(0, py::ellipsis(), 0)]; .. versionchanged:: 2.6 - ``py::ellipsis()`` is now also avaliable in Python 2. + ``py::ellipsis()`` is now also available in Python 2. Memory view =========== diff --git a/thirdparty/pybind11/docs/advanced/pycpp/utilities.rst b/thirdparty/pybind11/docs/advanced/pycpp/utilities.rst index c15051fb96..30429e84d7 100644 --- a/thirdparty/pybind11/docs/advanced/pycpp/utilities.rst +++ b/thirdparty/pybind11/docs/advanced/pycpp/utilities.rst @@ -47,6 +47,17 @@ redirects output to the corresponding Python streams: call_noisy_func(); }); +.. warning:: + + The implementation in ``pybind11/iostream.h`` is NOT thread safe. Multiple + threads writing to a redirected ostream concurrently cause data races + and potentially buffer overflows. Therefore it is currently a requirement + that all (possibly) concurrent redirected ostream writes are protected by + a mutex. #HelpAppreciated: Work on iostream.h thread safety. For more + background see the discussions under + `PR #2982 `_ and + `PR #2995 `_. + This method respects flushes on the output streams and will flush if needed when the scoped guard is destroyed. This allows the output to be redirected in real time, such as to a Jupyter notebook. The two arguments, the C++ stream and diff --git a/thirdparty/pybind11/docs/changelog.rst b/thirdparty/pybind11/docs/changelog.rst index 84f1352fb9..2f76abe055 100644 --- a/thirdparty/pybind11/docs/changelog.rst +++ b/thirdparty/pybind11/docs/changelog.rst @@ -6,8 +6,86 @@ Changelog Starting with version 1.8.0, pybind11 releases use a `semantic versioning `_ policy. -v2.7.0 (TBA, not yet released) ------------------------------- +v2.8.0 (WIP) +------------ + +* Allow exception translators to be optionally registered local to a module + instead of applying globally across all pybind11 modules. Use + ``register_local_exception_translator(ExceptionTranslator&& translator)`` + instead of ``register_exception_translator(ExceptionTranslator&& + translator)`` to keep your exception remapping code local to the module. + `#2650 `_ + +v2.7.1 (Aug 3, 2021) +--------------------- + +Minor missing functionality added: + +* Allow Python builtins to be used as callbacks in CPython. + `#1413 `_ + +Bug fixes: + +* Fix regression in CMake Python package config: improper use of absolute path. + `#3144 `_ + +* Fix Mingw64 and add to the CI testing matrix. + `#3132 `_ + +* Specified UTF8-encoding in setup.py calls of open(). + `#3137 `_ + +* Add clang-tidy-readability rules to make boolean casts explicit improving + code readability. Also enabled other misc and readability clang-tidy checks. + `#3148 `_ + +* Move object in ``.pop()`` for list. + `#3116 `_ + +Backend and tidying up: + +* Removed and fixed warning suppressions. + `#3127 `_ + `#3129 `_ + `#3135 `_ + `#3141 `_ + `#3142 `_ + `#3150 `_ + `#3152 `_ + `#3160 `_ + `#3161 `_ + + +v2.7.0 (Jul 16, 2021) +--------------------- + +New features: + +* Enable ``py::implicitly_convertible`` for + ``py::class_``-wrapped types. + `#3059 `_ + +* Allow function pointer extraction from overloaded functions. + `#2944 `_ + +* NumPy: added ``.char_()`` to type which gives the NumPy public ``char`` + result, which also distinguishes types by bit length (unlike ``.kind()``). + `#2864 `_ + +* Add ``pybind11::bytearray`` to manipulate ``bytearray`` similar to ``bytes``. + `#2799 `_ + +* ``pybind11/stl/filesystem.h`` registers a type caster that, on C++17/Python + 3.6+, converts ``std::filesystem::path`` to ``pathlib.Path`` and any + ``os.PathLike`` to ``std::filesystem::path``. + `#2730 `_ + +* A ``PYBIND11_VERSION_HEX`` define was added, similar to ``PY_VERSION_HEX``. + `#3120 `_ + + + +Changes: * ``py::str`` changed to exclusively hold `PyUnicodeObject`. Previously ``py::str`` could also hold `bytes`, which is probably surprising, was @@ -15,6 +93,130 @@ v2.7.0 (TBA, not yet released) instead of ``py::bytes``). `#2409 `_ +* Add a safety guard to ensure that the Python GIL is held when C++ calls back + into Python via ``object_api<>::operator()`` (e.g. ``py::function`` + ``__call__``). (This feature is available for Python 3.6+ only.) + `#2919 `_ + +* Catch a missing ``self`` argument in calls to ``__init__()``. + `#2914 `_ + +* Use ``std::string_view`` if available to avoid a copy when passing an object + to a ``std::ostream``. + `#3042 `_ + +* An important warning about thread safety was added to the ``iostream.h`` + documentation; attempts to make ``py::scoped_ostream_redirect`` thread safe + have been removed, as it was only partially effective. + `#2995 `_ + + +Fixes: + +* Performance: avoid unnecessary strlen calls. + `#3058 `_ + +* Fix auto-generated documentation string when using ``const T`` in + ``pyarray_t``. + `#3020 `_ + +* Unify error messages thrown by ``simple_collector``/``unpacking_collector``. + `#3013 `_ + +* ``pybind11::builtin_exception`` is now explicitly exported, which means the + types included/defined in different modules are identical, and exceptions + raised in different modules can be caught correctly. The documentation was + updated to explain that custom exceptions that are used across module + boundaries need to be explicitly exported as well. + `#2999 `_ + +* Fixed exception when printing UTF-8 to a ``scoped_ostream_redirect``. + `#2982 `_ + +* Pickle support enhancement: ``setstate`` implementation will attempt to + ``setattr`` ``__dict__`` only if the unpickled ``dict`` object is not empty, + to not force use of ``py::dynamic_attr()`` unnecessarily. + `#2972 `_ + +* Allow negative timedelta values to roundtrip. + `#2870 `_ + +* Fix unchecked errors could potentially swallow signals/other exceptions. + `#2863 `_ + +* Add null pointer check with ``std::localtime``. + `#2846 `_ + +* Fix the ``weakref`` constructor from ``py::object`` to create a new + ``weakref`` on conversion. + `#2832 `_ + +* Avoid relying on exceptions in C++17 when getting a ``shared_ptr`` holder + from a ``shared_from_this`` class. + `#2819 `_ + +* Allow the codec's exception to be raised instead of :code:`RuntimeError` when + casting from :code:`py::str` to :code:`std::string`. + `#2903 `_ + + +Build system improvements: + +* In ``setup_helpers.py``, test for platforms that have some multiprocessing + features but lack semaphores, which ``ParallelCompile`` requires. + `#3043 `_ + +* Fix ``pybind11_INCLUDE_DIR`` in case ``CMAKE_INSTALL_INCLUDEDIR`` is + absolute. + `#3005 `_ + +* Fix bug not respecting ``WITH_SOABI`` or ``WITHOUT_SOABI`` to CMake. + `#2938 `_ + +* Fix the default ``Pybind11Extension`` compilation flags with a Mingw64 python. + `#2921 `_ + +* Clang on Windows: do not pass ``/MP`` (ignored flag). + `#2824 `_ + +* ``pybind11.setup_helpers.intree_extensions`` can be used to generate + ``Pybind11Extension`` instances from cpp files placed in the Python package + source tree. + `#2831 `_ + +Backend and tidying up: + +* Enable clang-tidy performance, readability, and modernization checks + throughout the codebase to enforce best coding practices. + `#3046 `_, + `#3049 `_, + `#3051 `_, + `#3052 `_, + `#3080 `_, and + `#3094 `_ + + +* Checks for common misspellings were added to the pre-commit hooks. + `#3076 `_ + +* Changed ``Werror`` to stricter ``Werror-all`` for Intel compiler and fixed + minor issues. + `#2948 `_ + +* Fixed compilation with GCC < 5 when the user defines ``_GLIBCXX_USE_CXX11_ABI``. + `#2956 `_ + +* Added nox support for easier local testing and linting of contributions. + `#3101 `_ and + `#3121 `_ + +* Avoid RTD style issue with docutils 0.17+. + `#3119 `_ + +* Support pipx run, such as ``pipx run pybind11 --include`` for a quick compile. + `#3117 `_ + + v2.6.2 (Jan 26, 2021) --------------------- @@ -95,7 +297,7 @@ Bug fixes: * Fix ``py::gil_scoped_acquire`` assert with CPython 3.9 debug build. `#2683 `_ -* Fix issue with a test failing on PyTest 6.2. +* Fix issue with a test failing on pytest 6.2. `#2741 `_ Warning fixes: @@ -504,7 +706,7 @@ v2.4.0 (Sep 19, 2019) `#1888 `_. * ``py::details::overload_cast_impl`` is available in C++11 mode, can be used - like ``overload_cast`` with an additional set of parantheses. + like ``overload_cast`` with an additional set of parentheses. `#1581 `_. * Fixed ``get_include()`` on Conda. diff --git a/thirdparty/pybind11/docs/compiling.rst b/thirdparty/pybind11/docs/compiling.rst index 3a8a270d58..bf7acfc808 100644 --- a/thirdparty/pybind11/docs/compiling.rst +++ b/thirdparty/pybind11/docs/compiling.rst @@ -70,6 +70,19 @@ that is supported via a ``build_ext`` command override; it will only affect ext_modules=ext_modules ) +If you have single-file extension modules that are directly stored in the +Python source tree (``foo.cpp`` in the same directory as where a ``foo.py`` +would be located), you can also generate ``Pybind11Extensions`` using +``setup_helpers.intree_extensions``: ``intree_extensions(["path/to/foo.cpp", +...])`` returns a list of ``Pybind11Extensions`` which can be passed to +``ext_modules``, possibly after further customizing their attributes +(``libraries``, ``include_dirs``, etc.). By doing so, a ``foo.*.so`` extension +module will be generated and made available upon installation. + +``intree_extension`` will automatically detect if you are using a ``src``-style +layout (as long as no namespace packages are involved), but you can also +explicitly pass ``package_dir`` to it (as in ``setuptools.setup``). + Since pybind11 does not require NumPy when building, a light-weight replacement for NumPy's parallel compilation distutils tool is included. Use it like this: @@ -93,7 +106,7 @@ to a memory dependent number. If you are developing rapidly and have a lot of C++ files, you may want to avoid rebuilding files that have not changed. For simple cases were you are using ``pip install -e .`` and do not have local headers, you can skip the -rebuild if a object file is newer than it's source (headers are not checked!) +rebuild if an object file is newer than its source (headers are not checked!) with the following: .. code-block:: python @@ -149,7 +162,7 @@ Your ``pyproject.toml`` file will likely look something like this: and ``pyproject.toml`` are not even contained in the wheel, so this high Pip requirement is only for source builds, and will not affect users of your binary wheels. If you are building SDists and wheels, then - `pypa-build`_ is the recommended offical tool. + `pypa-build`_ is the recommended official tool. .. _PEP 517: https://www.python.org/dev/peps/pep-0517/ .. _cibuildwheel: https://cibuildwheel.readthedocs.io @@ -411,7 +424,7 @@ existing targets instead: .. code-block:: cmake - cmake_minumum_required(VERSION 3.15...3.19) + cmake_minimum_required(VERSION 3.15...3.19) project(example LANGUAGES CXX) find_package(Python COMPONENTS Interpreter Development REQUIRED) @@ -516,7 +529,7 @@ Instead of setting properties, you can set ``CMAKE_*`` variables to initialize t compiler flags are provided to ensure high quality code generation. In contrast to the ``pybind11_add_module()`` command, the CMake interface provides a *composable* set of targets to ensure that you retain flexibility. - It can be expecially important to provide or set these properties; the + It can be especially important to provide or set these properties; the :ref:`FAQ ` contains an explanation on why these are needed. .. versionadded:: 2.6 diff --git a/thirdparty/pybind11/docs/faq.rst b/thirdparty/pybind11/docs/faq.rst index 8c0b0f9fc2..d6a048b06f 100644 --- a/thirdparty/pybind11/docs/faq.rst +++ b/thirdparty/pybind11/docs/faq.rst @@ -5,7 +5,7 @@ Frequently asked questions =========================================================== 1. Make sure that the name specified in PYBIND11_MODULE is identical to the -filename of the extension library (without suffixes such as .so) +filename of the extension library (without suffixes such as ``.so``). 2. If the above did not fix the issue, you are likely using an incompatible version of Python (for instance, the extension library was compiled against @@ -170,7 +170,7 @@ complete independence of the symbols involved when not using ``-fvisibility=hidden``. Additionally, ``-fvisibility=hidden`` can deliver considerably binary size -savings. (See the following section for more details). +savings. (See the following section for more details.) .. _`faq:symhidden`: @@ -180,7 +180,7 @@ How can I create smaller binaries? To do its job, pybind11 extensively relies on a programming technique known as *template metaprogramming*, which is a way of performing computation at compile -time using type information. Template metaprogamming usually instantiates code +time using type information. Template metaprogramming usually instantiates code involving significant numbers of deeply nested types that are either completely removed or reduced to just a few instructions during the compiler's optimization phase. However, due to the nested nature of these types, the resulting symbol diff --git a/thirdparty/pybind11/docs/limitations.rst b/thirdparty/pybind11/docs/limitations.rst index be7300cdb6..def5ad659c 100644 --- a/thirdparty/pybind11/docs/limitations.rst +++ b/thirdparty/pybind11/docs/limitations.rst @@ -57,16 +57,16 @@ clean, well written patch would likely be accepted to solve them. Python 3.9.0 warning ^^^^^^^^^^^^^^^^^^^^ -Combining older versions of pybind11 (< 2.6.0) with Python on 3.9.0 will -trigger undefined behavior that typically manifests as crashes during +Combining older versions of pybind11 (< 2.6.0) with Python on exactly 3.9.0 +will trigger undefined behavior that typically manifests as crashes during interpreter shutdown (but could also destroy your data. **You have been warned**). -This issue has been -`fixed in Python `_. As a -mitigation until 3.9.1 is released and commonly used, pybind11 (2.6.0 or newer) -includes a temporary workaround specifically when Python 3.9.0 is detected at -runtime, leaking about 50 bytes of memory when a callback function is garbage -collected. For reference; the pybind11 test suite has about 2,000 such -callbacks, but only 49 are garbage collected before the end-of-process. Wheels -built with Python 3.9.0 will correctly avoid the leak when run in Python 3.9.1. +This issue was `fixed in Python `_. +As a mitigation for this bug, pybind11 2.6.0 or newer includes a workaround +specifically when Python 3.9.0 is detected at runtime, leaking about 50 bytes +of memory when a callback function is garbage collected. For reference, the +pybind11 test suite has about 2,000 such callbacks, but only 49 are garbage +collected before the end-of-process. Wheels (even if built with Python 3.9.0) +will correctly avoid the leak when run in Python 3.9.1, and this does not +affect other 3.X versions. diff --git a/thirdparty/pybind11/docs/release.rst b/thirdparty/pybind11/docs/release.rst index 9dbff03838..e4f3d1902a 100644 --- a/thirdparty/pybind11/docs/release.rst +++ b/thirdparty/pybind11/docs/release.rst @@ -15,31 +15,33 @@ For example: For beta, ``PYBIND11_VERSION_PATCH`` should be ``Z.b1``. RC's can be ``Z.rc1``. Always include the dot (even though PEP 440 allows it to be dropped). For a -final release, this must be a simple integer. +final release, this must be a simple integer. There is also a HEX version of +the version just below. To release a new version of pybind11: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Update the version number - - Update ``PYBIND11_VERSION_MAJOR`` etc. in - ``include/pybind11/detail/common.h``. PATCH should be a simple integer. - - Update ``pybind11/_version.py`` (match above) - - Ensure that all the information in ``setup.cfg`` is up-to-date, like - supported Python versions. - - Add release date in ``docs/changelog.rst``. - - Check to make sure - `needs-changelog `_ - issues are entered in the changelog (clear the label when done). - - ``git add`` and ``git commit``, ``git push``. **Ensure CI passes**. (If it - fails due to a known flake issue, either ignore or restart CI.) + - Update ``PYBIND11_VERSION_MAJOR`` etc. in + ``include/pybind11/detail/common.h``. PATCH should be a simple integer. + - Update the version HEX just below, as well. + - Update ``pybind11/_version.py`` (match above) + - Ensure that all the information in ``setup.cfg`` is up-to-date, like + supported Python versions. + - Add release date in ``docs/changelog.rst``. + - Check to make sure + `needs-changelog `_ + issues are entered in the changelog (clear the label when done). + - ``git add`` and ``git commit``, ``git push``. **Ensure CI passes**. (If it + fails due to a known flake issue, either ignore or restart CI.) - Add a release branch if this is a new minor version, or update the existing release branch if it is a patch version - - New branch: ``git checkout -b vX.Y``, ``git push -u origin vX.Y`` - - Update branch: ``git checkout vX.Y``, ``git merge ``, ``git push`` + - New branch: ``git checkout -b vX.Y``, ``git push -u origin vX.Y`` + - Update branch: ``git checkout vX.Y``, ``git merge ``, ``git push`` - Update tags (optional; if you skip this, the GitHub release makes a - non-annotated tag for you) - - ``git tag -a vX.Y.Z -m 'vX.Y.Z release'``. - - ``git push --tags``. + non-annotated tag for you) + - ``git tag -a vX.Y.Z -m 'vX.Y.Z release'``. + - ``git push --tags``. - Update stable - ``git checkout stable`` - ``git merge master`` @@ -48,22 +50,22 @@ To release a new version of pybind11: notifications to users watching releases, and also uploads PyPI packages). (Note: if you do not use an existing tag, this creates a new lightweight tag for you, so you could skip the above step). - - GUI method: click "Create a new release" on the far right, fill in the tag - name (if you didn't tag above, it will be made here), fill in a release - name like "Version X.Y.Z", and optionally copy-and-paste the changelog into - the description (processed as markdown by Pandoc). Check "pre-release" if - this is a beta/RC. You can get partway there with - ``cat docs/changelog.rst | pandsoc -f rst -t markdown``. - - CLI method: with ``gh`` installed, run ``gh release create vX.Y.Z -t "Version X.Y.Z"`` - If this is a pre-release, add ``-p``. + - GUI method: click "Create a new release" on the far right, fill in the tag + name (if you didn't tag above, it will be made here), fill in a release + name like "Version X.Y.Z", and optionally copy-and-paste the changelog into + the description (processed as markdown by Pandoc). Check "pre-release" if + this is a beta/RC. You can get partway there with + ``cat docs/changelog.rst | pandoc -f rst -t gfm``. + - CLI method: with ``gh`` installed, run ``gh release create vX.Y.Z -t "Version X.Y.Z"`` + If this is a pre-release, add ``-p``. - Get back to work - - Make sure you are on master, not somewhere else: ``git checkout master`` - - Update version macros in ``include/pybind11/detail/common.h`` (set PATCH to - ``0.dev1`` and increment MINOR). - - Update ``_version.py`` to match - - Add a spot for in-development updates in ``docs/changelog.rst``. - - ``git add``, ``git commit``, ``git push`` + - Make sure you are on master, not somewhere else: ``git checkout master`` + - Update version macros in ``include/pybind11/detail/common.h`` (set PATCH to + ``0.dev1`` and increment MINOR). + - Update ``_version.py`` to match + - Add a spot for in-development updates in ``docs/changelog.rst``. + - ``git add``, ``git commit``, ``git push`` If a version branch is updated, remember to set PATCH to ``1.dev1``. diff --git a/thirdparty/pybind11/docs/requirements.txt b/thirdparty/pybind11/docs/requirements.txt index a1276a65d9..8f293b5d34 100644 --- a/thirdparty/pybind11/docs/requirements.txt +++ b/thirdparty/pybind11/docs/requirements.txt @@ -1,6 +1,7 @@ breathe==4.26.1 -commonmark==0.9.1 -recommonmark==0.7.1 +# docutils 0.17 breaks HTML tags & RTD theme +# https://github.com/sphinx-doc/sphinx/issues/9001 +docutils==0.16 sphinx==3.3.1 sphinx_rtd_theme==0.5.0 sphinxcontrib-moderncmakedomain==3.17 diff --git a/thirdparty/pybind11/docs/upgrade.rst b/thirdparty/pybind11/docs/upgrade.rst index 5691879c85..b2b6b12456 100644 --- a/thirdparty/pybind11/docs/upgrade.rst +++ b/thirdparty/pybind11/docs/upgrade.rst @@ -281,7 +281,7 @@ Within pybind11's CMake build system, ``pybind11_add_module`` has always been setting the ``-fvisibility=hidden`` flag in release mode. From now on, it's being applied unconditionally, even in debug mode and it can no longer be opted out of with the ``NO_EXTRAS`` option. The ``pybind11::module`` target now also -adds this flag to it's interface. The ``pybind11::embed`` target is unchanged. +adds this flag to its interface. The ``pybind11::embed`` target is unchanged. The most significant change here is for the ``pybind11::module`` target. If you were previously relying on default visibility, i.e. if your Python module was diff --git a/thirdparty/pybind11/include/pybind11/attr.h b/thirdparty/pybind11/include/pybind11/attr.h index 50efdc7cec..60ed9fd90e 100644 --- a/thirdparty/pybind11/include/pybind11/attr.h +++ b/thirdparty/pybind11/include/pybind11/attr.h @@ -62,7 +62,8 @@ struct metaclass { handle value; PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.") - metaclass() { } // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute + // NOLINTNEXTLINE(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute + metaclass() {} /// Override pybind11's default metaclass explicit metaclass(handle value) : value(value) { } @@ -377,7 +378,7 @@ template <> struct process_attribute : process_attribu }; inline void process_kw_only_arg(const arg &a, function_record *r) { - if (!a.name || strlen(a.name) == 0) + if (!a.name || a.name[0] == '\0') pybind11_fail("arg(): cannot specify an unnamed argument after an kw_only() annotation"); ++r->nargs_kw_only; } diff --git a/thirdparty/pybind11/include/pybind11/buffer_info.h b/thirdparty/pybind11/include/pybind11/buffer_info.h index d803004a10..eba68d1aa1 100644 --- a/thirdparty/pybind11/include/pybind11/buffer_info.h +++ b/thirdparty/pybind11/include/pybind11/buffer_info.h @@ -83,7 +83,7 @@ struct buffer_info { view->strides ? std::vector(view->strides, view->strides + view->ndim) : detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize), - view->readonly) { + (view->readonly != 0)) { this->m_view = view; this->ownview = ownview; } @@ -91,11 +91,9 @@ struct buffer_info { buffer_info(const buffer_info &) = delete; buffer_info& operator=(const buffer_info &) = delete; - buffer_info(buffer_info &&other) { - (*this) = std::move(other); - } + buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); } - buffer_info& operator=(buffer_info &&rhs) { + buffer_info &operator=(buffer_info &&rhs) noexcept { ptr = rhs.ptr; itemsize = rhs.itemsize; size = rhs.size; diff --git a/thirdparty/pybind11/include/pybind11/cast.h b/thirdparty/pybind11/include/pybind11/cast.h index 576299211b..898047b304 100644 --- a/thirdparty/pybind11/include/pybind11/cast.h +++ b/thirdparty/pybind11/include/pybind11/cast.h @@ -85,25 +85,28 @@ public: operator std::reference_wrapper() { return cast_op(subcaster); } }; -#define PYBIND11_TYPE_CASTER(type, py_name) \ - protected: \ - type value; \ - public: \ - static constexpr auto name = py_name; \ - template >::value, int> = 0> \ - static handle cast(T_ *src, return_value_policy policy, handle parent) { \ - if (!src) return none().release(); \ - if (policy == return_value_policy::take_ownership) { \ - auto h = cast(std::move(*src), policy, parent); delete src; return h; \ - } else { \ - return cast(*src, policy, parent); \ - } \ - } \ - operator type*() { return &value; } \ - operator type&() { return value; } \ - operator type&&() && { return std::move(value); } \ - template using cast_op_type = pybind11::detail::movable_cast_op_type - +#define PYBIND11_TYPE_CASTER(type, py_name) \ +protected: \ + type value; \ + \ +public: \ + static constexpr auto name = py_name; \ + template >::value, int> = 0> \ + static handle cast(T_ *src, return_value_policy policy, handle parent) { \ + if (!src) \ + return none().release(); \ + if (policy == return_value_policy::take_ownership) { \ + auto h = cast(std::move(*src), policy, parent); \ + delete src; \ + return h; \ + } \ + return cast(*src, policy, parent); \ + } \ + operator type *() { return &value; } \ + operator type &() { return value; } \ + operator type &&() && { return std::move(value); } \ + template \ + using cast_op_type = pybind11::detail::movable_cast_op_type template using is_std_char_type = any_of< std::is_same, /* std::string */ @@ -178,7 +181,7 @@ public: // Signed/unsigned checks happen elsewhere if (py_err || (std::is_integral::value && sizeof(py_type) != sizeof(T) && py_value != (py_type) (T) py_value)) { PyErr_Clear(); - if (py_err && convert && PyNumber_Check(src.ptr())) { + if (py_err && convert && (PyNumber_Check(src.ptr()) != 0)) { auto tmp = reinterpret_steal(std::is_floating_point::value ? PyNumber_Float(src.ptr()) : PyNumber_Long(src.ptr())); @@ -222,7 +225,7 @@ public: return PyLong_FromUnsignedLongLong((unsigned long long) src); } - PYBIND11_TYPE_CASTER(T, _x::value>("int", "float")); + PYBIND11_TYPE_CASTER(T, _::value>("int", "float")); }; template struct void_caster { @@ -235,7 +238,7 @@ public: static handle cast(T, return_value_policy /* policy */, handle /* parent */) { return none().inc_ref(); } - PYBIND11_TYPE_CASTER(T, _x("None")); + PYBIND11_TYPE_CASTER(T, _("None")); }; template <> class type_caster : public void_caster {}; @@ -247,7 +250,8 @@ public: bool load(handle h, bool) { if (!h) { return false; - } else if (h.is_none()) { + } + if (h.is_none()) { value = nullptr; return true; } @@ -272,13 +276,12 @@ public: static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) { if (ptr) return capsule(ptr).release(); - else - return none().inc_ref(); + return none().inc_ref(); } template using cast_op_type = void*&; operator void *&() { return value; } - static constexpr auto name = _x("capsule"); + static constexpr auto name = _("capsule"); private: void *value = nullptr; }; @@ -289,9 +292,15 @@ template <> class type_caster { public: bool load(handle src, bool convert) { if (!src) return false; - else if (src.ptr() == Py_True) { value = true; return true; } - else if (src.ptr() == Py_False) { value = false; return true; } - else if (convert || !std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name)) { + if (src.ptr() == Py_True) { + value = true; + return true; + } + if (src.ptr() == Py_False) { + value = false; + return true; + } + if (convert || (std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name) == 0)) { // (allow non-implicit conversion for numpy booleans) Py_ssize_t res = -1; @@ -313,18 +322,17 @@ public: } #endif if (res == 0 || res == 1) { - value = (bool) res; + value = (res != 0); return true; - } else { - PyErr_Clear(); } + PyErr_Clear(); } return false; } static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) { return handle(src ? Py_True : Py_False).inc_ref(); } - PYBIND11_TYPE_CASTER(bool, _x("bool")); + PYBIND11_TYPE_CASTER(bool, _("bool")); }; // Helper class for UTF-{8,16,32} C++ stl strings: @@ -351,7 +359,8 @@ template struct string_caster { handle load_src = src; if (!src) { return false; - } else if (!PyUnicode_Check(load_src.ptr())) { + } + if (!PyUnicode_Check(load_src.ptr())) { #if PY_MAJOR_VERSION >= 3 return load_bytes(load_src); #else @@ -393,7 +402,7 @@ template struct string_caster { return s; } - PYBIND11_TYPE_CASTER(StringType, _x(PYBIND11_STRING_NAME)); + PYBIND11_TYPE_CASTER(StringType, _(PYBIND11_STRING_NAME)); private: static handle decode_utfN(const char *buffer, ssize_t nbytes) { @@ -492,10 +501,14 @@ public: // can fit into a single char value. if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) { auto v0 = static_cast(value[0]); - size_t char0_bytes = !(v0 & 0x80) ? 1 : // low bits only: 0-127 - (v0 & 0xE0) == 0xC0 ? 2 : // 0b110xxxxx - start of 2-byte sequence - (v0 & 0xF0) == 0xE0 ? 3 : // 0b1110xxxx - start of 3-byte sequence - 4; // 0b11110xxx - start of 4-byte sequence + // low bits only: 0-127 + // 0b110xxxxx - start of 2-byte sequence + // 0b1110xxxx - start of 3-byte sequence + // 0b11110xxx - start of 4-byte sequence + size_t char0_bytes = (v0 & 0x80) == 0 ? 1 + : (v0 & 0xE0) == 0xC0 ? 2 + : (v0 & 0xF0) == 0xE0 ? 3 + : 4; if (char0_bytes == str_len) { // If we have a 128-255 value, we can decode it into a single char: @@ -524,7 +537,7 @@ public: return one_char; } - static constexpr auto name = _x(PYBIND11_STRING_NAME); + static constexpr auto name = _(PYBIND11_STRING_NAME); template using cast_op_type = pybind11::detail::cast_op_type<_T>; }; @@ -554,13 +567,14 @@ public: static handle cast(T *src, return_value_policy policy, handle parent) { if (!src) return none().release(); if (policy == return_value_policy::take_ownership) { - auto h = cast(std::move(*src), policy, parent); delete src; return h; - } else { - return cast(*src, policy, parent); + auto h = cast(std::move(*src), policy, parent); + delete src; + return h; } + return cast(*src, policy, parent); } - static constexpr auto name = _x("Tuple[") + concat(make_caster::name...) + _x("]"); + static constexpr auto name = _("Tuple[") + concat(make_caster::name...) + _("]"); template using cast_op_type = type; @@ -664,14 +678,14 @@ protected: value = v_h.value_ptr(); holder = v_h.template holder(); return true; - } else { - throw cast_error("Unable to cast from non-held to held instance (T& to Holder) " -#if defined(NDEBUG) - "(compile in debug mode for type information)"); -#else - "of type '" + type_id() + "''"); -#endif } + throw cast_error("Unable to cast from non-held to held instance (T& to Holder) " +#if defined(NDEBUG) + "(compile in debug mode for type information)"); +#else + "of type '" + + type_id() + "''"); +#endif } template ::value, int> = 0> @@ -743,14 +757,14 @@ template struct is_holder_type : template struct is_holder_type> : std::true_type {}; -template struct handle_type_name { static constexpr auto name = _x(); }; -template <> struct handle_type_name { static constexpr auto name = _x(PYBIND11_BYTES_NAME); }; -template <> struct handle_type_name { static constexpr auto name = _x("int"); }; -template <> struct handle_type_name { static constexpr auto name = _x("Iterable"); }; -template <> struct handle_type_name { static constexpr auto name = _x("Iterator"); }; -template <> struct handle_type_name { static constexpr auto name = _x("None"); }; -template <> struct handle_type_name { static constexpr auto name = _x("*args"); }; -template <> struct handle_type_name { static constexpr auto name = _x("**kwargs"); }; +template struct handle_type_name { static constexpr auto name = _(); }; +template <> struct handle_type_name { static constexpr auto name = _(PYBIND11_BYTES_NAME); }; +template <> struct handle_type_name { static constexpr auto name = _("int"); }; +template <> struct handle_type_name { static constexpr auto name = _("Iterable"); }; +template <> struct handle_type_name { static constexpr auto name = _("Iterator"); }; +template <> struct handle_type_name { static constexpr auto name = _("None"); }; +template <> struct handle_type_name { static constexpr auto name = _("*args"); }; +template <> struct handle_type_name { static constexpr auto name = _("**kwargs"); }; template struct pyobject_caster { @@ -917,8 +931,7 @@ template detail::enable_if_t::value, T> cast template detail::enable_if_t::value, T> cast(object &&object) { if (object.ref_count() > 1) return cast(object); - else - return move(std::move(object)); + return move(std::move(object)); } template detail::enable_if_t::value, T> cast(object &&object) { return cast(object); @@ -958,6 +971,21 @@ template <> inline void cast_safe(object &&) {} PYBIND11_NAMESPACE_END(detail) +// The overloads could coexist, i.e. the #if is not strictly speaking needed, +// but it is an easy minor optimization. +#if defined(NDEBUG) +inline cast_error cast_error_unable_to_convert_call_arg() { + return cast_error( + "Unable to convert call argument to Python object (compile in debug mode for details)"); +} +#else +inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name, + const std::string &type) { + return cast_error("Unable to convert call argument '" + name + "' of type '" + type + + "' to Python object"); +} +#endif + template tuple make_tuple() { return tuple(0); } @@ -971,11 +999,10 @@ template argtypes { {type_id()...} }; - throw cast_error("make_tuple(): unable to convert argument of type '" + - argtypes[i] + "' to Python object"); + throw cast_error_unable_to_convert_call_arg(std::to_string(i), argtypes[i]); #endif } } @@ -1064,7 +1091,9 @@ struct kw_only {}; struct pos_only {}; template -arg_v arg::operator=(T &&value) const { return {std::move(*this), std::forward(value)}; } +arg_v arg::operator=(T &&value) const { + return {*this, std::forward(value)}; +} /// Alias for backward compatibility -- to be removed in version 2.0 template using arg_t = arg_v; @@ -1228,9 +1257,10 @@ private: auto o = reinterpret_steal(detail::make_caster::cast(std::forward(x), policy, {})); if (!o) { #if defined(NDEBUG) - argument_cast_error(); + throw cast_error_unable_to_convert_call_arg(); #else - argument_cast_error(std::to_string(args_list.size()), type_id()); + throw cast_error_unable_to_convert_call_arg( + std::to_string(args_list.size()), type_id()); #endif } args_list.append(o); @@ -1258,9 +1288,9 @@ private: } if (!a.value) { #if defined(NDEBUG) - argument_cast_error(); + throw cast_error_unable_to_convert_call_arg(); #else - argument_cast_error(a.name, a.type); + throw cast_error_unable_to_convert_call_arg(a.name, a.type); #endif } m_kwargs[a.name] = a.value; @@ -1286,7 +1316,7 @@ private: "may be passed via py::arg() to a python function call. " "(compile in debug mode for details)"); } - [[noreturn]] static void nameless_argument_error(std::string type) { + [[noreturn]] static void nameless_argument_error(const std::string &type) { throw type_error("Got kwargs without a name of type '" + type + "'; only named " "arguments may be passed via py::arg() to a python function call. "); } @@ -1295,20 +1325,10 @@ private: "(compile in debug mode for details)"); } - [[noreturn]] static void multiple_values_error(std::string name) { + [[noreturn]] static void multiple_values_error(const std::string &name) { throw type_error("Got multiple values for keyword argument '" + name + "'"); } - [[noreturn]] static void argument_cast_error() { - throw cast_error("Unable to convert call argument to Python object " - "(compile in debug mode for details)"); - } - - [[noreturn]] static void argument_cast_error(std::string name, std::string type) { - throw cast_error("Unable to convert call argument '" + name - + "' of type '" + type + "' to Python object"); - } - private: tuple m_args; dict m_kwargs; @@ -1348,6 +1368,11 @@ unpacking_collector collect_arguments(Args &&...args) { template template object object_api::operator()(Args &&...args) const { +#if !defined(NDEBUG) && PY_VERSION_HEX >= 0x03060000 + if (!PyGILState_Check()) { + pybind11_fail("pybind11::object_api<>::operator() PyGILState_Check() failure."); + } +#endif return detail::collect_arguments(std::forward(args)...).call(derived().ptr()); } diff --git a/thirdparty/pybind11/include/pybind11/chrono.h b/thirdparty/pybind11/include/pybind11/chrono.h index 551a802ad3..61bbcbc540 100644 --- a/thirdparty/pybind11/include/pybind11/chrono.h +++ b/thirdparty/pybind11/include/pybind11/chrono.h @@ -11,9 +11,14 @@ #pragma once #include "pybind11.h" + +#include #include #include -#include +#include + +#include + #include // Backport the PyDateTime_DELTA functions from Python3.3 if required @@ -35,7 +40,7 @@ public: using rep = typename type::rep; using period = typename type::period; - using days = std::chrono::duration>; + using days = std::chrono::duration>; // signed 25 bits required by the standard. bool load(handle src, bool) { using namespace std::chrono; @@ -53,11 +58,11 @@ public: return true; } // If invoked with a float we assume it is seconds and convert - else if (PyFloat_Check(src.ptr())) { + if (PyFloat_Check(src.ptr())) { value = type(duration_cast>(duration(PyFloat_AsDouble(src.ptr())))); return true; } - else return false; + return false; } // If this is a duration just return it back @@ -95,6 +100,22 @@ public: PYBIND11_TYPE_CASTER(type, _("datetime.timedelta")); }; +inline std::tm *localtime_thread_safe(const std::time_t *time, std::tm *buf) { +#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || defined(_MSC_VER) + if (localtime_s(buf, time)) + return nullptr; + return buf; +#else + static std::mutex mtx; + std::lock_guard lock(mtx); + std::tm *tm_ptr = localtime(time); + if (tm_ptr != nullptr) { + *buf = *tm_ptr; + } + return tm_ptr; +#endif +} + // This is for casting times on the system clock into datetime.datetime instances template class type_caster> { public: @@ -162,16 +183,10 @@ public: // (https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t) std::time_t tt = system_clock::to_time_t(time_point_cast(src - us)); - // std::localtime returns a pointer to a static internal std::tm object on success, - // or null pointer otherwise - std::tm *localtime_ptr = std::localtime(&tt); + std::tm localtime; + std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime); if (!localtime_ptr) throw cast_error("Unable to represent system_clock in local time"); - - // this function uses static memory so it's best to copy it out asap just in case - // otherwise other code that is using localtime may break this (not just python code) - std::tm localtime = *localtime_ptr; - return PyDateTime_FromDateAndTime(localtime.tm_year + 1900, localtime.tm_mon + 1, localtime.tm_mday, diff --git a/thirdparty/pybind11/include/pybind11/detail/class.h b/thirdparty/pybind11/include/pybind11/detail/class.h index 2f414e5c7c..4951830684 100644 --- a/thirdparty/pybind11/include/pybind11/detail/class.h +++ b/thirdparty/pybind11/include/pybind11/detail/class.h @@ -129,8 +129,9 @@ extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyOb // 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop` // 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment const auto static_prop = (PyObject *) get_internals().static_property_type; - const auto call_descr_set = descr && value && PyObject_IsInstance(descr, static_prop) - && !PyObject_IsInstance(value, static_prop); + const auto call_descr_set = (descr != nullptr) && (value != nullptr) + && (PyObject_IsInstance(descr, static_prop) != 0) + && (PyObject_IsInstance(value, static_prop) == 0); if (call_descr_set) { // Call `static_property.__set__()` instead of replacing the `static_property`. #if !defined(PYPY_VERSION) @@ -162,9 +163,7 @@ extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name Py_INCREF(descr); return descr; } - else { - return PyType_Type.tp_getattro(obj, name); - } + return PyType_Type.tp_getattro(obj, name); } #endif @@ -329,7 +328,7 @@ inline bool deregister_instance(instance *self, void *valptr, const type_info *t inline PyObject *make_new_instance(PyTypeObject *type) { #if defined(PYPY_VERSION) // PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first inherited - // object is a a plain Python type (i.e. not derived from an extension type). Fix it. + // object is a plain Python type (i.e. not derived from an extension type). Fix it. ssize_t instance_size = static_cast(sizeof(instance)); if (type->tp_basicsize < instance_size) { type->tp_basicsize = instance_size; @@ -564,7 +563,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla view->len = view->itemsize; for (auto s : info->shape) view->len *= s; - view->readonly = info->readonly; + view->readonly = static_cast(info->readonly); if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) view->format = const_cast(info->format.c_str()); if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { diff --git a/thirdparty/pybind11/include/pybind11/detail/common.h b/thirdparty/pybind11/include/pybind11/detail/common.h index f08030914e..dfd5b5699f 100644 --- a/thirdparty/pybind11/include/pybind11/detail/common.h +++ b/thirdparty/pybind11/include/pybind11/detail/common.h @@ -10,8 +10,12 @@ #pragma once #define PYBIND11_VERSION_MAJOR 2 -#define PYBIND11_VERSION_MINOR 6 -#define PYBIND11_VERSION_PATCH 3.dev1 +#define PYBIND11_VERSION_MINOR 7 +#define PYBIND11_VERSION_PATCH 1 + +// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html +// Additional convention: 0xD = dev +#define PYBIND11_VERSION_HEX 0x02070100 #define PYBIND11_NAMESPACE_BEGIN(name) namespace name { #define PYBIND11_NAMESPACE_END(name) } @@ -52,6 +56,9 @@ # elif __INTEL_COMPILER < 1900 && defined(PYBIND11_CPP14) # error pybind11 supports only C++11 with Intel C++ compiler v18. Use v19 or newer for C++14. # endif +/* The following pragma cannot be pop'ed: + https://community.intel.com/t5/Intel-C-Compiler/Inline-and-no-inline-warning/td-p/1216764 */ +# pragma warning disable 2196 // warning #2196: routine is both "inline" and "noinline" #elif defined(__clang__) && !defined(__apple_build_version__) # if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3) # error pybind11 requires clang 3.3 or newer @@ -82,13 +89,27 @@ # endif #endif +#if !defined(PYBIND11_EXPORT_EXCEPTION) +# ifdef __MINGW32__ +// workaround for: +// error: 'dllexport' implies default visibility, but xxx has already been declared with a different visibility +# define PYBIND11_EXPORT_EXCEPTION +# else +# define PYBIND11_EXPORT_EXCEPTION PYBIND11_EXPORT +# endif +#endif + #if defined(_MSC_VER) # define PYBIND11_NOINLINE __declspec(noinline) #else # define PYBIND11_NOINLINE __attribute__ ((noinline)) #endif -#if defined(PYBIND11_CPP14) +#if defined(__MINGW32__) +// For unknown reasons all PYBIND11_DEPRECATED member trigger a warning when declared +// whether it is used or not +# define PYBIND11_DEPRECATED(reason) +#elif defined(PYBIND11_CPP14) # define PYBIND11_DEPRECATED(reason) [[deprecated(reason)]] #else # define PYBIND11_DEPRECATED(reason) __attribute__((deprecated(reason))) @@ -108,12 +129,23 @@ # define HAVE_SNPRINTF 1 #endif +/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) # if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 4) # define HAVE_ROUND 1 # endif # pragma warning(push) -# pragma warning(disable: 4510 4610 4512 4005) +// C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed (PyPy only) +# pragma warning(disable: 4505) +# if defined(_DEBUG) && !defined(Py_DEBUG) +# define PYBIND11_DEBUG_MARKER +# undef _DEBUG +# endif +#endif + +// https://en.cppreference.com/w/c/chrono/localtime +#if defined(__STDC_LIB_EXT1__) && !defined(__STDC_WANT_LIB_EXT1__) +# define __STDC_WANT_LIB_EXT1__ #endif #include @@ -475,7 +507,7 @@ struct instance { void allocate_layout(); /// Destroys/deallocates all of the above - void deallocate_layout(); + void deallocate_layout() const; /// Returns the value_and_holder wrapper for the given type (or the first, if `find_type` /// omitted). Returns a default-constructed (with `.inst = nullptr`) object on failure if @@ -718,16 +750,23 @@ using expand_side_effects = bool[]; PYBIND11_NAMESPACE_END(detail) +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4275) // warning C4275: An exported class was derived from a class that wasn't exported. Can be ignored when derived from a STL class. +#endif /// C++ bindings of builtin Python exceptions -class builtin_exception : public std::runtime_error { +class PYBIND11_EXPORT_EXCEPTION builtin_exception : public std::runtime_error { public: using std::runtime_error::runtime_error; /// Set the error using the Python C API virtual void set_error() const = 0; }; +#if defined(_MSC_VER) +# pragma warning(pop) +#endif #define PYBIND11_RUNTIME_EXCEPTION(name, type) \ - class name : public builtin_exception { public: \ + class PYBIND11_EXPORT_EXCEPTION name : public builtin_exception { public: \ using builtin_exception::builtin_exception; \ name() : name("") { } \ void set_error() const override { PyErr_SetString(type, what()); } \ @@ -789,7 +828,8 @@ struct nodelete { template void operator()(T*) { } }; PYBIND11_NAMESPACE_BEGIN(detail) template struct overload_cast_impl { - constexpr overload_cast_impl() {}; // NOLINT(modernize-use-equals-default): MSVC 2015 needs this + // NOLINTNEXTLINE(modernize-use-equals-default): MSVC 2015 needs this + constexpr overload_cast_impl() {} template constexpr auto operator()(Return (*pf)(Args...)) const noexcept diff --git a/thirdparty/pybind11/include/pybind11/detail/descr.h b/thirdparty/pybind11/include/pybind11/detail/descr.h index 5c41c05a77..7cb8350e7b 100644 --- a/thirdparty/pybind11/include/pybind11/detail/descr.h +++ b/thirdparty/pybind11/include/pybind11/detail/descr.h @@ -23,9 +23,9 @@ PYBIND11_NAMESPACE_BEGIN(detail) /* Concatenate type signatures at compile time */ template struct descr { - char text[N + 1]; + char text[N + 1]{'\0'}; - constexpr descr() : text{'\0'} { } + constexpr descr() = default; constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence()) { } template @@ -51,8 +51,8 @@ constexpr descr operator+(const descr &a, c } template -constexpr descr _x(char const(&text)[N]) { return descr(text); } -constexpr descr<0> _x(char const(&)[1]) { return {}; } +constexpr descr _(char const(&text)[N]) { return descr(text); } +constexpr descr<0> _(char const(&)[1]) { return {}; } template struct int_to_str : int_to_str { }; template struct int_to_str<0, Digits...> { @@ -61,24 +61,24 @@ template struct int_to_str<0, Digits...> { // Ternary description (like std::conditional) template -constexpr enable_if_t> _x(char const(&text1)[N1], char const(&)[N2]) { - return _x(text1); +constexpr enable_if_t> _(char const(&text1)[N1], char const(&)[N2]) { + return _(text1); } template -constexpr enable_if_t> _x(char const(&)[N1], char const(&text2)[N2]) { - return _x(text2); +constexpr enable_if_t> _(char const(&)[N1], char const(&text2)[N2]) { + return _(text2); } template -constexpr enable_if_t _x(const T1 &d, const T2 &) { return d; } +constexpr enable_if_t _(const T1 &d, const T2 &) { return d; } template -constexpr enable_if_t _x(const T1 &, const T2 &d) { return d; } +constexpr enable_if_t _(const T1 &, const T2 &d) { return d; } -template auto constexpr _x() -> decltype(int_to_str::digits) { +template auto constexpr _() -> decltype(int_to_str::digits) { return int_to_str::digits; } -template constexpr descr<1, Type> _x() { return {'%'}; } +template constexpr descr<1, Type> _() { return {'%'}; } constexpr descr<0> concat() { return {}; } @@ -88,12 +88,12 @@ constexpr descr concat(const descr &descr) { return descr; } template constexpr auto concat(const descr &d, const Args &...args) -> decltype(std::declval>() + concat(args...)) { - return d + _x(", ") + concat(args...); + return d + _(", ") + concat(args...); } template constexpr descr type_descr(const descr &descr) { - return _x("{") + descr + _x("}"); + return _("{") + descr + _("}"); } PYBIND11_NAMESPACE_END(detail) diff --git a/thirdparty/pybind11/include/pybind11/detail/init.h b/thirdparty/pybind11/include/pybind11/detail/init.h index e4734defa4..3269e04254 100644 --- a/thirdparty/pybind11/include/pybind11/detail/init.h +++ b/thirdparty/pybind11/include/pybind11/detail/init.h @@ -24,7 +24,7 @@ public: template using cast_op_type = value_and_holder &; operator value_and_holder &() { return *value; } - static constexpr auto name = _x(); + static constexpr auto name = _(); private: value_and_holder *value = nullptr; @@ -293,7 +293,13 @@ template ::value, int> = 0> void setstate(value_and_holder &v_h, std::pair &&result, bool need_alias) { construct(v_h, std::move(result.first), need_alias); - setattr((PyObject *) v_h.inst, "__dict__", result.second); + auto d = handle(result.second); + if (PyDict_Check(d.ptr()) && PyDict_Size(d.ptr()) == 0) { + // Skipping setattr below, to not force use of py::dynamic_attr() for Class unnecessarily. + // See PR #2972 for details. + return; + } + setattr((PyObject *) v_h.inst, "__dict__", d); } /// Implementation for py::pickle(GetState, SetState) diff --git a/thirdparty/pybind11/include/pybind11/detail/internals.h b/thirdparty/pybind11/include/pybind11/detail/internals.h index 75fcd3c208..273a0dbaf6 100644 --- a/thirdparty/pybind11/include/pybind11/detail/internals.h +++ b/thirdparty/pybind11/include/pybind11/detail/internals.h @@ -276,6 +276,8 @@ PYBIND11_NOINLINE inline internals &get_internals() { // initial exception translator, below, so add another for our local exception classes. // // libstdc++ doesn't require this (types there are identified only by name) + // libc++ with CPython doesn't require this (types are explicitly exported) + // libc++ with PyPy still need it, awaiting further investigation #if !defined(__GLIBCXX__) (*internals_pp)->registered_exception_translators.push_front(&translate_local_exception); #endif @@ -291,7 +293,7 @@ PYBIND11_NOINLINE inline internals &get_internals() { PyThreadState *tstate = PyThreadState_Get(); #if PY_VERSION_HEX >= 0x03070000 internals_ptr->tstate = PyThread_tss_alloc(); - if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate)) + if (!internals_ptr->tstate || (PyThread_tss_create(internals_ptr->tstate) != 0)) pybind11_fail("get_internals: could not successfully initialize the TSS key!"); PyThread_tss_set(internals_ptr->tstate, tstate); #else diff --git a/thirdparty/pybind11/include/pybind11/detail/type_caster_base.h b/thirdparty/pybind11/include/pybind11/detail/type_caster_base.h index 52dd304cdd..7a74133f6e 100644 --- a/thirdparty/pybind11/include/pybind11/detail/type_caster_base.h +++ b/thirdparty/pybind11/include/pybind11/detail/type_caster_base.h @@ -231,17 +231,17 @@ struct value_and_holder { return reinterpret_cast(vh[0]); } // True if this `value_and_holder` has a non-null value pointer - explicit operator bool() const { return value_ptr(); } + explicit operator bool() const { return value_ptr() != nullptr; } template H &holder() const { return reinterpret_cast(vh[1]); } bool holder_constructed() const { return inst->simple_layout - ? inst->simple_holder_constructed - : inst->nonsimple.status[index] & instance::status_holder_constructed; + ? inst->simple_holder_constructed + : (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u; } - void set_holder_constructed(bool v = true) { + void set_holder_constructed(bool v = true) const { if (inst->simple_layout) inst->simple_holder_constructed = v; else if (v) @@ -252,9 +252,9 @@ struct value_and_holder { bool instance_registered() const { return inst->simple_layout ? inst->simple_instance_registered - : inst->nonsimple.status[index] & instance::status_instance_registered; + : ((inst->nonsimple.status[index] & instance::status_instance_registered) != 0); } - void set_instance_registered(bool v = true) { + void set_instance_registered(bool v = true) const { if (inst->simple_layout) inst->simple_instance_registered = v; else if (v) @@ -397,7 +397,7 @@ PYBIND11_NOINLINE inline void instance::allocate_layout() { owned = true; } -PYBIND11_NOINLINE inline void instance::deallocate_layout() { +PYBIND11_NOINLINE inline void instance::deallocate_layout() const { if (!simple_layout) PyMem_Free(nonsimple.values_and_holders); } @@ -657,12 +657,6 @@ public: PYBIND11_NOINLINE bool load_impl(handle src, bool convert) { if (!src) return false; if (!typeinfo) return try_load_foreign_module_local(src); - if (src.is_none()) { - // Defer accepting None to other overloads (if we aren't in convert mode): - if (!convert) return false; - value = nullptr; - return true; - } auto &this_ = static_cast(*this); this_.check_holder_compat(); @@ -676,7 +670,7 @@ public: return true; } // Case 2: We have a derived class - else if (PyType_IsSubtype(srctype, typeinfo->type)) { + if (PyType_IsSubtype(srctype, typeinfo->type)) { auto &bases = all_type_info(srctype); bool no_cpp_mi = typeinfo->simple_type; @@ -693,7 +687,7 @@ public: // Case 2b: the python type inherits from multiple C++ bases. Check the bases to see if // we can find an exact match (or, for a simple C++ type, an inherited match); if so, we // can safely reinterpret_cast to the relevant pointer. - else if (bases.size() > 1) { + if (bases.size() > 1) { for (auto base : bases) { if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type) : base->type == typeinfo->type) { this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder(base)); @@ -731,7 +725,19 @@ public: } // Global typeinfo has precedence over foreign module_local - return try_load_foreign_module_local(src); + if (try_load_foreign_module_local(src)) { + return true; + } + + // Custom converters didn't take None, now we convert None to nullptr. + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) return false; + value = nullptr; + return true; + } + + return false; } @@ -859,7 +865,7 @@ template class type_caster_base : public type_caster_generic { using itype = intrinsic_t; public: - static constexpr auto name = _x(); + static constexpr auto name = _(); type_caster_base() : type_caster_base(typeid(type)) { } explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { } diff --git a/thirdparty/pybind11/include/pybind11/eigen.h b/thirdparty/pybind11/include/pybind11/eigen.h index e8c6f63391..218fe27034 100644 --- a/thirdparty/pybind11/include/pybind11/eigen.h +++ b/thirdparty/pybind11/include/pybind11/eigen.h @@ -169,21 +169,18 @@ template struct EigenProps { return false; // Vector size mismatch return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride}; } - else if (fixed) { + if (fixed) { // The type has a fixed size, but is not a vector: abort return false; } - else if (fixed_cols) { + if (fixed_cols) { // Since this isn't a vector, cols must be != 1. We allow this only if it exactly // equals the number of elements (rows is Dynamic, and so 1 row is allowed). if (cols != n) return false; return {1, n, stride}; - } - else { - // Otherwise it's either fully dynamic, or column dynamic; both become a column vector + } // Otherwise it's either fully dynamic, or column dynamic; both become a column vector if (fixed_rows && rows != n) return false; return {n, 1, stride}; - } } static constexpr bool show_writeable = is_eigen_dense_map::value && is_eigen_mutable_map::value; diff --git a/thirdparty/pybind11/include/pybind11/embed.h b/thirdparty/pybind11/include/pybind11/embed.h index 204aaf989f..abb1cd3cca 100644 --- a/thirdparty/pybind11/include/pybind11/embed.h +++ b/thirdparty/pybind11/include/pybind11/embed.h @@ -76,7 +76,7 @@ struct embedded_module { using init_t = void (*)(); #endif embedded_module(const char *name, init_t init) { - if (Py_IsInitialized()) + if (Py_IsInitialized() != 0) pybind11_fail("Can't add new modules after the interpreter has been initialized"); auto result = PyImport_AppendInittab(name, init); @@ -101,7 +101,7 @@ PYBIND11_NAMESPACE_END(detail) .. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx \endrst */ inline void initialize_interpreter(bool init_signal_handlers = true) { - if (Py_IsInitialized()) + if (Py_IsInitialized() != 0) pybind11_fail("The interpreter is already running"); Py_InitializeEx(init_signal_handlers ? 1 : 0); diff --git a/thirdparty/pybind11/include/pybind11/eval.h b/thirdparty/pybind11/include/pybind11/eval.h index fa6b8af479..33fcdc09d1 100644 --- a/thirdparty/pybind11/include/pybind11/eval.h +++ b/thirdparty/pybind11/include/pybind11/eval.h @@ -11,6 +11,8 @@ #pragma once +#include + #include "pybind11.h" PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) @@ -43,7 +45,7 @@ enum eval_mode { }; template -object eval(str expr, object global = globals(), object local = object()) { +object eval(const str &expr, object global = globals(), object local = object()) { if (!local) local = global; @@ -53,7 +55,7 @@ object eval(str expr, object global = globals(), object local = object()) { this seems to be the only alternative */ std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr; - int start; + int start = 0; switch (mode) { case eval_expr: start = Py_eval_input; break; case eval_single_statement: start = Py_single_input; break; @@ -75,8 +77,8 @@ object eval(const char (&s)[N], object global = globals(), object local = object return eval(expr, global, local); } -inline void exec(str expr, object global = globals(), object local = object()) { - eval(expr, global, local); +inline void exec(const str &expr, object global = globals(), object local = object()) { + eval(expr, std::move(global), std::move(local)); } template @@ -105,7 +107,7 @@ object eval_file(str fname, object global = globals(), object local = object()) detail::ensure_builtins_in_globals(global); - int start; + int start = 0; switch (mode) { case eval_expr: start = Py_eval_input; break; case eval_single_statement: start = Py_single_input; break; diff --git a/thirdparty/pybind11/include/pybind11/functional.h b/thirdparty/pybind11/include/pybind11/functional.h index 92c17dc225..bc8a8af821 100644 --- a/thirdparty/pybind11/include/pybind11/functional.h +++ b/thirdparty/pybind11/include/pybind11/functional.h @@ -43,24 +43,38 @@ public: captured variables), in which case the roundtrip can be avoided. */ if (auto cfunc = func.cpp_function()) { - auto c = reinterpret_borrow(PyCFunction_GET_SELF(cfunc.ptr())); - auto rec = (function_record *) c; + auto cfunc_self = PyCFunction_GET_SELF(cfunc.ptr()); + if (isinstance(cfunc_self)) { + auto c = reinterpret_borrow(cfunc_self); + auto rec = (function_record *) c; - if (rec && rec->is_stateless && - same_type(typeid(function_type), *reinterpret_cast(rec->data[1]))) { - struct capture { function_type f; }; - value = ((capture *) &rec->data)->f; - return true; + while (rec != nullptr) { + if (rec->is_stateless + && same_type(typeid(function_type), + *reinterpret_cast(rec->data[1]))) { + struct capture { + function_type f; + }; + value = ((capture *) &rec->data)->f; + return true; + } + rec = rec->next; + } } + // PYPY segfaults here when passing builtin function like sum. + // Raising an fail exception here works to prevent the segfault, but only on gcc. + // See PR #1413 for full details } // ensure GIL is held during functor destruction struct func_handle { function f; - func_handle(function&& f_) : f(std::move(f_)) {} - func_handle(const func_handle& f_) { + func_handle(function &&f_) noexcept : f(std::move(f_)) {} + func_handle(const func_handle &f_) { operator=(f_); } + func_handle &operator=(const func_handle &f_) { gil_scoped_acquire acq; f = f_.f; + return *this; } ~func_handle() { gil_scoped_acquire acq; @@ -71,7 +85,7 @@ public: // to emulate 'move initialization capture' in C++11 struct func_wrapper { func_handle hfunc; - func_wrapper(func_handle&& hf): hfunc(std::move(hf)) {} + func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {} Return operator()(Args... args) const { gil_scoped_acquire acq; object retval(hfunc.f(std::forward(args)...)); @@ -92,8 +106,7 @@ public: auto result = f_.template target(); if (result) return cpp_function(*result, policy).release(); - else - return cpp_function(std::forward(f_), policy).release(); + return cpp_function(std::forward(f_), policy).release(); } PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster::name...) + _("], ") diff --git a/thirdparty/pybind11/include/pybind11/iostream.h b/thirdparty/pybind11/include/pybind11/iostream.h index 9dee755431..e4d2095857 100644 --- a/thirdparty/pybind11/include/pybind11/iostream.h +++ b/thirdparty/pybind11/include/pybind11/iostream.h @@ -5,17 +5,31 @@ All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + + WARNING: The implementation in this file is NOT thread safe. Multiple + threads writing to a redirected ostream concurrently cause data races + and potentially buffer overflows. Therefore it is currently a requirement + that all (possibly) concurrent redirected ostream writes are protected by + a mutex. + #HelpAppreciated: Work on iostream.h thread safety. + For more background see the discussions under + https://github.com/pybind/pybind11/pull/2982 and + https://github.com/pybind/pybind11/pull/2995. */ #pragma once #include "pybind11.h" -#include -#include -#include -#include +#include +#include #include +#include +#include +#include +#include +#include +#include PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) @@ -38,25 +52,68 @@ private: return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof(); } - // This function must be non-virtual to be called in a destructor. If the - // rare MSVC test failure shows up with this version, then this should be - // simplified to a fully qualified call. + // Computes how many bytes at the end of the buffer are part of an + // incomplete sequence of UTF-8 bytes. + // Precondition: pbase() < pptr() + size_t utf8_remainder() const { + const auto rbase = std::reverse_iterator(pbase()); + const auto rpptr = std::reverse_iterator(pptr()); + auto is_ascii = [](char c) { + return (static_cast(c) & 0x80) == 0x00; + }; + auto is_leading = [](char c) { + return (static_cast(c) & 0xC0) == 0xC0; + }; + auto is_leading_2b = [](char c) { + return static_cast(c) <= 0xDF; + }; + auto is_leading_3b = [](char c) { + return static_cast(c) <= 0xEF; + }; + // If the last character is ASCII, there are no incomplete code points + if (is_ascii(*rpptr)) + return 0; + // Otherwise, work back from the end of the buffer and find the first + // UTF-8 leading byte + const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase; + const auto leading = std::find_if(rpptr, rpend, is_leading); + if (leading == rbase) + return 0; + const auto dist = static_cast(leading - rpptr); + size_t remainder = 0; + + if (dist == 0) + remainder = 1; // 1-byte code point is impossible + else if (dist == 1) + remainder = is_leading_2b(*leading) ? 0 : dist + 1; + else if (dist == 2) + remainder = is_leading_3b(*leading) ? 0 : dist + 1; + // else if (dist >= 3), at least 4 bytes before encountering an UTF-8 + // leading byte, either no remainder or invalid UTF-8. + // Invalid UTF-8 will cause an exception later when converting + // to a Python string, so that's not handled here. + return remainder; + } + + // This function must be non-virtual to be called in a destructor. int _sync() { - if (pbase() != pptr()) { - - { - gil_scoped_acquire tmp; - - // This subtraction cannot be negative, so dropping the sign. - str line(pbase(), static_cast(pptr() - pbase())); + if (pbase() != pptr()) { // If buffer is not empty + gil_scoped_acquire tmp; + // This subtraction cannot be negative, so dropping the sign. + auto size = static_cast(pptr() - pbase()); + size_t remainder = utf8_remainder(); + if (size > remainder) { + str line(pbase(), size - remainder); pywrite(line); pyflush(); - - // Placed inside gil_scoped_aquire as a mutex to avoid a race - setp(pbase(), epptr()); } + // Copy the remainder at the end of the buffer to the beginning: + if (remainder > 0) + std::memmove(pbase(), pptr() - remainder, remainder); + setp(pbase(), epptr()); + pbump(static_cast(remainder)); } return 0; } @@ -66,11 +123,8 @@ private: } public: - - pythonbuf(object pyostream, size_t buffer_size = 1024) - : buf_size(buffer_size), - d_buffer(new char[buf_size]), - pywrite(pyostream.attr("write")), + pythonbuf(const object &pyostream, size_t buffer_size = 1024) + : buf_size(buffer_size), d_buffer(new char[buf_size]), pywrite(pyostream.attr("write")), pyflush(pyostream.attr("flush")) { setp(d_buffer.get(), d_buffer.get() + buf_size - 1); } @@ -117,9 +171,8 @@ protected: detail::pythonbuf buffer; public: - scoped_ostream_redirect( - std::ostream &costream = std::cout, - object pyostream = module_::import("sys").attr("stdout")) + scoped_ostream_redirect(std::ostream &costream = std::cout, + const object &pyostream = module_::import("sys").attr("stdout")) : costream(costream), buffer(pyostream) { old = costream.rdbuf(&buffer); } @@ -148,10 +201,9 @@ public: \endrst */ class scoped_estream_redirect : public scoped_ostream_redirect { public: - scoped_estream_redirect( - std::ostream &costream = std::cerr, - object pyostream = module_::import("sys").attr("stderr")) - : scoped_ostream_redirect(costream,pyostream) {} + scoped_estream_redirect(std::ostream &costream = std::cerr, + const object &pyostream = module_::import("sys").attr("stderr")) + : scoped_ostream_redirect(costream, pyostream) {} }; @@ -210,11 +262,12 @@ PYBIND11_NAMESPACE_END(detail) m.noisy_function_with_error_printing() \endrst */ -inline class_ add_ostream_redirect(module_ m, std::string name = "ostream_redirect") { - return class_(m, name.c_str(), module_local()) - .def(init(), arg("stdout")=true, arg("stderr")=true) +inline class_ +add_ostream_redirect(module_ m, const std::string &name = "ostream_redirect") { + return class_(std::move(m), name.c_str(), module_local()) + .def(init(), arg("stdout") = true, arg("stderr") = true) .def("__enter__", &detail::OstreamRedirect::enter) - .def("__exit__", [](detail::OstreamRedirect &self_, args) { self_.exit(); }); + .def("__exit__", [](detail::OstreamRedirect &self_, const args &) { self_.exit(); }); } PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/thirdparty/pybind11/include/pybind11/numpy.h b/thirdparty/pybind11/include/pybind11/numpy.h index d1ddc4a9db..7313897fe1 100644 --- a/thirdparty/pybind11/include/pybind11/numpy.h +++ b/thirdparty/pybind11/include/pybind11/numpy.h @@ -164,10 +164,10 @@ struct npy_api { NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_), }; - typedef struct { + struct PyArray_Dims { Py_intptr_t *ptr; int len; - } PyArray_Dims; + }; static npy_api& get() { static npy_api api = lookup(); @@ -319,14 +319,13 @@ template using remove_all_extents_t = typename array_info::type; template using is_pod_struct = all_of< std::is_standard_layout, // since we're accessing directly in memory we need a standard layout type -#if !defined(__GNUG__) || defined(_LIBCPP_VERSION) || defined(_GLIBCXX_USE_CXX11_ABI) - // _GLIBCXX_USE_CXX11_ABI indicates that we're using libstdc++ from GCC 5 or newer, independent - // of the actual compiler (Clang can also use libstdc++, but it always defines __GNUC__ == 4). - std::is_trivially_copyable, -#else - // GCC 4 doesn't implement is_trivially_copyable, so approximate it +#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150623 || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803) + // libstdc++ < 5 (including versions 4.8.5, 4.9.3 and 4.9.4 which were released after 5) + // don't implement is_trivially_copyable, so approximate it std::is_trivially_destructible, satisfies_any_of, +#else + std::is_trivially_copyable, #endif satisfies_none_of >; @@ -466,7 +465,9 @@ public: explicit dtype(const buffer_info &info) { dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format))); // If info.itemsize == 0, use the value calculated from the format string - m_ptr = descr.strip_padding(info.itemsize ? info.itemsize : descr.itemsize()).release().ptr(); + m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize()) + .release() + .ptr(); } explicit dtype(const std::string &format) { @@ -487,7 +488,7 @@ public: /// This is essentially the same as calling numpy.dtype(args) in Python. static dtype from_args(object args) { PyObject *ptr = nullptr; - if (!detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) || !ptr) + if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr) throw error_already_set(); return reinterpret_steal(ptr); } @@ -543,7 +544,7 @@ private: auto name = spec[0].cast(); auto format = spec[1].cast()[0].cast(); auto offset = spec[1].cast()[1].cast(); - if (!len(name) && format.kind() == 'V') + if ((len(name) == 0u) && format.kind() == 'V') continue; field_descriptors.push_back({(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset}); } @@ -873,11 +874,12 @@ public: : array(std::move(shape), std::move(strides), ptr, base) { } explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle()) - : array_t(private_ctor{}, std::move(shape), - ExtraFlags & f_style - ? detail::f_strides(*shape, itemsize()) - : detail::c_strides(*shape, itemsize()), - ptr, base) { } + : array_t(private_ctor{}, + std::move(shape), + (ExtraFlags & f_style) != 0 ? detail::f_strides(*shape, itemsize()) + : detail::c_strides(*shape, itemsize()), + ptr, + base) {} explicit array_t(ssize_t count, const T *ptr = nullptr, handle base = handle()) : array({count}, {}, ptr, base) { } @@ -1030,7 +1032,10 @@ struct npy_format_descriptor_name::value>> { template struct npy_format_descriptor_name::value>> { - static constexpr auto name = _::value || std::is_same::value>( + static constexpr auto name = _::value + || std::is_same::value + || std::is_same::value + || std::is_same::value>( _("numpy.float") + _(), _("numpy.longdouble") ); }; @@ -1038,7 +1043,9 @@ struct npy_format_descriptor_name::valu template struct npy_format_descriptor_name::value>> { static constexpr auto name = _::value - || std::is_same::value>( + || std::is_same::value + || std::is_same::value + || std::is_same::value>( _("numpy.complex") + _(), _("numpy.longcomplex") ); }; @@ -1287,7 +1294,7 @@ public: using value_type = container_type::value_type; using size_type = container_type::size_type; - common_iterator() : p_ptr(0), m_strides() {} + common_iterator() : m_strides() {} common_iterator(void* ptr, const container_type& strides, const container_type& shape) : p_ptr(reinterpret_cast(ptr)), m_strides(strides.size()) { @@ -1308,7 +1315,7 @@ public: } private: - char* p_ptr; + char *p_ptr{0}; container_type m_strides; }; @@ -1336,9 +1343,8 @@ public: if (++m_index[i] != m_shape[i]) { increment_common_iterator(i); break; - } else { - m_index[i] = 0; } + m_index[i] = 0; } return *this; } @@ -1489,8 +1495,7 @@ struct vectorize_returned_array { static Type create(broadcast_trivial trivial, const std::vector &shape) { if (trivial == broadcast_trivial::f_trivial) return array_t(shape); - else - return array_t(shape); + return array_t(shape); } static Return *mutable_data(Type &array) { diff --git a/thirdparty/pybind11/include/pybind11/pybind11.h b/thirdparty/pybind11/include/pybind11/pybind11.h index ea6c397e80..1cb232d3a7 100644 --- a/thirdparty/pybind11/include/pybind11/pybind11.h +++ b/thirdparty/pybind11/include/pybind11/pybind11.h @@ -10,36 +10,14 @@ #pragma once -#if defined(__INTEL_COMPILER) -# pragma warning push -# pragma warning disable 68 // integer conversion resulted in a change of sign -# pragma warning disable 186 // pointless comparison of unsigned integer with zero -# pragma warning disable 878 // incompatible exception specifications -# pragma warning disable 1334 // the "template" keyword used for syntactic disambiguation may only be used within a template -# pragma warning disable 1682 // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem) -# pragma warning disable 1786 // function "strdup" was declared deprecated -# pragma warning disable 1875 // offsetof applied to non-POD (Plain Old Data) types is nonstandard -# pragma warning disable 2196 // warning #2196: routine is both "inline" and "noinline" -#elif defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) # pragma warning(push) # pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter # pragma warning(disable: 4127) // warning C4127: Conditional expression is constant -# pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted -# pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning) -# pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name -# pragma warning(disable: 4702) // warning C4702: unreachable code -# pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified -# pragma warning(disable: 4505) // warning C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed (PyPy only) -#elif defined(__GNUG__) && !defined(__clang__) +#elif defined(__GNUG__) && !defined(__clang__) && !defined(__INTEL_COMPILER) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-but-set-parameter" -# pragma GCC diagnostic ignored "-Wunused-but-set-variable" -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -# pragma GCC diagnostic ignored "-Wstrict-aliasing" # pragma GCC diagnostic ignored "-Wattributes" -# if __GNUC__ >= 7 -# pragma GCC diagnostic ignored "-Wnoexcept-type" -# endif #endif #include "attr.h" @@ -49,16 +27,44 @@ #include "detail/init.h" #include +#include #include #include #include +#include + +#if defined(__cpp_lib_launder) && !(defined(_MSC_VER) && (_MSC_VER < 1914)) +# define PYBIND11_STD_LAUNDER std::launder +# define PYBIND11_HAS_STD_LAUNDER 1 +#else +# define PYBIND11_STD_LAUNDER +# define PYBIND11_HAS_STD_LAUNDER 0 +#endif #if defined(__GNUG__) && !defined(__clang__) # include #endif +/* https://stackoverflow.com/questions/46798456/handling-gccs-noexcept-type-warning + This warning is about ABI compatibility, not code health. + It is only actually needed in a couple places, but apparently GCC 7 "generates this warning if + and only if the first template instantiation ... involves noexcept" [stackoverflow], therefore + it could get triggered from seemingly random places, depending on user code. + No other GCC version generates this warning. + */ +#if defined(__GNUC__) && __GNUC__ == 7 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnoexcept-type" +#endif + PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +#if defined(_MSC_VER) +# define PYBIND11_COMPAT_STRDUP _strdup +#else +# define PYBIND11_COMPAT_STRDUP strdup +#endif + /// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object class cpp_function : public function { public: @@ -143,16 +149,29 @@ protected: /* Without these pragmas, GCC warns that there might not be enough space to use the placement new operator. However, the 'if' statement above ensures that this is the case. */ -#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ >= 6 +#if defined(__GNUG__) && __GNUC__ >= 6 && !defined(__clang__) && !defined(__INTEL_COMPILER) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wplacement-new" #endif new ((capture *) &rec->data) capture { std::forward(f) }; -#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ >= 6 +#if defined(__GNUG__) && __GNUC__ >= 6 && !defined(__clang__) && !defined(__INTEL_COMPILER) # pragma GCC diagnostic pop #endif +#if defined(__GNUG__) && !PYBIND11_HAS_STD_LAUNDER && !defined(__INTEL_COMPILER) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + // UB without std::launder, but without breaking ABI and/or + // a significant refactoring it's "impossible" to solve. if (!std::is_trivially_destructible::value) - rec->free_data = [](function_record *r) { ((capture *) &r->data)->~capture(); }; + rec->free_data = [](function_record *r) { + auto data = PYBIND11_STD_LAUNDER((capture *) &r->data); + (void) data; + data->~capture(); + }; +#if defined(__GNUG__) && !PYBIND11_HAS_STD_LAUNDER && !defined(__INTEL_COMPILER) +# pragma GCC diagnostic pop +#endif } else { rec->data[0] = new capture { std::forward(f) }; rec->free_data = [](function_record *r) { delete ((capture *) r->data[0]); }; @@ -213,7 +232,7 @@ protected: } /* Generate a readable signature describing the function's arguments and return value types */ - static constexpr auto signature = _x("(") + cast_in::arg_names + _x(") -> ") + cast_out::name; + static constexpr auto signature = _("(") + cast_in::arg_names + _(") -> ") + cast_out::name; PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types(); /* Register the function with Python from generic (non-templated) code */ @@ -243,7 +262,7 @@ protected: std::free(s); } char *operator()(const char *s) { - auto t = strdup(s); + auto t = PYBIND11_COMPAT_STRDUP(s); strings.push_back(t); return t; } @@ -281,7 +300,8 @@ protected: a.descr = guarded_strdup(repr(a.value).cast().c_str()); } - rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__"); + rec->is_constructor + = (strcmp(rec->name, "__init__") == 0) || (strcmp(rec->name, "__setstate__") == 0); #if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING) if (rec->is_constructor && !rec->is_new_style_constructor) { @@ -395,7 +415,8 @@ protected: rec->def = new PyMethodDef(); std::memset(rec->def, 0, sizeof(PyMethodDef)); rec->def->ml_name = rec->name; - rec->def->ml_meth = reinterpret_cast(reinterpret_cast(*dispatcher)); + rec->def->ml_meth + = reinterpret_cast(reinterpret_cast(dispatcher)); rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS; capsule rec_capsule(unique_rec.release(), [](void *ptr) { @@ -469,7 +490,7 @@ protected: signatures += it->signature; signatures += "\n"; } - if (it->doc && strlen(it->doc) > 0 && options::show_user_defined_docstrings()) { + if (it->doc && it->doc[0] != '\0' && options::show_user_defined_docstrings()) { // If we're appending another docstring, and aren't printing function signatures, we // need to append a newline first: if (!options::show_function_signatures()) { @@ -486,7 +507,8 @@ protected: auto *func = (PyCFunctionObject *) m_ptr; std::free(const_cast(func->m_ml->ml_doc)); // Install docstring if it's non-empty (when at least one option is enabled) - func->m_ml->ml_doc = signatures.empty() ? nullptr : strdup(signatures.c_str()); + func->m_ml->ml_doc + = signatures.empty() ? nullptr : PYBIND11_COMPAT_STRDUP(signatures.c_str()); if (rec->is_method) { m_ptr = PYBIND11_INSTANCE_METHOD_NEW(m_ptr, rec->scope.ptr()); @@ -555,8 +577,8 @@ protected: auto self_value_and_holder = value_and_holder(); if (overloads->is_constructor) { - if (!PyObject_TypeCheck(parent.ptr(), (PyTypeObject *) overloads->scope.ptr())) { - PyErr_SetString(PyExc_TypeError, "__init__(self, ...) called with invalid `self` argument"); + if (!parent || !PyObject_TypeCheck(parent.ptr(), (PyTypeObject *) overloads->scope.ptr())) { + PyErr_SetString(PyExc_TypeError, "__init__(self, ...) called with invalid or missing `self` argument"); return nullptr; } @@ -635,7 +657,7 @@ protected: bool bad_arg = false; for (; args_copied < args_to_copy; ++args_copied) { const argument_record *arg_rec = args_copied < func.args.size() ? &func.args[args_copied] : nullptr; - if (kwargs_in && arg_rec && arg_rec->name && PyDict_GetItemString(kwargs_in, arg_rec->name)) { + if (kwargs_in && arg_rec && arg_rec->name && dict_getitemstring(kwargs_in, arg_rec->name)) { bad_arg = true; break; } @@ -683,7 +705,7 @@ protected: handle value; if (kwargs_in && arg_rec.name) - value = PyDict_GetItemString(kwargs.ptr(), arg_rec.name); + value = dict_getitemstring(kwargs.ptr(), arg_rec.name); if (value) { // Consume a kwargs value @@ -691,7 +713,9 @@ protected: kwargs = reinterpret_steal(PyDict_Copy(kwargs.ptr())); copied_kwargs = true; } - PyDict_DelItemString(kwargs.ptr(), arg_rec.name); + if (PyDict_DelItemString(kwargs.ptr(), arg_rec.name) == -1) { + throw error_already_set(); + } } else if (arg_rec.value) { value = arg_rec.value; } @@ -921,20 +945,20 @@ protected: append_note_if_missing_header_is_suspected(msg); PyErr_SetString(PyExc_TypeError, msg.c_str()); return nullptr; - } else if (!result) { + } + if (!result) { std::string msg = "Unable to convert function return value to a " "Python type! The signature was\n\t"; msg += it->signature; append_note_if_missing_header_is_suspected(msg); PyErr_SetString(PyExc_TypeError, msg.c_str()); return nullptr; - } else { - if (overloads->is_constructor && !self_value_and_holder.holder_constructed()) { - auto *pi = reinterpret_cast(parent.ptr()); - self_value_and_holder.type->init_instance(pi, nullptr); - } - return result.ptr(); } + if (overloads->is_constructor && !self_value_and_holder.holder_constructed()) { + auto *pi = reinterpret_cast(parent.ptr()); + self_value_and_holder.type->init_instance(pi, nullptr); + } + return result.ptr(); } }; @@ -1086,7 +1110,8 @@ protected: pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec.name) + "\": an object with that name is already defined"); - if (rec.module_local ? get_local_type_info(*rec.type) : get_global_type_info(*rec.type)) + if ((rec.module_local ? get_local_type_info(*rec.type) : get_global_type_info(*rec.type)) + != nullptr) pybind11_fail("generic_type: type \"" + std::string(rec.name) + "\" is already registered!"); @@ -1164,8 +1189,9 @@ protected: void def_property_static_impl(const char *name, handle fget, handle fset, detail::function_record *rec_func) { - const auto is_static = rec_func && !(rec_func->is_method && rec_func->scope); - const auto has_doc = rec_func && rec_func->doc && pybind11::options::show_user_defined_docstrings(); + const auto is_static = (rec_func != nullptr) && !(rec_func->is_method && rec_func->scope); + const auto has_doc = (rec_func != nullptr) && (rec_func->doc != nullptr) + && pybind11::options::show_user_defined_docstrings(); auto property = handle((PyObject *) (is_static ? get_internals().static_property_type : &PyProperty_Type)); attr(name) = property(fget.ptr() ? fget : none(), @@ -1412,15 +1438,15 @@ public: template class_ &def_readwrite_static(const char *name, D *pm, const Extra& ...extra) { - cpp_function fget([pm](object) -> const D &{ return *pm; }, scope(*this)), - fset([pm](object, const D &value) { *pm = value; }, scope(*this)); + cpp_function fget([pm](const object &) -> const D & { return *pm; }, scope(*this)), + fset([pm](const object &, const D &value) { *pm = value; }, scope(*this)); def_property_static(name, fget, fset, return_value_policy::reference, extra...); return *this; } template class_ &def_readonly_static(const char *name, const D *pm, const Extra& ...extra) { - cpp_function fget([pm](object) -> const D &{ return *pm; }, scope(*this)); + cpp_function fget([pm](const object &) -> const D & { return *pm; }, scope(*this)); def_property_readonly_static(name, fget, return_value_policy::reference, extra...); return *this; } @@ -1485,7 +1511,7 @@ public: detail::process_attributes::init(extra..., rec_fget); if (rec_fget->doc && rec_fget->doc != doc_prev) { free(doc_prev); - rec_fget->doc = strdup(rec_fget->doc); + rec_fget->doc = PYBIND11_COMPAT_STRDUP(rec_fget->doc); } } if (rec_fset) { @@ -1493,7 +1519,7 @@ public: detail::process_attributes::init(extra..., rec_fset); if (rec_fset->doc && rec_fset->doc != doc_prev) { free(doc_prev); - rec_fset->doc = strdup(rec_fset->doc); + rec_fset->doc = PYBIND11_COMPAT_STRDUP(rec_fset->doc); } if (! rec_active) rec_active = rec_fset; } @@ -1628,12 +1654,13 @@ struct enum_base { auto static_property = handle((PyObject *) get_internals().static_property_type); m_base.attr("__repr__") = cpp_function( - [](object arg) -> str { + [](const object &arg) -> str { handle type = type::handle_of(arg); object type_name = type.attr("__name__"); return pybind11::str("<{}.{}: {}>").format(type_name, enum_name(arg), int_(arg)); - }, name("__repr__"), is_method(m_base) - ); + }, + name("__repr__"), + is_method(m_base)); m_base.attr("name") = property(cpp_function(&enum_name, name("name"), is_method(m_base))); @@ -1671,30 +1698,36 @@ struct enum_base { }, name("__members__")), none(), none(), "" ); - #define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior) \ - m_base.attr(op) = cpp_function( \ - [](object a, object b) { \ - if (!type::handle_of(a).is(type::handle_of(b))) \ - strict_behavior; \ - return expr; \ - }, \ - name(op), is_method(m_base), arg("other")) +#define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior) \ + m_base.attr(op) = cpp_function( \ + [](const object &a, const object &b) { \ + if (!type::handle_of(a).is(type::handle_of(b))) \ + strict_behavior; \ + return expr; \ + }, \ + name(op), \ + is_method(m_base), \ + arg("other")) - #define PYBIND11_ENUM_OP_CONV(op, expr) \ - m_base.attr(op) = cpp_function( \ - [](object a_, object b_) { \ - int_ a(a_), b(b_); \ - return expr; \ - }, \ - name(op), is_method(m_base), arg("other")) +#define PYBIND11_ENUM_OP_CONV(op, expr) \ + m_base.attr(op) = cpp_function( \ + [](const object &a_, const object &b_) { \ + int_ a(a_), b(b_); \ + return expr; \ + }, \ + name(op), \ + is_method(m_base), \ + arg("other")) - #define PYBIND11_ENUM_OP_CONV_LHS(op, expr) \ - m_base.attr(op) = cpp_function( \ - [](object a_, object b) { \ - int_ a(a_); \ - return expr; \ - }, \ - name(op), is_method(m_base), arg("other")) +#define PYBIND11_ENUM_OP_CONV_LHS(op, expr) \ + m_base.attr(op) = cpp_function( \ + [](const object &a_, const object &b) { \ + int_ a(a_); \ + return expr; \ + }, \ + name(op), \ + is_method(m_base), \ + arg("other")) if (is_convertible) { PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b)); @@ -1711,8 +1744,10 @@ struct enum_base { PYBIND11_ENUM_OP_CONV("__ror__", a | b); PYBIND11_ENUM_OP_CONV("__xor__", a ^ b); PYBIND11_ENUM_OP_CONV("__rxor__", a ^ b); - m_base.attr("__invert__") = cpp_function( - [](object arg) { return ~(int_(arg)); }, name("__invert__"), is_method(m_base)); + m_base.attr("__invert__") + = cpp_function([](const object &arg) { return ~(int_(arg)); }, + name("__invert__"), + is_method(m_base)); } } else { PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false); @@ -1733,10 +1768,10 @@ struct enum_base { #undef PYBIND11_ENUM_OP_STRICT m_base.attr("__getstate__") = cpp_function( - [](object arg) { return int_(arg); }, name("__getstate__"), is_method(m_base)); + [](const object &arg) { return int_(arg); }, name("__getstate__"), is_method(m_base)); m_base.attr("__hash__") = cpp_function( - [](object arg) { return int_(arg); }, name("__hash__"), is_method(m_base)); + [](const object &arg) { return int_(arg); }, name("__hash__"), is_method(m_base)); } PYBIND11_NOINLINE void value(char const* name_, object value, const char *doc = nullptr) { @@ -1848,9 +1883,9 @@ PYBIND11_NOINLINE inline void keep_alive_impl(size_t Nurse, size_t Patient, func auto get_arg = [&](size_t n) { if (n == 0) return ret; - else if (n == 1 && call.init_self) + if (n == 1 && call.init_self) return call.init_self; - else if (n <= call.args.size()) + if (n <= call.args.size()) return call.args[n - 1]; return handle(); }; @@ -2054,7 +2089,7 @@ exception ®ister_exception(handle scope, } PYBIND11_NAMESPACE_BEGIN(detail) -PYBIND11_NOINLINE inline void print(tuple args, dict kwargs) { +PYBIND11_NOINLINE inline void print(const tuple &args, const dict &kwargs) { auto strings = tuple(args.size()); for (size_t i = 0; i < args.size(); ++i) { strings[i] = str(args[i]); @@ -2126,10 +2161,10 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty Unfortunately this doesn't work on PyPy. */ #if !defined(PYPY_VERSION) PyFrameObject *frame = PyThreadState_Get()->frame; - if (frame && (std::string) str(frame->f_code->co_name) == name && - frame->f_code->co_argcount > 0) { + if (frame != nullptr && (std::string) str(frame->f_code->co_name) == name + && frame->f_code->co_argcount > 0) { PyFrame_FastToLocals(frame); - PyObject *self_caller = PyDict_GetItem( + PyObject *self_caller = dict_getitem( frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0)); if (self_caller == self.ptr()) return function(); @@ -2174,18 +2209,19 @@ template function get_override(const T *this_ptr, const char *name) { return tinfo ? detail::get_type_override(this_ptr, tinfo, name) : function(); } -#define PYBIND11_OVERRIDE_IMPL(ret_type, cname, name, ...) \ - do { \ - pybind11::gil_scoped_acquire gil; \ - pybind11::function override = pybind11::get_override(static_cast(this), name); \ - if (override) { \ - auto o = override(__VA_ARGS__); \ - if (pybind11::detail::cast_is_temporary_value_reference::value) { \ - static pybind11::detail::override_caster_t caster; \ - return pybind11::detail::cast_ref(std::move(o), caster); \ - } \ - else return pybind11::detail::cast_safe(std::move(o)); \ - } \ +#define PYBIND11_OVERRIDE_IMPL(ret_type, cname, name, ...) \ + do { \ + pybind11::gil_scoped_acquire gil; \ + pybind11::function override \ + = pybind11::get_override(static_cast(this), name); \ + if (override) { \ + auto o = override(__VA_ARGS__); \ + if (pybind11::detail::cast_is_temporary_value_reference::value) { \ + static pybind11::detail::override_caster_t caster; \ + return pybind11::detail::cast_ref(std::move(o), caster); \ + } \ + return pybind11::detail::cast_safe(std::move(o)); \ + } \ } while (false) /** \rst @@ -2281,8 +2317,12 @@ inline function get_overload(const T *this_ptr, const char *name) { PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) +#if defined(__GNUC__) && __GNUC__ == 7 +# pragma GCC diagnostic pop // -Wnoexcept-type +#endif + #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) # pragma warning(pop) -#elif defined(__GNUG__) && !defined(__clang__) +#elif defined(__GNUG__) && !defined(__clang__) && !defined(__INTEL_COMPILER) # pragma GCC diagnostic pop #endif diff --git a/thirdparty/pybind11/include/pybind11/pytypes.h b/thirdparty/pybind11/include/pybind11/pytypes.h index 6f0e6067ef..4cf606e8d0 100644 --- a/thirdparty/pybind11/include/pybind11/pytypes.h +++ b/thirdparty/pybind11/include/pybind11/pytypes.h @@ -319,11 +319,15 @@ PYBIND11_NAMESPACE_BEGIN(detail) inline std::string error_string(); PYBIND11_NAMESPACE_END(detail) +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4275 4251) // warning C4275: An exported class was derived from a class that wasn't exported. Can be ignored when derived from a STL class. +#endif /// Fetch and hold an error which was already set in Python. An instance of this is typically /// thrown to propagate python-side errors back through C++ which can either be caught manually or /// else falls back to the function dispatcher (which then raises the captured error back to /// python). -class error_already_set : public std::runtime_error { +class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::runtime_error { public: /// Constructs a new exception from the current Python error indicator, if any. The current /// Python error indicator will be cleared. @@ -341,16 +345,17 @@ public: /// error variables (but the `.what()` string is still available). void restore() { PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr()); } - /// If it is impossible to raise the currently-held error, such as in destructor, we can write - /// it out using Python's unraisable hook (sys.unraisablehook). The error context should be - /// some object whose repr() helps identify the location of the error. Python already knows the - /// type and value of the error, so there is no need to repeat that. For example, __func__ could - /// be helpful. After this call, the current object no longer stores the error variables, - /// and neither does Python. + /// If it is impossible to raise the currently-held error, such as in a destructor, we can write + /// it out using Python's unraisable hook (`sys.unraisablehook`). The error context should be + /// some object whose `repr()` helps identify the location of the error. Python already knows the + /// type and value of the error, so there is no need to repeat that. After this call, the current + /// object no longer stores the error variables, and neither does Python. void discard_as_unraisable(object err_context) { restore(); PyErr_WriteUnraisable(err_context.ptr()); } + /// An alternate version of `discard_as_unraisable()`, where a string provides information on the + /// location of the error. For example, `__func__` could be helpful. void discard_as_unraisable(const char *err_context) { discard_as_unraisable(reinterpret_steal(PYBIND11_FROM_STRING(err_context))); } @@ -362,7 +367,9 @@ public: /// Check if the currently trapped error type matches the given Python exception class (or a /// subclass thereof). May also be passed a tuple to search for any exception class matches in /// the given tuple. - bool matches(handle exc) const { return PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()); } + bool matches(handle exc) const { + return (PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()) != 0); + } const object& type() const { return m_type; } const object& value() const { return m_value; } @@ -371,6 +378,9 @@ public: private: object m_type, m_value, m_trace; }; +#if defined(_MSC_VER) +# pragma warning(pop) +#endif /** \defgroup python_builtins _ Unless stated otherwise, the following C++ functions behave the same @@ -433,19 +443,17 @@ inline object getattr(handle obj, const char *name) { inline object getattr(handle obj, handle name, handle default_) { if (PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr())) { return reinterpret_steal(result); - } else { - PyErr_Clear(); - return reinterpret_borrow(default_); } + PyErr_Clear(); + return reinterpret_borrow(default_); } inline object getattr(handle obj, const char *name, handle default_) { if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) { return reinterpret_steal(result); - } else { - PyErr_Clear(); - return reinterpret_borrow(default_); } + PyErr_Clear(); + return reinterpret_borrow(default_); } inline void setattr(handle obj, handle name, handle value) { @@ -478,6 +486,43 @@ inline handle get_function(handle value) { return value; } +// Reimplementation of python's dict helper functions to ensure that exceptions +// aren't swallowed (see #2862) + +// copied from cpython _PyDict_GetItemStringWithError +inline PyObject * dict_getitemstring(PyObject *v, const char *key) +{ +#if PY_MAJOR_VERSION >= 3 + PyObject *kv = nullptr, *rv = nullptr; + kv = PyUnicode_FromString(key); + if (kv == NULL) { + throw error_already_set(); + } + + rv = PyDict_GetItemWithError(v, kv); + Py_DECREF(kv); + if (rv == NULL && PyErr_Occurred()) { + throw error_already_set(); + } + return rv; +#else + return PyDict_GetItemString(v, key); +#endif +} + +inline PyObject * dict_getitem(PyObject *v, PyObject *key) +{ +#if PY_MAJOR_VERSION >= 3 + PyObject *rv = PyDict_GetItemWithError(v, key); + if (rv == NULL && PyErr_Occurred()) { + throw error_already_set(); + } + return rv; +#else + return PyDict_GetItem(v, key); +#endif +} + // Helper aliases/functions to support implicit casting of values given to python accessors/methods. // When given a pyobject, this simply returns the pyobject as-is; for other C++ type, the value goes // through pybind11::cast(obj) to convert it to an `object`. @@ -489,6 +534,10 @@ object object_or_cast(T &&o); // Match a PyObject*, which we want to convert directly to handle via its converting constructor inline handle object_or_cast(PyObject *ptr) { return ptr; } +#if defined(_MSC_VER) && _MSC_VER < 1920 +# pragma warning(push) +# pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified +#endif template class accessor : public object_api> { using key_type = typename Policy::key_type; @@ -496,7 +545,7 @@ class accessor : public object_api> { public: accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) { } accessor(const accessor &) = default; - accessor(accessor &&) = default; + accessor(accessor &&) noexcept = default; // accessor overload required to override default assignment operator (templates are not allowed // to replace default compiler-generated assignments). @@ -537,6 +586,9 @@ private: key_type key; mutable object cache; }; +#if defined(_MSC_VER) && _MSC_VER < 1920 +# pragma warning(pop) +#endif PYBIND11_NAMESPACE_BEGIN(accessor_policies) struct obj_attr { @@ -721,7 +773,11 @@ protected: dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); } reference dereference() const { return {key, value}; } - void increment() { if (!PyDict_Next(obj.ptr(), &pos, &key, &value)) { pos = -1; } } + void increment() { + if (PyDict_Next(obj.ptr(), &pos, &key, &value) == 0) { + pos = -1; + } + } bool equal(const dict_readonly &b) const { return pos == b.pos; } private: @@ -747,10 +803,9 @@ inline bool PyIterable_Check(PyObject *obj) { if (iter) { Py_DECREF(iter); return true; - } else { - PyErr_Clear(); - return false; } + PyErr_Clear(); + return false; } inline bool PyNone_Check(PyObject *o) { return o == Py_None; } @@ -804,7 +859,7 @@ PYBIND11_NAMESPACE_END(detail) Name(handle h, borrowed_t) : Parent(h, borrowed_t{}) { } \ Name(handle h, stolen_t) : Parent(h, stolen_t{}) { } \ PYBIND11_DEPRECATED("Use py::isinstance(obj) instead") \ - bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } \ + bool check() const { return m_ptr != nullptr && (CheckFun(m_ptr) != 0); } \ static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } \ template \ Name(const ::pybind11::detail::accessor &a) : Name(object(a)) { } @@ -973,10 +1028,10 @@ public: if (PyUnicode_Check(m_ptr)) { temp = reinterpret_steal(PyUnicode_AsUTF8String(m_ptr)); if (!temp) - pybind11_fail("Unable to extract string contents! (encoding issue)"); + throw error_already_set(); } - char *buffer; - ssize_t length; + char *buffer = nullptr; + ssize_t length = 0; if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) pybind11_fail("Unable to extract string contents! (invalid type)"); return std::string(buffer, (size_t) length); @@ -1031,8 +1086,8 @@ public: explicit bytes(const pybind11::str &s); operator std::string() const { - char *buffer; - ssize_t length; + char *buffer = nullptr; + ssize_t length = 0; if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) pybind11_fail("Unable to extract bytes contents!"); return std::string(buffer, (size_t) length); @@ -1049,8 +1104,8 @@ inline bytes::bytes(const pybind11::str &s) { if (!temp) pybind11_fail("Unable to extract string contents! (encoding issue)"); } - char *buffer; - ssize_t length; + char *buffer = nullptr; + ssize_t length = 0; if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) pybind11_fail("Unable to extract string contents! (invalid type)"); auto obj = reinterpret_steal(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length)); @@ -1060,8 +1115,8 @@ inline bytes::bytes(const pybind11::str &s) { } inline str::str(const bytes& b) { - char *buffer; - ssize_t length; + char *buffer = nullptr; + ssize_t length = 0; if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) pybind11_fail("Unable to extract bytes contents!"); auto obj = reinterpret_steal(PyUnicode_FromStringAndSize(buffer, (ssize_t) length)); @@ -1118,14 +1173,14 @@ public: bool_() : object(Py_False, borrowed_t{}) { } // Allow implicit conversion from and to `bool`: bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) { } - operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; } + operator bool() const { return (m_ptr != nullptr) && PyLong_AsLong(m_ptr) != 0; } private: /// Return the truth value of an object -- always returns a new reference static PyObject *raw_bool(PyObject *op) { const auto value = PyObject_IsTrue(op); if (value == -1) return nullptr; - return handle(value ? Py_True : Py_False).inc_ref().ptr(); + return handle(value != 0 ? Py_True : Py_False).inc_ref().ptr(); } }; @@ -1144,10 +1199,8 @@ Unsigned as_unsigned(PyObject *o) { unsigned long v = PyLong_AsUnsignedLong(o); return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; } - else { - unsigned long long v = PyLong_AsUnsignedLongLong(o); - return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; - } + unsigned long long v = PyLong_AsUnsignedLongLong(o); + return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; } PYBIND11_NAMESPACE_END(detail) @@ -1501,7 +1554,7 @@ public: detail::any_container shape, detail::any_container strides) { return memoryview::from_buffer( - const_cast(ptr), itemsize, format, shape, strides, true); + const_cast(ptr), itemsize, format, std::move(shape), std::move(strides), true); } template @@ -1558,7 +1611,7 @@ inline memoryview memoryview::from_buffer( size_t ndim = shape->size(); if (ndim != strides->size()) pybind11_fail("memoryview: shape length doesn't match strides length"); - ssize_t size = ndim ? 1 : 0; + ssize_t size = ndim != 0u ? 1 : 0; for (size_t i = 0; i < ndim; ++i) size *= (*shape)[i]; Py_buffer view; diff --git a/thirdparty/pybind11/include/pybind11/stl.h b/thirdparty/pybind11/include/pybind11/stl.h index 18fbafb1e2..51994c656b 100644 --- a/thirdparty/pybind11/include/pybind11/stl.h +++ b/thirdparty/pybind11/include/pybind11/stl.h @@ -159,10 +159,13 @@ template struct list_caster { } private: - template ().reserve(0)), void>::value, int> = 0> - void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); } - void reserve_maybe(sequence, void *) { } + template < + typename T = Type, + enable_if_t().reserve(0)), void>::value, int> = 0> + void reserve_maybe(const sequence &s, Type *) { + value.reserve(s.size()); + } + void reserve_maybe(const sequence &, void *) {} public: template @@ -275,7 +278,8 @@ template struct optional_caster { bool load(handle src, bool convert) { if (!src) { return false; - } else if (src.is_none()) { + } + if (src.is_none()) { return true; // default-constructed value is already empty } value_conv inner_caster; @@ -377,7 +381,11 @@ struct type_caster> : variant_caster> { PYBIND11_NAMESPACE_END(detail) inline std::ostream &operator<<(std::ostream &os, const handle &obj) { +#ifdef PYBIND11_HAS_STRING_VIEW + os << str(obj).cast(); +#else os << (std::string) str(obj); +#endif return os; } diff --git a/thirdparty/pybind11/include/pybind11/stl/filesystem.h b/thirdparty/pybind11/include/pybind11/stl/filesystem.h new file mode 100644 index 0000000000..431b94b4f7 --- /dev/null +++ b/thirdparty/pybind11/include/pybind11/stl/filesystem.h @@ -0,0 +1,103 @@ +// Copyright (c) 2021 The Pybind Development Team. +// All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#pragma once + +#include "../cast.h" +#include "../pybind11.h" +#include "../pytypes.h" + +#include "../detail/common.h" +#include "../detail/descr.h" + +#include + +#ifdef __has_include +# if defined(PYBIND11_CPP17) && __has_include() && \ + PY_VERSION_HEX >= 0x03060000 +# include +# define PYBIND11_HAS_FILESYSTEM 1 +# endif +#endif + +#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL) +# error \ + "#include is not available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)" +#endif + +PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +PYBIND11_NAMESPACE_BEGIN(detail) + +#if defined(PYBIND11_HAS_FILESYSTEM) +template struct path_caster { + +private: + static PyObject* unicode_from_fs_native(const std::string& w) { +#if !defined(PYPY_VERSION) + return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size())); +#else + // PyPy mistakenly declares the first parameter as non-const. + return PyUnicode_DecodeFSDefaultAndSize( + const_cast(w.c_str()), ssize_t(w.size())); +#endif + } + + static PyObject* unicode_from_fs_native(const std::wstring& w) { + return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size())); + } + +public: + static handle cast(const T& path, return_value_policy, handle) { + if (auto py_str = unicode_from_fs_native(path.native())) { + return module_::import("pathlib").attr("Path")(reinterpret_steal(py_str)) + .release(); + } + return nullptr; + } + + bool load(handle handle, bool) { + // PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of + // calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy + // issue #3168) so we do it ourselves instead. + PyObject* buf = PyOS_FSPath(handle.ptr()); + if (!buf) { + PyErr_Clear(); + return false; + } + PyObject* native = nullptr; + if constexpr (std::is_same_v) { + if (PyUnicode_FSConverter(buf, &native) != 0) { + if (auto c_str = PyBytes_AsString(native)) { + // AsString returns a pointer to the internal buffer, which + // must not be free'd. + value = c_str; + } + } + } else if constexpr (std::is_same_v) { + if (PyUnicode_FSDecoder(buf, &native) != 0) { + if (auto c_str = PyUnicode_AsWideCharString(native, nullptr)) { + // AsWideCharString returns a new string that must be free'd. + value = c_str; // Copies the string. + PyMem_Free(c_str); + } + } + } + Py_XDECREF(native); + Py_DECREF(buf); + if (PyErr_Occurred()) { + PyErr_Clear(); + return false; + } + return true; + } + + PYBIND11_TYPE_CASTER(T, _("os.PathLike")); +}; + +template<> struct type_caster + : public path_caster {}; +#endif // PYBIND11_HAS_FILESYSTEM + +PYBIND11_NAMESPACE_END(detail) +PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/thirdparty/pybind11/include/pybind11/stl_bind.h b/thirdparty/pybind11/include/pybind11/stl_bind.h index 83195ee496..82317b3791 100644 --- a/thirdparty/pybind11/include/pybind11/stl_bind.h +++ b/thirdparty/pybind11/include/pybind11/stl_bind.h @@ -128,11 +128,11 @@ void vector_modifiers(enable_if_t(new Vector()); v->reserve(len_hint(it)); for (handle h : it) - v->push_back(h.cast()); + v->push_back(h.cast()); return v.release(); })); @@ -151,27 +151,28 @@ void vector_modifiers(enable_if_t()); - } - } catch (const cast_error &) { - v.erase(v.begin() + static_cast(old_size), v.end()); - try { - v.shrink_to_fit(); - } catch (const std::exception &) { - // Do nothing - } - throw; - } - }, - arg("L"), - "Extend the list by appending all the items in the given list" - ); + cl.def( + "extend", + [](Vector &v, const iterable &it) { + const size_t old_size = v.size(); + v.reserve(old_size + len_hint(it)); + try { + for (handle h : it) { + v.push_back(h.cast()); + } + } catch (const cast_error &) { + v.erase(v.begin() + static_cast(old_size), + v.end()); + try { + v.shrink_to_fit(); + } catch (const std::exception &) { + // Do nothing + } + throw; + } + }, + arg("L"), + "Extend the list by appending all the items in the given list"); cl.def("insert", [](Vector &v, DiffType i, const T &x) { @@ -190,7 +191,7 @@ void vector_modifiers(enable_if_t Vector * { - size_t start, stop, step, slicelength; + size_t start = 0, stop = 0, step = 0, slicelength = 0; if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) throw error_already_set(); @@ -233,12 +235,12 @@ void vector_modifiers(enable_if_t), @@ -400,7 +400,7 @@ void vector_buffer_impl(Class_& cl, std::true_type) { return buffer_info(v.data(), static_cast(sizeof(T)), format_descriptor::format(), 1, {v.size()}, {sizeof(T)}); }); - cl.def(init([](buffer buf) { + cl.def(init([](const buffer &buf) { auto info = buf.request(); if (info.ndim != 1 || info.strides[0] % static_cast(sizeof(T))) throw type_error("Only valid 1D buffers can be copied to a vector"); @@ -413,13 +413,12 @@ void vector_buffer_impl(Class_& cl, std::true_type) { if (step == 1) { return Vector(p, end); } - else { - Vector vec; - vec.reserve((size_t) info.shape[0]); - for (; p != end; p += step) - vec.push_back(*p); - return vec; - } + Vector vec; + vec.reserve((size_t) info.shape[0]); + for (; p != end; p += step) + vec.push_back(*p); + return vec; + })); return; diff --git a/thirdparty/pybind11/pybind11/_version.py b/thirdparty/pybind11/pybind11/_version.py index ffadcca5a8..2bb4fe364d 100644 --- a/thirdparty/pybind11/pybind11/_version.py +++ b/thirdparty/pybind11/pybind11/_version.py @@ -8,5 +8,5 @@ def _to_int(s): return s -__version__ = "2.6.3.dev1" +__version__ = "2.7.1" version_info = tuple(_to_int(s) for s in __version__.split(".")) diff --git a/thirdparty/pybind11/pybind11/setup_helpers.py b/thirdparty/pybind11/pybind11/setup_helpers.py index c69064ca50..0888ab4872 100644 --- a/thirdparty/pybind11/pybind11/setup_helpers.py +++ b/thirdparty/pybind11/pybind11/setup_helpers.py @@ -47,6 +47,7 @@ import tempfile import threading import platform import warnings +import sysconfig try: from setuptools.command.build_ext import build_ext as _build_ext @@ -58,8 +59,7 @@ except ImportError: import distutils.errors import distutils.ccompiler - -WIN = sys.platform.startswith("win32") +WIN = sys.platform.startswith("win32") and "mingw" not in sysconfig.get_platform() PY2 = sys.version_info[0] < 3 MACOS = sys.platform.startswith("darwin") STD_TMPL = "/std:c++{}" if WIN else "-std=c++{}" @@ -84,7 +84,7 @@ class Pybind11Extension(_Extension): * ``stdlib=libc++`` on macOS * ``visibility=hidden`` and ``-g0`` on Unix - Finally, you can set ``cxx_std`` via constructor or afterwords to enable + Finally, you can set ``cxx_std`` via constructor or afterwards to enable flags for C++ std, and a few extra helper flags related to the C++ standard level. It is _highly_ recommended you either set this, or use the provided ``build_ext``, which will search for the highest supported extension for @@ -302,6 +302,42 @@ class build_ext(_build_ext): # noqa: N801 _build_ext.build_extensions(self) +def intree_extensions(paths, package_dir=None): + """ + Generate Pybind11Extensions from source files directly located in a Python + source tree. + + ``package_dir`` behaves as in ``setuptools.setup``. If unset, the Python + package root parent is determined as the first parent directory that does + not contain an ``__init__.py`` file. + """ + exts = [] + for path in paths: + if package_dir is None: + parent, _ = os.path.split(path) + while os.path.exists(os.path.join(parent, "__init__.py")): + parent, _ = os.path.split(parent) + relname, _ = os.path.splitext(os.path.relpath(path, parent)) + qualified_name = relname.replace(os.path.sep, ".") + exts.append(Pybind11Extension(qualified_name, [path])) + else: + found = False + for prefix, parent in package_dir.items(): + if path.startswith(parent): + found = True + relname, _ = os.path.splitext(os.path.relpath(path, parent)) + qualified_name = relname.replace(os.path.sep, ".") + if prefix: + qualified_name = prefix + "." + qualified_name + exts.append(Pybind11Extension(qualified_name, [path])) + if not found: + raise ValueError( + "path {} is not a child of any of the directories listed " + "in 'package_dir' ({})".format(path, package_dir) + ) + return exts + + def naive_recompile(obj, src): """ This will recompile only if the source file changes. It does not check @@ -409,7 +445,9 @@ class ParallelCompile(object): compiler._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) try: - import multiprocessing + # Importing .synchronize checks for platforms that have some multiprocessing + # capabilities but lack semaphores, such as AWS Lambda and Android Termux. + import multiprocessing.synchronize from multiprocessing.pool import ThreadPool except ImportError: threads = 1 diff --git a/thirdparty/pybind11/pybind11/setup_helpers.pyi b/thirdparty/pybind11/pybind11/setup_helpers.pyi index 23232e1fda..8b16c0a137 100644 --- a/thirdparty/pybind11/pybind11/setup_helpers.pyi +++ b/thirdparty/pybind11/pybind11/setup_helpers.pyi @@ -1,7 +1,7 @@ # IMPORTANT: Should stay in sync with setup_helpers.py (mostly checked by CI / # pre-commit). -from typing import Any, Callable, Iterator, Optional, Type, TypeVar, Union +from typing import Any, Callable, Dict, Iterator, List, Optional, Type, TypeVar, Union from types import TracebackType from distutils.command.build_ext import build_ext as _build_ext # type: ignore @@ -33,6 +33,9 @@ def auto_cpp_level(compiler: distutils.ccompiler.CCompiler) -> Union[int, str]: class build_ext(_build_ext): # type: ignore def build_extensions(self) -> None: ... +def intree_extensions( + paths: Iterator[str], package_dir: Optional[Dict[str, str]] = None +) -> List[Pybind11Extension]: ... def no_recompile(obj: str, src: str) -> bool: ... def naive_recompile(obj: str, src: str) -> bool: ... diff --git a/thirdparty/pybind11/tests/CMakeLists.txt b/thirdparty/pybind11/tests/CMakeLists.txt index 9ff6c0dd9a..dc70038dba 100644 --- a/thirdparty/pybind11/tests/CMakeLists.txt +++ b/thirdparty/pybind11/tests/CMakeLists.txt @@ -247,6 +247,41 @@ if(Boost_FOUND) endif() endif() +# Check if we need to add -lstdc++fs or -lc++fs or nothing +if(MSVC) + set(STD_FS_NO_LIB_NEEDED TRUE) +else() + file( + WRITE ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + "#include \nint main(int argc, char ** argv) {\n std::filesystem::path p(argv[0]);\n return p.string().length();\n}" + ) + try_compile( + STD_FS_NO_LIB_NEEDED ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + COMPILE_DEFINITIONS -std=c++17) + try_compile( + STD_FS_NEEDS_STDCXXFS ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + COMPILE_DEFINITIONS -std=c++17 + LINK_LIBRARIES stdc++fs) + try_compile( + STD_FS_NEEDS_CXXFS ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + COMPILE_DEFINITIONS -std=c++17 + LINK_LIBRARIES c++fs) +endif() + +if(${STD_FS_NEEDS_STDCXXFS}) + set(STD_FS_LIB stdc++fs) +elseif(${STD_FS_NEEDS_CXXFS}) + set(STD_FS_LIB c++fs) +elseif(${STD_FS_NO_LIB_NEEDED}) + set(STD_FS_LIB "") +else() + message(WARNING "Unknown compiler - not passing -lstdc++fs") + set(STD_FS_LIB "") +endif() + # Compile with compiler warnings turned on function(pybind11_enable_warnings target_name) if(MSVC) @@ -268,12 +303,19 @@ function(pybind11_enable_warnings target_name) target_compile_options(${target_name} PRIVATE /WX) elseif(PYBIND11_CUDA_TESTS) target_compile_options(${target_name} PRIVATE "SHELL:-Werror all-warnings") - elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)") + elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang|IntelLLVM)") target_compile_options(${target_name} PRIVATE -Werror) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + target_compile_options( + ${target_name} + PRIVATE + -Werror-all + # "Inlining inhibited by limit max-size", "Inlining inhibited by limit max-total-size" + -diag-disable 11074,11076) endif() endif() - # Needs to be readded since the ordering requires these to be after the ones above + # Needs to be re-added 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) @@ -350,6 +392,8 @@ foreach(target ${test_targets}) target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST) endif() + target_link_libraries(${target} PRIVATE ${STD_FS_LIB}) + # Always write the output file directly into the 'tests' directory (even on MSVC) if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY diff --git a/thirdparty/pybind11/tests/env.py b/thirdparty/pybind11/tests/env.py index 5cded44127..6172b451b3 100644 --- a/thirdparty/pybind11/tests/env.py +++ b/thirdparty/pybind11/tests/env.py @@ -2,6 +2,8 @@ import platform import sys +import pytest + LINUX = sys.platform.startswith("linux") MACOS = sys.platform.startswith("darwin") WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin") @@ -12,3 +14,20 @@ PYPY = platform.python_implementation() == "PyPy" PY2 = sys.version_info.major == 2 PY = sys.version_info + + +def deprecated_call(): + """ + pytest.deprecated_call() seems broken in pytest<3.9.x; concretely, it + doesn't work on CPython 3.8.0 with pytest==3.3.2 on Ubuntu 18.04 (#2922). + + This is a narrowed reimplementation of the following PR :( + https://github.com/pytest-dev/pytest/pull/4104 + """ + # TODO: Remove this when testing requires pytest>=3.9. + pieces = pytest.__version__.split(".") + pytest_major_minor = (int(pieces[0]), int(pieces[1])) + if pytest_major_minor < (3, 9): + return pytest.warns((DeprecationWarning, PendingDeprecationWarning)) + else: + return pytest.deprecated_call() diff --git a/thirdparty/pybind11/tests/extra_python_package/test_files.py b/thirdparty/pybind11/tests/extra_python_package/test_files.py index 064a3e12fe..337a72dfea 100644 --- a/thirdparty/pybind11/tests/extra_python_package/test_files.py +++ b/thirdparty/pybind11/tests/extra_python_package/test_files.py @@ -46,6 +46,10 @@ detail_headers = { "include/pybind11/detail/typeid.h", } +stl_headers = { + "include/pybind11/stl/filesystem.h", +} + cmake_files = { "share/cmake/pybind11/FindPythonLibsNew.cmake", "share/cmake/pybind11/pybind11Common.cmake", @@ -67,7 +71,7 @@ py_files = { "setup_helpers.pyi", } -headers = main_headers | detail_headers +headers = main_headers | detail_headers | stl_headers src_files = headers | cmake_files all_files = src_files | py_files @@ -77,6 +81,7 @@ sdist_files = { "pybind11/include", "pybind11/include/pybind11", "pybind11/include/pybind11/detail", + "pybind11/include/pybind11/stl", "pybind11/share", "pybind11/share/cmake", "pybind11/share/cmake/pybind11", @@ -121,7 +126,7 @@ def test_build_sdist(monkeypatch, tmpdir): 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:]) + simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]} with contextlib.closing( tar.extractfile(tar.getmember(start + "setup.py")) @@ -133,9 +138,19 @@ def test_build_sdist(monkeypatch, tmpdir): ) as f: pyproject_toml = f.read() - files = set("pybind11/{}".format(n) for n in all_files) + with contextlib.closing( + tar.extractfile( + tar.getmember( + start + "pybind11/share/cmake/pybind11/pybind11Config.cmake" + ) + ) + ) as f: + contents = f.read().decode("utf8") + assert 'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")' in contents + + files = {"pybind11/{}".format(n) for n in all_files} files |= sdist_files - files |= set("pybind11{}".format(n) for n in local_sdist_files) + files |= {"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 @@ -146,11 +161,11 @@ def test_build_sdist(monkeypatch, tmpdir): .substitute(version=version, extra_cmd="") .encode() ) - assert setup_py == contents + assert setup_py == contents with open(os.path.join(MAIN_DIR, "tools", "pyproject.toml"), "rb") as f: contents = f.read() - assert pyproject_toml == contents + assert pyproject_toml == contents def test_build_global_dist(monkeypatch, tmpdir): @@ -176,7 +191,7 @@ def test_build_global_dist(monkeypatch, tmpdir): 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:]) + simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]} with contextlib.closing( tar.extractfile(tar.getmember(start + "setup.py")) @@ -188,9 +203,9 @@ def test_build_global_dist(monkeypatch, tmpdir): ) as f: pyproject_toml = f.read() - files = set("pybind11/{}".format(n) for n in all_files) + files = {"pybind11/{}".format(n) for n in all_files} files |= sdist_files - files |= set("pybind11_global{}".format(n) for n in local_sdist_files) + files |= {"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: @@ -215,7 +230,7 @@ def tests_build_wheel(monkeypatch, tmpdir): (wheel,) = tmpdir.visit("*.whl") - files = set("pybind11/{}".format(n) for n in all_files) + files = {"pybind11/{}".format(n) for n in all_files} files |= { "dist-info/LICENSE", "dist-info/METADATA", @@ -228,10 +243,10 @@ def tests_build_wheel(monkeypatch, tmpdir): with zipfile.ZipFile(str(wheel)) as z: names = z.namelist() - trimmed = set(n for n in names if "dist-info" not in n) - trimmed |= set( + trimmed = {n for n in names if "dist-info" not in n} + trimmed |= { "dist-info/{}".format(n.split("/", 1)[-1]) for n in names if "dist-info" in n - ) + } assert files == trimmed @@ -245,8 +260,8 @@ def tests_build_global_wheel(monkeypatch, 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 = {"data/data/{}".format(n) for n in src_files} + files |= {"data/headers/{}".format(n[8:]) for n in headers} files |= { "dist-info/LICENSE", "dist-info/METADATA", @@ -259,6 +274,6 @@ def tests_build_global_wheel(monkeypatch, tmpdir): names = z.namelist() beginning = names[0].split("/", 1)[0].rsplit(".", 1)[0] - trimmed = set(n[len(beginning) + 1 :] for n in names) + trimmed = {n[len(beginning) + 1 :] for n in names} assert files == trimmed diff --git a/thirdparty/pybind11/tests/extra_setuptools/test_setuphelper.py b/thirdparty/pybind11/tests/extra_setuptools/test_setuphelper.py index 0d8bd0e4d6..fb2d342086 100644 --- a/thirdparty/pybind11/tests/extra_setuptools/test_setuphelper.py +++ b/thirdparty/pybind11/tests/extra_setuptools/test_setuphelper.py @@ -99,3 +99,45 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std): subprocess.check_call( [sys.executable, "test.py"], stdout=sys.stdout, stderr=sys.stderr ) + + +def test_intree_extensions(monkeypatch, tmpdir): + monkeypatch.syspath_prepend(MAIN_DIR) + + from pybind11.setup_helpers import intree_extensions + + monkeypatch.chdir(tmpdir) + root = tmpdir + root.ensure_dir() + subdir = root / "dir" + subdir.ensure_dir() + src = subdir / "ext.cpp" + src.ensure() + (ext,) = intree_extensions([src.relto(tmpdir)]) + assert ext.name == "ext" + subdir.ensure("__init__.py") + (ext,) = intree_extensions([src.relto(tmpdir)]) + assert ext.name == "dir.ext" + + +def test_intree_extensions_package_dir(monkeypatch, tmpdir): + monkeypatch.syspath_prepend(MAIN_DIR) + + from pybind11.setup_helpers import intree_extensions + + monkeypatch.chdir(tmpdir) + root = tmpdir / "src" + root.ensure_dir() + subdir = root / "dir" + subdir.ensure_dir() + src = subdir / "ext.cpp" + src.ensure() + (ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"": "src"}) + assert ext.name == "dir.ext" + (ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"foo": "src"}) + assert ext.name == "foo.dir.ext" + subdir.ensure("__init__.py") + (ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"": "src"}) + assert ext.name == "dir.ext" + (ext,) = intree_extensions([src.relto(tmpdir)], package_dir={"foo": "src"}) + assert ext.name == "foo.dir.ext" diff --git a/thirdparty/pybind11/tests/local_bindings.h b/thirdparty/pybind11/tests/local_bindings.h index 22537b13ad..8629ed7784 100644 --- a/thirdparty/pybind11/tests/local_bindings.h +++ b/thirdparty/pybind11/tests/local_bindings.h @@ -1,4 +1,6 @@ #pragma once +#include + #include "pybind11_tests.h" /// Simple class used to test py::local: @@ -54,9 +56,9 @@ py::class_ bind_local(Args && ...args) { namespace pets { class Pet { public: - Pet(std::string name) : name_(name) {} + Pet(std::string name) : name_(std::move(name)) {} std::string name_; - const std::string &name() { return name_; } + const std::string &name() const { return name_; } }; } // namespace pets diff --git a/thirdparty/pybind11/tests/object.h b/thirdparty/pybind11/tests/object.h index 9235f19c20..865a9beae8 100644 --- a/thirdparty/pybind11/tests/object.h +++ b/thirdparty/pybind11/tests/object.h @@ -81,7 +81,7 @@ public: } /// Move constructor - ref(ref &&r) : m_ptr(r.m_ptr) { + ref(ref &&r) noexcept : m_ptr(r.m_ptr) { r.m_ptr = nullptr; print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this); @@ -96,7 +96,7 @@ public: } /// Move another reference into the current one - ref& operator=(ref&& r) { + ref &operator=(ref &&r) noexcept { print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this); if (*this == r) diff --git a/thirdparty/pybind11/tests/pybind11_cross_module_tests.cpp b/thirdparty/pybind11/tests/pybind11_cross_module_tests.cpp index f705e31061..e79701c6c6 100644 --- a/thirdparty/pybind11/tests/pybind11_cross_module_tests.cpp +++ b/thirdparty/pybind11/tests/pybind11_cross_module_tests.cpp @@ -9,8 +9,12 @@ #include "pybind11_tests.h" #include "local_bindings.h" +#include "test_exceptions.h" + #include + #include +#include PYBIND11_MODULE(pybind11_cross_module_tests, m) { m.doc() = "pybind11 cross-module test module"; @@ -30,6 +34,13 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) { m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); }); m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); }); m.def("throw_stop_iteration", []() { throw py::stop_iteration(); }); + py::register_exception_translator([](std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (const shared_exception &e) { + PyErr_SetString(PyExc_KeyError, e.what()); + } + }); // test_local_bindings.py // Local to both: @@ -96,7 +107,10 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) { m.def("return_self", [](LocalVec *v) { return v; }); m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); }); - class Dog : public pets::Pet { public: Dog(std::string name) : Pet(name) {}; }; + class Dog : public pets::Pet { + public: + Dog(std::string name) : Pet(std::move(name)) {} + }; py::class_(m, "Pet", py::module_local()) .def("name", &pets::Pet::name); // Binding for local extending class: @@ -118,6 +132,6 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) { // test_missing_header_message // The main module already includes stl.h, but we need to test the error message // which appears when this header is missing. - m.def("missing_header_arg", [](std::vector) { }); + m.def("missing_header_arg", [](const std::vector &) {}); m.def("missing_header_return", []() { return std::vector(); }); } diff --git a/thirdparty/pybind11/tests/pybind11_tests.h b/thirdparty/pybind11/tests/pybind11_tests.h index ccb0529787..d970ba8bd4 100644 --- a/thirdparty/pybind11/tests/pybind11_tests.h +++ b/thirdparty/pybind11/tests/pybind11_tests.h @@ -1,10 +1,15 @@ #pragma once + +// This must be kept first for MSVC 2015. +// Do not remove the empty line between the #includes. #include + #include #if defined(_MSC_VER) && _MSC_VER < 1910 // We get some really long type names here which causes MSVC 2015 to emit warnings -# pragma warning(disable: 4503) // warning C4503: decorated name length exceeded, name was truncated +# pragma warning( \ + disable : 4503) // warning C4503: decorated name length exceeded, name was truncated #endif namespace py = pybind11; diff --git a/thirdparty/pybind11/tests/requirements.txt b/thirdparty/pybind11/tests/requirements.txt index 257d8d85fb..00cb5f119f 100644 --- a/thirdparty/pybind11/tests/requirements.txt +++ b/thirdparty/pybind11/tests/requirements.txt @@ -5,7 +5,8 @@ numpy==1.19.3; (platform_python_implementation!="PyPy" or sys_platform=="linux") numpy==1.20.0; (platform_python_implementation!="PyPy" or sys_platform=="linux") and python_version>="3.7" and python_version<"3.10" pytest==4.6.9; python_version<"3.5" pytest==6.1.2; python_version=="3.5" -pytest==6.2.1; python_version>="3.6" +pytest==6.2.1; python_version>="3.6" and python_version<="3.9" +pytest @ git+https://github.com/pytest-dev/pytest@c117bc350ec1e570672fda3b2ad234fd52e72b53; python_version>="3.10" pytest-timeout scipy==1.2.3; (platform_python_implementation!="PyPy" or sys_platform=="linux") and python_version<"3.6" scipy==1.5.4; (platform_python_implementation!="PyPy" or sys_platform=="linux") and python_version>="3.6" and python_version<"3.10" diff --git a/thirdparty/pybind11/tests/test_buffers.cpp b/thirdparty/pybind11/tests/test_buffers.cpp index 46eabf3963..e77c626f87 100644 --- a/thirdparty/pybind11/tests/test_buffers.cpp +++ b/thirdparty/pybind11/tests/test_buffers.cpp @@ -27,7 +27,7 @@ TEST_SUBMODULE(buffers, m) { memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols)); } - Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) { + Matrix(Matrix &&s) noexcept : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) { print_move_created(this); s.m_rows = 0; s.m_cols = 0; @@ -49,7 +49,7 @@ TEST_SUBMODULE(buffers, m) { return *this; } - Matrix &operator=(Matrix &&s) { + Matrix &operator=(Matrix &&s) noexcept { print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); if (&s != this) { delete[] m_data; @@ -79,7 +79,7 @@ TEST_SUBMODULE(buffers, m) { py::class_(m, "Matrix", py::buffer_protocol()) .def(py::init()) /// Construct from a buffer - .def(py::init([](py::buffer const b) { + .def(py::init([](const py::buffer &b) { py::buffer_info info = b.request(); if (info.format != py::format_descriptor::format() || info.ndim != 2) throw std::runtime_error("Incompatible buffer format!"); @@ -89,31 +89,31 @@ TEST_SUBMODULE(buffers, m) { return v; })) - .def("rows", &Matrix::rows) - .def("cols", &Matrix::cols) + .def("rows", &Matrix::rows) + .def("cols", &Matrix::cols) /// Bare bones interface - .def("__getitem__", [](const Matrix &m, std::pair 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 i, float v) { - if (i.first >= m.rows() || i.second >= m.cols()) - throw py::index_error(); - m(i.first, i.second) = v; - }) - /// Provide buffer access - .def_buffer([](Matrix &m) -> py::buffer_info { + .def("__getitem__", + [](const Matrix &m, std::pair 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 i, float v) { + if (i.first >= m.rows() || i.second >= m.cols()) + throw py::index_error(); + m(i.first, i.second) = v; + }) + /// Provide buffer access + .def_buffer([](Matrix &m) -> py::buffer_info { return py::buffer_info( m.data(), /* Pointer to buffer */ { m.rows(), m.cols() }, /* Buffer dimensions */ { sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */ sizeof(float) } ); - }) - ; - + }); // test_inherited_protocol class SquareMatrix : public Matrix { @@ -154,7 +154,7 @@ TEST_SUBMODULE(buffers, m) { py::format_descriptor::format(), 1); } - ConstBuffer() : value(new int32_t{0}) { }; + ConstBuffer() : value(new int32_t{0}) {} }; py::class_(m, "ConstBuffer", py::buffer_protocol()) .def(py::init<>()) @@ -208,7 +208,5 @@ TEST_SUBMODULE(buffers, m) { }) ; - m.def("get_buffer_info", [](py::buffer buffer) { - return buffer.request(); - }); + m.def("get_buffer_info", [](const py::buffer &buffer) { return buffer.request(); }); } diff --git a/thirdparty/pybind11/tests/test_builtin_casters.cpp b/thirdparty/pybind11/tests/test_builtin_casters.cpp index f4e775676d..51e410cadd 100644 --- a/thirdparty/pybind11/tests/test_builtin_casters.cpp +++ b/thirdparty/pybind11/tests/test_builtin_casters.cpp @@ -30,7 +30,11 @@ class type_caster { // cast operator. bool load(handle, bool) { return true; } - operator ConstRefCasted&&() { value = {1}; return std::move(value); } + operator ConstRefCasted &&() { + value = {1}; + // NOLINTNEXTLINE(performance-move-const-arg) + return std::move(value); + } operator ConstRefCasted&() { value = {2}; return value; } operator ConstRefCasted*() { value = {3}; return &value; } @@ -101,7 +105,7 @@ TEST_SUBMODULE(builtin_casters, m) { // test_bytes_to_string m.def("strlen", [](char *s) { return strlen(s); }); - m.def("string_length", [](std::string s) { return s.length(); }); + m.def("string_length", [](const std::string &s) { return s.length(); }); #ifdef PYBIND11_HAS_U8STRING m.attr("has_u8string") = true; @@ -146,9 +150,12 @@ TEST_SUBMODULE(builtin_casters, m) { m.def("int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert()); // test_tuple - m.def("pair_passthrough", [](std::pair input) { - return std::make_pair(input.second, input.first); - }, "Return a pair in reversed order"); + m.def( + "pair_passthrough", + [](const std::pair &input) { + return std::make_pair(input.second, input.first); + }, + "Return a pair in reversed order"); m.def("tuple_passthrough", [](std::tuple input) { return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input)); }, "Return a triple in reversed order"); @@ -177,11 +184,11 @@ TEST_SUBMODULE(builtin_casters, m) { // test_none_deferred m.def("defer_none_cstring", [](char *) { return false; }); - m.def("defer_none_cstring", [](py::none) { return true; }); + m.def("defer_none_cstring", [](const py::none &) { return true; }); m.def("defer_none_custom", [](UserType *) { return false; }); - m.def("defer_none_custom", [](py::none) { return true; }); + m.def("defer_none_custom", [](const py::none &) { return true; }); m.def("nodefer_none_void", [](void *) { return true; }); - m.def("nodefer_none_void", [](py::none) { return false; }); + m.def("nodefer_none_void", [](const py::none &) { return false; }); // test_void_caster m.def("load_nullptr_t", [](std::nullptr_t) {}); // not useful, but it should still compile @@ -231,7 +238,7 @@ TEST_SUBMODULE(builtin_casters, m) { }, "copy"_a); m.def("refwrap_iiw", [](const IncType &w) { return w.value(); }); - m.def("refwrap_call_iiw", [](IncType &w, py::function f) { + m.def("refwrap_call_iiw", [](IncType &w, const py::function &f) { py::list l; l.append(f(std::ref(w))); l.append(f(std::cref(w))); diff --git a/thirdparty/pybind11/tests/test_builtin_casters.py b/thirdparty/pybind11/tests/test_builtin_casters.py index fda0384333..1b9dbb2b40 100644 --- a/thirdparty/pybind11/tests/test_builtin_casters.py +++ b/thirdparty/pybind11/tests/test_builtin_casters.py @@ -50,7 +50,7 @@ def test_single_char_arguments(): """Tests failures for passing invalid inputs to char-accepting functions""" def toobig_message(r): - return "Character code point not in range({0:#x})".format(r) + return "Character code point not in range({:#x})".format(r) toolong_message = "Expected a character, but multi-character string found" @@ -301,7 +301,7 @@ def test_int_convert(): cant_convert(3.14159) # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar) if (3, 8) <= env.PY < (3, 10): - with pytest.deprecated_call(): + with env.deprecated_call(): assert convert(Int()) == 42 else: assert convert(Int()) == 42 @@ -336,7 +336,7 @@ def test_numpy_int_convert(): # The implicit conversion from np.float32 is undesirable but currently accepted. # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar) if (3, 8) <= env.PY < (3, 10): - with pytest.deprecated_call(): + with env.deprecated_call(): assert convert(np.float32(3.14159)) == 3 else: assert convert(np.float32(3.14159)) == 3 @@ -521,7 +521,7 @@ def test_void_caster_2(): def test_const_ref_caster(): """Verifies that const-ref is propagated through type_caster cast_op. - The returned ConstRefCasted type is a mimimal type that is constructed to + The returned ConstRefCasted type is a minimal type that is constructed to reference the casting mode used. """ x = False diff --git a/thirdparty/pybind11/tests/test_call_policies.cpp b/thirdparty/pybind11/tests/test_call_policies.cpp index 26c83f81b0..7cb98d0d86 100644 --- a/thirdparty/pybind11/tests/test_call_policies.cpp +++ b/thirdparty/pybind11/tests/test_call_policies.cpp @@ -51,6 +51,7 @@ TEST_SUBMODULE(call_policies, m) { void addChild(Child *) { } Child *returnChild() { return new Child(); } Child *returnNullChild() { return nullptr; } + static Child *staticFunction(Parent*) { return new Child(); } }; py::class_(m, "Parent") .def(py::init<>()) @@ -60,7 +61,12 @@ TEST_SUBMODULE(call_policies, m) { .def("returnChild", &Parent::returnChild) .def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>()) .def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>()) - .def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>()); + .def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>()) + .def_static( + "staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>()); + + m.def("free_function", [](Parent*, Child*) {}, py::keep_alive<1, 2>()); + m.def("invalid_arg_index", []{}, py::keep_alive<0, 1>()); #if !defined(PYPY_VERSION) // test_alive_gc diff --git a/thirdparty/pybind11/tests/test_call_policies.py b/thirdparty/pybind11/tests/test_call_policies.py index e0413d1451..af017e9d0c 100644 --- a/thirdparty/pybind11/tests/test_call_policies.py +++ b/thirdparty/pybind11/tests/test_call_policies.py @@ -46,6 +46,19 @@ def test_keep_alive_argument(capture): """ ) + p = m.Parent() + c = m.Child() + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + m.free_function(p, c) + del c + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + del p + assert ConstructorStats.detail_reg_inst() == n_inst + + with pytest.raises(RuntimeError) as excinfo: + m.invalid_arg_index() + assert str(excinfo.value) == "Could not activate keep_alive!" + def test_keep_alive_return_value(capture): n_inst = ConstructorStats.detail_reg_inst() @@ -85,6 +98,23 @@ def test_keep_alive_return_value(capture): """ ) + p = m.Parent() + assert ConstructorStats.detail_reg_inst() == n_inst + 1 + with capture: + m.Parent.staticFunction(p) + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + assert capture == "Allocating child." + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert ( + capture + == """ + Releasing parent. + Releasing child. + """ + ) + # https://foss.heptapod.net/pypy/pypy/-/issues/2447 @pytest.mark.xfail("env.PYPY", reason="_PyObject_GetDictPtr is unimplemented") diff --git a/thirdparty/pybind11/tests/test_callbacks.cpp b/thirdparty/pybind11/tests/test_callbacks.cpp index dffe538fc5..a50771038b 100644 --- a/thirdparty/pybind11/tests/test_callbacks.cpp +++ b/thirdparty/pybind11/tests/test_callbacks.cpp @@ -17,8 +17,8 @@ int dummy_function(int i) { return i + 1; } TEST_SUBMODULE(callbacks, m) { // test_callbacks, test_function_signatures - m.def("test_callback1", [](py::object func) { return func(); }); - m.def("test_callback2", [](py::object func) { return func("Hello", 'x', true, 5); }); + m.def("test_callback1", [](const py::object &func) { return func(); }); + m.def("test_callback2", [](const py::object &func) { return func("Hello", 'x', true, 5); }); m.def("test_callback3", [](const std::function &func) { return "func(43) = " + std::to_string(func(43)); }); m.def("test_callback4", []() -> std::function { return [](int i) { return i+1; }; }); @@ -27,51 +27,48 @@ TEST_SUBMODULE(callbacks, m) { }); // test_keyword_args_and_generalized_unpacking - m.def("test_tuple_unpacking", [](py::function f) { + m.def("test_tuple_unpacking", [](const py::function &f) { auto t1 = py::make_tuple(2, 3); auto t2 = py::make_tuple(5, 6); return f("positional", 1, *t1, 4, *t2); }); - m.def("test_dict_unpacking", [](py::function f) { + m.def("test_dict_unpacking", [](const py::function &f) { auto d1 = py::dict("key"_a="value", "a"_a=1); auto d2 = py::dict(); auto d3 = py::dict("b"_a=2); return f("positional", 1, **d1, **d2, **d3); }); - m.def("test_keyword_args", [](py::function f) { - return f("x"_a=10, "y"_a=20); - }); + m.def("test_keyword_args", [](const py::function &f) { return f("x"_a = 10, "y"_a = 20); }); - m.def("test_unpacking_and_keywords1", [](py::function f) { + m.def("test_unpacking_and_keywords1", [](const py::function &f) { auto args = py::make_tuple(2); auto kwargs = py::dict("d"_a=4); return f(1, *args, "c"_a=3, **kwargs); }); - m.def("test_unpacking_and_keywords2", [](py::function f) { + m.def("test_unpacking_and_keywords2", [](const py::function &f) { auto kwargs1 = py::dict("a"_a=1); auto kwargs2 = py::dict("c"_a=3, "d"_a=4); return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5, "key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5); }); - m.def("test_unpacking_error1", [](py::function f) { + m.def("test_unpacking_error1", [](const py::function &f) { auto kwargs = py::dict("x"_a=3); return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword }); - m.def("test_unpacking_error2", [](py::function f) { + m.def("test_unpacking_error2", [](const py::function &f) { auto kwargs = py::dict("x"_a=3); return f(**kwargs, "x"_a=1); // duplicate keyword after ** }); - m.def("test_arg_conversion_error1", [](py::function f) { - f(234, UnregisteredType(), "kw"_a=567); - }); + m.def("test_arg_conversion_error1", + [](const py::function &f) { f(234, UnregisteredType(), "kw"_a = 567); }); - m.def("test_arg_conversion_error2", [](py::function f) { + m.def("test_arg_conversion_error2", [](const py::function &f) { f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567); }); @@ -80,12 +77,12 @@ TEST_SUBMODULE(callbacks, m) { Payload() { print_default_created(this); } ~Payload() { print_destroyed(this); } Payload(const Payload &) { print_copy_created(this); } - Payload(Payload &&) { print_move_created(this); } + Payload(Payload &&) noexcept { print_move_created(this); } }; // Export the payload constructor statistics for testing purposes: m.def("payload_cstats", &ConstructorStats::get); /* Test cleanup of lambda closure */ - m.def("test_cleanup", []() -> std::function { + m.def("test_cleanup", []() -> std::function { Payload p; return [p]() { @@ -97,6 +94,8 @@ TEST_SUBMODULE(callbacks, m) { // test_cpp_function_roundtrip /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */ m.def("dummy_function", &dummy_function); + m.def("dummy_function_overloaded", [](int i, int j) { return i + j; }); + m.def("dummy_function_overloaded", &dummy_function); m.def("dummy_function2", [](int i, int j) { return i + j; }); m.def("roundtrip", [](std::function f, bool expect_none = false) { if (expect_none && f) @@ -109,12 +108,13 @@ TEST_SUBMODULE(callbacks, m) { if (!result) { auto r = f(1); return "can't convert to function pointer: eval(1) = " + std::to_string(r); - } else if (*result == dummy_function) { + } + if (*result == dummy_function) { auto r = (*result)(1); return "matches dummy_function: eval(1) = " + std::to_string(r); - } else { - return "argument does NOT match dummy_function. This should never happen!"; } + return "argument does NOT match dummy_function. This should never happen!"; + }); class AbstractBase { @@ -122,10 +122,11 @@ TEST_SUBMODULE(callbacks, m) { // [workaround(intel)] = default does not work here // Defaulting this destructor results in linking errors with the Intel compiler // (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827) - virtual ~AbstractBase() {}; // NOLINT(modernize-use-equals-default) + virtual ~AbstractBase() {} // NOLINT(modernize-use-equals-default) virtual unsigned int func() = 0; }; - m.def("func_accepting_func_accepting_base", [](std::function) { }); + m.def("func_accepting_func_accepting_base", + [](const std::function &) {}); struct MovableObject { bool valid = true; @@ -133,8 +134,8 @@ TEST_SUBMODULE(callbacks, m) { MovableObject() = default; MovableObject(const MovableObject &) = default; MovableObject &operator=(const MovableObject &) = default; - MovableObject(MovableObject &&o) : valid(o.valid) { o.valid = false; } - MovableObject &operator=(MovableObject &&o) { + MovableObject(MovableObject &&o) noexcept : valid(o.valid) { o.valid = false; } + MovableObject &operator=(MovableObject &&o) noexcept { valid = o.valid; o.valid = false; return *this; @@ -143,7 +144,7 @@ TEST_SUBMODULE(callbacks, m) { py::class_(m, "MovableObject"); // test_movable_object - m.def("callback_with_movable", [](std::function f) { + m.def("callback_with_movable", [](const std::function &f) { auto x = MovableObject(); f(x); // lvalue reference shouldn't move out object return x.valid; // must still return `true` @@ -155,9 +156,15 @@ TEST_SUBMODULE(callbacks, m) { .def(py::init<>()) .def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; }); + // This checks that builtin functions can be passed as callbacks + // rather than throwing RuntimeError due to trying to extract as capsule + m.def("test_sum_builtin", [](const std::function &sum_builtin, const py::iterable &i) { + return sum_builtin(i); + }); + // test async Python callbacks using callback_f = std::function; - m.def("test_async_callback", [](callback_f f, py::list work) { + m.def("test_async_callback", [](const callback_f &f, const py::list &work) { // make detached thread that calls `f` with piece of work after a little delay auto start_f = [f](int j) { auto invoke_f = [f, j] { @@ -172,4 +179,10 @@ TEST_SUBMODULE(callbacks, m) { for (auto i : work) start_f(py::cast(i)); }); + + m.def("callback_num_times", [](const py::function &f, std::size_t num) { + for (std::size_t i = 0; i < num; i++) { + f(); + } + }); } diff --git a/thirdparty/pybind11/tests/test_callbacks.py b/thirdparty/pybind11/tests/test_callbacks.py index 039b877ced..5bc4d1773d 100644 --- a/thirdparty/pybind11/tests/test_callbacks.py +++ b/thirdparty/pybind11/tests/test_callbacks.py @@ -2,6 +2,8 @@ import pytest from pybind11_tests import callbacks as m from threading import Thread +import time +import env # NOQA: F401 def test_callbacks(): @@ -92,6 +94,10 @@ def test_cpp_function_roundtrip(): m.test_dummy_function(m.roundtrip(m.dummy_function)) == "matches dummy_function: eval(1) = 2" ) + assert ( + m.test_dummy_function(m.dummy_function_overloaded) + == "matches dummy_function: eval(1) = 2" + ) assert m.roundtrip(None, expect_none=True) is None assert ( m.test_dummy_function(lambda x: x + 2) @@ -119,6 +125,16 @@ def test_movable_object(): assert m.callback_with_movable(lambda _: None) is True +@pytest.mark.skipif( + "env.PYPY", + reason="PyPy segfaults on here. See discussion on #1413.", +) +def test_python_builtins(): + """Test if python builtins like sum() can be used as callbacks""" + assert m.test_sum_builtin(sum, [1, 2, 3]) == 6 + assert m.test_sum_builtin(sum, []) == 0 + + def test_async_callbacks(): # serves as state for async callback class Item: @@ -139,10 +155,41 @@ def test_async_callbacks(): from time import sleep sleep(0.5) - assert sum(res) == sum([x + 3 for x in work]) + assert sum(res) == sum(x + 3 for x in work) def test_async_async_callbacks(): t = Thread(target=test_async_callbacks) t.start() t.join() + + +def test_callback_num_times(): + # Super-simple micro-benchmarking related to PR #2919. + # Example runtimes (Intel Xeon 2.2GHz, fully optimized): + # num_millions 1, repeats 2: 0.1 secs + # num_millions 20, repeats 10: 11.5 secs + one_million = 1000000 + num_millions = 1 # Try 20 for actual micro-benchmarking. + repeats = 2 # Try 10. + rates = [] + for rep in range(repeats): + t0 = time.time() + m.callback_num_times(lambda: None, num_millions * one_million) + td = time.time() - t0 + rate = num_millions / td if td else 0 + rates.append(rate) + if not rep: + print() + print( + "callback_num_times: {:d} million / {:.3f} seconds = {:.3f} million / second".format( + num_millions, td, rate + ) + ) + if len(rates) > 1: + print("Min Mean Max") + print( + "{:6.3f} {:6.3f} {:6.3f}".format( + min(rates), sum(rates) / len(rates), max(rates) + ) + ) diff --git a/thirdparty/pybind11/tests/test_chrono.py b/thirdparty/pybind11/tests/test_chrono.py index e9e24e0826..12312c7207 100644 --- a/thirdparty/pybind11/tests/test_chrono.py +++ b/thirdparty/pybind11/tests/test_chrono.py @@ -39,9 +39,7 @@ def test_chrono_system_clock_roundtrip(): # They should be identical (no information lost on roundtrip) diff = abs(date1 - date2) - assert diff.days == 0 - assert diff.seconds == 0 - assert diff.microseconds == 0 + assert diff == datetime.timedelta(0) def test_chrono_system_clock_roundtrip_date(): @@ -64,9 +62,7 @@ def test_chrono_system_clock_roundtrip_date(): assert diff.microseconds == 0 # Year, Month & Day should be the same after the round trip - assert date1.year == date2.year - assert date1.month == date2.month - assert date1.day == date2.day + assert date1 == date2 # There should be no time information assert time2.hour == 0 @@ -117,10 +113,7 @@ def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch): assert isinstance(time2, datetime.time) # Hour, Minute, Second & Microsecond should be the same after the round trip - assert time1.hour == time2.hour - assert time1.minute == time2.minute - assert time1.second == time2.second - assert time1.microsecond == time2.microsecond + assert time1 == time2 # There should be no date information (i.e. date = python base date) assert date2.year == 1970 @@ -140,9 +133,13 @@ def test_chrono_duration_roundtrip(): cpp_diff = m.test_chrono3(diff) - assert cpp_diff.days == diff.days - assert cpp_diff.seconds == diff.seconds - assert cpp_diff.microseconds == diff.microseconds + assert cpp_diff == diff + + # Negative timedelta roundtrip + diff = datetime.timedelta(microseconds=-1) + cpp_diff = m.test_chrono3(diff) + + assert cpp_diff == diff def test_chrono_duration_subtraction_equivalence(): @@ -153,9 +150,7 @@ def test_chrono_duration_subtraction_equivalence(): diff = date2 - date1 cpp_diff = m.test_chrono4(date2, date1) - assert cpp_diff.days == diff.days - assert cpp_diff.seconds == diff.seconds - assert cpp_diff.microseconds == diff.microseconds + assert cpp_diff == diff def test_chrono_duration_subtraction_equivalence_date(): @@ -166,9 +161,7 @@ def test_chrono_duration_subtraction_equivalence_date(): diff = date2 - date1 cpp_diff = m.test_chrono4(date2, date1) - assert cpp_diff.days == diff.days - assert cpp_diff.seconds == diff.seconds - assert cpp_diff.microseconds == diff.microseconds + assert cpp_diff == diff def test_chrono_steady_clock(): @@ -183,9 +176,7 @@ def test_chrono_steady_clock_roundtrip(): assert isinstance(time2, datetime.timedelta) # They should be identical (no information lost on roundtrip) - assert time1.days == time2.days - assert time1.seconds == time2.seconds - assert time1.microseconds == time2.microseconds + assert time1 == time2 def test_floating_point_duration(): diff --git a/thirdparty/pybind11/tests/test_class.cpp b/thirdparty/pybind11/tests/test_class.cpp index bd545e8c68..73de2a61aa 100644 --- a/thirdparty/pybind11/tests/test_class.cpp +++ b/thirdparty/pybind11/tests/test_class.cpp @@ -19,6 +19,8 @@ #include "local_bindings.h" #include +#include + #if defined(_MSC_VER) # pragma warning(disable: 4324) // warning C4324: structure was padded due to alignment specifier #endif @@ -129,7 +131,7 @@ TEST_SUBMODULE(class_, m) { m.def("return_none", []() -> BaseClass* { return nullptr; }); // test_isinstance - m.def("check_instances", [](py::list l) { + m.def("check_instances", [](const py::list &l) { return py::make_tuple( py::isinstance(l[0]), py::isinstance(l[1]), @@ -151,21 +153,16 @@ TEST_SUBMODULE(class_, m) { // return py::type::of(); if (category == 1) return py::type::of(); - else - return py::type::of(); + return py::type::of(); }); - m.def("get_type_of", [](py::object ob) { - return py::type::of(ob); - }); + m.def("get_type_of", [](py::object ob) { return py::type::of(std::move(ob)); }); m.def("get_type_classic", [](py::handle h) { return h.get_type(); }); - m.def("as_type", [](py::object ob) { - return py::type(ob); - }); + m.def("as_type", [](const py::object &ob) { return py::type(ob); }); // test_mismatched_holder struct MismatchBase1 { }; @@ -219,7 +216,7 @@ TEST_SUBMODULE(class_, m) { py::implicitly_convertible(); m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; }); - m.def("implicitly_convert_variable", [](py::object o) { + m.def("implicitly_convert_variable", [](const py::object &o) { // `o` is `UserType` and `r` is a reference to a temporary created by implicit // conversion. This is valid when called inside a bound function because the temp // object is attached to the same life support system as the arguments. @@ -397,7 +394,7 @@ TEST_SUBMODULE(class_, m) { struct StringWrapper { std::string str; }; m.def("test_error_after_conversions", [](int) {}); m.def("test_error_after_conversions", - [](StringWrapper) -> NotRegistered { return {}; }); + [](const StringWrapper &) -> NotRegistered { return {}; }); py::class_(m, "StringWrapper").def(py::init()); py::implicitly_convertible(); @@ -461,19 +458,20 @@ TEST_SUBMODULE(class_, m) { struct OtherDuplicate {}; struct DuplicateNested {}; struct OtherDuplicateNested {}; - m.def("register_duplicate_class_name", [](py::module_ m) { + + m.def("register_duplicate_class_name", [](const py::module_ &m) { py::class_(m, "Duplicate"); py::class_(m, "Duplicate"); }); - m.def("register_duplicate_class_type", [](py::module_ m) { + m.def("register_duplicate_class_type", [](const py::module_ &m) { py::class_(m, "OtherDuplicate"); py::class_(m, "YetAnotherDuplicate"); }); - m.def("register_duplicate_nested_class_name", [](py::object gt) { + m.def("register_duplicate_nested_class_name", [](const py::object >) { py::class_(gt, "DuplicateNested"); py::class_(gt, "DuplicateNested"); }); - m.def("register_duplicate_nested_class_type", [](py::object gt) { + m.def("register_duplicate_nested_class_type", [](const py::object >) { py::class_(gt, "OtherDuplicateNested"); py::class_(gt, "YetAnotherDuplicateNested"); }); diff --git a/thirdparty/pybind11/tests/test_class.py b/thirdparty/pybind11/tests/test_class.py index bdcced9643..1ff60fe214 100644 --- a/thirdparty/pybind11/tests/test_class.py +++ b/thirdparty/pybind11/tests/test_class.py @@ -321,7 +321,7 @@ def test_bind_protected_functions(): def test_brace_initialization(): - """ Tests that simple POD classes can be constructed using C++11 brace initialization """ + """Tests that simple POD classes can be constructed using C++11 brace initialization""" a = m.BraceInitialization(123, "test") assert a.field1 == 123 assert a.field2 == "test" diff --git a/thirdparty/pybind11/tests/test_constants_and_functions.cpp b/thirdparty/pybind11/tests/test_constants_and_functions.cpp index 8855dd7d7c..c0554503fa 100644 --- a/thirdparty/pybind11/tests/test_constants_and_functions.cpp +++ b/thirdparty/pybind11/tests/test_constants_and_functions.cpp @@ -1,5 +1,6 @@ /* - tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw byte strings + tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw + byte strings Copyright (c) 2016 Wenzel Jakob @@ -33,7 +34,7 @@ py::bytes return_bytes() { return std::string(data, 4); } -std::string print_bytes(py::bytes bytes) { +std::string print_bytes(const py::bytes &bytes) { std::string ret = "bytes["; const auto value = static_cast(bytes); for (size_t i = 0; i < value.length(); ++i) { @@ -56,12 +57,13 @@ int f1(int x) noexcept { return x+1; } #endif int f2(int x) noexcept(true) { return x+2; } int f3(int x) noexcept(false) { return x+3; } -#if defined(__GNUG__) +#if defined(__GNUG__) && !defined(__INTEL_COMPILER) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wdeprecated" #endif +// NOLINTNEXTLINE(modernize-use-noexcept) int f4(int x) throw() { return x+4; } // Deprecated equivalent to noexcept(true) -#if defined(__GNUG__) +#if defined(__GNUG__) && !defined(__INTEL_COMPILER) # pragma GCC diagnostic pop #endif struct C { @@ -71,13 +73,15 @@ struct C { int m4(int x) const noexcept(true) { return x-4; } int m5(int x) noexcept(false) { return x-5; } int m6(int x) const noexcept(false) { return x-6; } -#if defined(__GNUG__) +#if defined(__GNUG__) && !defined(__INTEL_COMPILER) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wdeprecated" #endif - int m7(int x) throw() { return x-7; } - int m8(int x) const throw() { return x-8; } -#if defined(__GNUG__) + // NOLINTNEXTLINE(modernize-use-noexcept) + int m7(int x) throw() { return x - 7; } + // NOLINTNEXTLINE(modernize-use-noexcept) + int m8(int x) const throw() { return x - 8; } +#if defined(__GNUG__) && !defined(__INTEL_COMPILER) # pragma GCC diagnostic pop #endif }; @@ -129,7 +133,14 @@ TEST_SUBMODULE(constants_and_functions, m) { ; m.def("f1", f1); m.def("f2", f2); +#if defined(__INTEL_COMPILER) +# pragma warning push +# pragma warning disable 878 // incompatible exception specifications +#endif m.def("f3", f3); +#if defined(__INTEL_COMPILER) +# pragma warning pop +#endif m.def("f4", f4); // test_function_record_leaks @@ -142,8 +153,13 @@ TEST_SUBMODULE(constants_and_functions, m) { LargeCapture capture; // VS 2015's MSVC is acting up if we create the array here m.def("should_raise", [capture](int) { return capture.zeros[9] + 33; }, py::kw_only(), py::arg()); }); - m.def("register_with_raising_repr", [](py::module_ m, py::object default_value) { - m.def("should_raise", [](int, int, py::object) { return 42; }, "some docstring", - py::arg_v("x", 42), py::arg_v("y", 42, ""), py::arg_v("z", default_value)); + m.def("register_with_raising_repr", [](py::module_ m, const py::object &default_value) { + m.def( + "should_raise", + [](int, int, const py::object &) { return 42; }, + "some docstring", + py::arg_v("x", 42), + py::arg_v("y", 42, ""), + py::arg_v("z", default_value)); }); } diff --git a/thirdparty/pybind11/tests/test_copy_move.cpp b/thirdparty/pybind11/tests/test_copy_move.cpp index 322e9bb85d..859da9df7e 100644 --- a/thirdparty/pybind11/tests/test_copy_move.cpp +++ b/thirdparty/pybind11/tests/test_copy_move.cpp @@ -37,9 +37,16 @@ template <> lacking_move_ctor empty::instance_ = {}; class MoveOnlyInt { public: MoveOnlyInt() { print_default_created(this); } - MoveOnlyInt(int v) : value{std::move(v)} { print_created(this, value); } - MoveOnlyInt(MoveOnlyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); } - MoveOnlyInt &operator=(MoveOnlyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; } + MoveOnlyInt(int v) : value{v} { print_created(this, value); } + MoveOnlyInt(MoveOnlyInt &&m) noexcept { + print_move_created(this, m.value); + std::swap(value, m.value); + } + MoveOnlyInt &operator=(MoveOnlyInt &&m) noexcept { + print_move_assigned(this, m.value); + std::swap(value, m.value); + return *this; + } MoveOnlyInt(const MoveOnlyInt &) = delete; MoveOnlyInt &operator=(const MoveOnlyInt &) = delete; ~MoveOnlyInt() { print_destroyed(this); } @@ -49,9 +56,16 @@ public: class MoveOrCopyInt { public: MoveOrCopyInt() { print_default_created(this); } - MoveOrCopyInt(int v) : value{std::move(v)} { print_created(this, value); } - MoveOrCopyInt(MoveOrCopyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); } - MoveOrCopyInt &operator=(MoveOrCopyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; } + MoveOrCopyInt(int v) : value{v} { print_created(this, value); } + MoveOrCopyInt(MoveOrCopyInt &&m) noexcept { + print_move_created(this, m.value); + std::swap(value, m.value); + } + MoveOrCopyInt &operator=(MoveOrCopyInt &&m) noexcept { + print_move_assigned(this, m.value); + std::swap(value, m.value); + return *this; + } MoveOrCopyInt(const MoveOrCopyInt &c) { print_copy_created(this, c.value); value = c.value; } MoveOrCopyInt &operator=(const MoveOrCopyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; } ~MoveOrCopyInt() { print_destroyed(this); } @@ -61,7 +75,7 @@ public: class CopyOnlyInt { public: CopyOnlyInt() { print_default_created(this); } - CopyOnlyInt(int v) : value{std::move(v)} { print_created(this, value); } + CopyOnlyInt(int v) : value{v} { print_created(this, value); } CopyOnlyInt(const CopyOnlyInt &c) { print_copy_created(this, c.value); value = c.value; } CopyOnlyInt &operator=(const CopyOnlyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; } ~CopyOnlyInt() { print_destroyed(this); } @@ -111,7 +125,8 @@ TEST_SUBMODULE(copy_move_policies, m) { py::return_value_policy::move); // test_move_and_copy_casts - m.def("move_and_copy_casts", [](py::object o) { + // NOLINTNEXTLINE(performance-unnecessary-value-param) + m.def("move_and_copy_casts", [](const py::object &o) { int r = 0; r += py::cast(o).value; /* moves */ r += py::cast(o).value; /* moves */ @@ -126,7 +141,11 @@ TEST_SUBMODULE(copy_move_policies, m) { // test_move_and_copy_loads m.def("move_only", [](MoveOnlyInt m) { return m.value; }); + // Changing this breaks the existing test: needs careful review. + // NOLINTNEXTLINE(performance-unnecessary-value-param) m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; }); + // Changing this breaks the existing test: needs careful review. + // NOLINTNEXTLINE(performance-unnecessary-value-param) m.def("copy_only", [](CopyOnlyInt m) { return m.value; }); m.def("move_pair", [](std::pair p) { return p.first.value + p.second.value; @@ -186,8 +205,7 @@ TEST_SUBMODULE(copy_move_policies, m) { void *ptr = std::malloc(bytes); if (ptr) return ptr; - else - throw std::bad_alloc{}; + throw std::bad_alloc{}; } }; py::class_(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value); diff --git a/thirdparty/pybind11/tests/test_custom_type_casters.cpp b/thirdparty/pybind11/tests/test_custom_type_casters.cpp index 3fe910d491..076777d6f1 100644 --- a/thirdparty/pybind11/tests/test_custom_type_casters.cpp +++ b/thirdparty/pybind11/tests/test_custom_type_casters.cpp @@ -67,9 +67,12 @@ public: DestructionTester() { print_default_created(this); } ~DestructionTester() { print_destroyed(this); } DestructionTester(const DestructionTester &) { print_copy_created(this); } - DestructionTester(DestructionTester &&) { print_move_created(this); } + DestructionTester(DestructionTester &&) noexcept { print_move_created(this); } DestructionTester &operator=(const DestructionTester &) { print_copy_assigned(this); return *this; } - DestructionTester &operator=(DestructionTester &&) { print_move_assigned(this); return *this; } + DestructionTester &operator=(DestructionTester &&) noexcept { + print_move_assigned(this); + return *this; + } }; namespace pybind11 { namespace detail { template <> struct type_caster { @@ -94,7 +97,11 @@ TEST_SUBMODULE(custom_type_casters, m) { class ArgInspector { public: ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; } - std::string g(ArgInspector1 a, const ArgInspector1 &b, int c, ArgInspector2 *d, ArgAlwaysConverts) { + std::string g(const ArgInspector1 &a, + const ArgInspector1 &b, + int c, + ArgInspector2 *d, + ArgAlwaysConverts) { return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg; } static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; } @@ -106,8 +113,14 @@ TEST_SUBMODULE(custom_type_casters, m) { .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( + "arg_inspect_func", + [](const ArgInspector2 &a, const ArgInspector1 &b, ArgAlwaysConverts) { + return a.arg + "\n" + b.arg; + }, + py::arg{}.noconvert(false), + py::arg_v(nullptr, ArgInspector1()).noconvert(true), + py::arg() = ArgAlwaysConverts()); m.def("floats_preferred", [](double f) { return 0.5 * f; }, "f"_a); m.def("floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert()); diff --git a/thirdparty/pybind11/tests/test_eigen.cpp b/thirdparty/pybind11/tests/test_eigen.cpp index 8432547439..651be0575f 100644 --- a/thirdparty/pybind11/tests/test_eigen.cpp +++ b/thirdparty/pybind11/tests/test_eigen.cpp @@ -54,8 +54,7 @@ void reset_refs() { } // Returns element 2,1 from a matrix (used to test copy/nocopy) -double get_elem(Eigen::Ref m) { return m(2, 1); }; - +double get_elem(const Eigen::Ref &m) { return m(2, 1); }; // Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix // reference is referencing rows/columns correctly). @@ -94,15 +93,18 @@ TEST_SUBMODULE(eigen, m) { m.def("double_complex", [](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; }); m.def("double_threec", [](py::EigenDRef x) { x *= 2; }); m.def("double_threer", [](py::EigenDRef x) { x *= 2; }); - m.def("double_mat_cm", [](Eigen::MatrixXf x) -> Eigen::MatrixXf { return 2.0f * x; }); - m.def("double_mat_rm", [](DenseMatrixR x) -> DenseMatrixR { return 2.0f * x; }); + m.def("double_mat_cm", [](const Eigen::MatrixXf &x) -> Eigen::MatrixXf { return 2.0f * x; }); + m.def("double_mat_rm", [](const DenseMatrixR &x) -> DenseMatrixR { return 2.0f * x; }); // test_eigen_ref_to_python // Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended - m.def("cholesky1", [](Eigen::Ref x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); + m.def("cholesky1", + [](const Eigen::Ref &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky2", [](const Eigen::Ref &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky3", [](const Eigen::Ref &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); - m.def("cholesky4", [](Eigen::Ref x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); + m.def("cholesky4", [](const Eigen::Ref &x) -> Eigen::MatrixXd { + return x.llt().matrixL(); + }); // test_eigen_ref_mutators // Mutators: these add some value to the given element using Eigen, but Eigen should be mapping into @@ -247,16 +249,19 @@ TEST_SUBMODULE(eigen, m) { m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; }); m.def("fixed_copy_c", [](const FixedMatrixC &m) -> FixedMatrixC { return m; }); // test_mutator_descriptors - m.def("fixed_mutator_r", [](Eigen::Ref) {}); - m.def("fixed_mutator_c", [](Eigen::Ref) {}); - m.def("fixed_mutator_a", [](py::EigenDRef) {}); + m.def("fixed_mutator_r", [](const Eigen::Ref &) {}); + m.def("fixed_mutator_c", [](const Eigen::Ref &) {}); + m.def("fixed_mutator_a", [](const py::EigenDRef &) {}); // test_dense m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); }); m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); }); m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; }); m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; }); // test_sparse, test_sparse_signature - m.def("sparse_r", [mat]() -> SparseMatrixR { return Eigen::SparseView(mat); }); //NOLINT(clang-analyzer-core.uninitialized.UndefReturn) + m.def("sparse_r", [mat]() -> SparseMatrixR { + // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) + return Eigen::SparseView(mat); + }); m.def("sparse_c", [mat]() -> SparseMatrixC { return Eigen::SparseView(mat); }); m.def("sparse_copy_r", [](const SparseMatrixR &m) -> SparseMatrixR { return m; }); m.def("sparse_copy_c", [](const SparseMatrixC &m) -> SparseMatrixC { return m; }); @@ -280,8 +285,10 @@ TEST_SUBMODULE(eigen, m) { // that would allow copying (if types or strides don't match) for comparison: m.def("get_elem", &get_elem); // Now this alternative that calls the tells pybind to fail rather than copy: - m.def("get_elem_nocopy", [](Eigen::Ref m) -> double { return get_elem(m); }, - py::arg{}.noconvert()); + m.def( + "get_elem_nocopy", + [](const Eigen::Ref &m) -> double { return get_elem(m); }, + py::arg{}.noconvert()); // Also test a row-major-only no-copy const ref: m.def("get_elem_rm_nocopy", [](Eigen::Ref> &m) -> long { return m(2, 1); }, py::arg{}.noconvert()); @@ -295,18 +302,23 @@ TEST_SUBMODULE(eigen, m) { // test_issue1105 // Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense - // eigen Vector or RowVector, the argument would fail to load because the numpy copy would fail: - // numpy won't broadcast a Nx1 into a 1-dimensional vector. - m.def("iss1105_col", [](Eigen::VectorXd) { return true; }); - m.def("iss1105_row", [](Eigen::RowVectorXd) { return true; }); + // eigen Vector or RowVector, the argument would fail to load because the numpy copy would + // fail: numpy won't broadcast a Nx1 into a 1-dimensional vector. + m.def("iss1105_col", [](const Eigen::VectorXd &) { return true; }); + m.def("iss1105_row", [](const Eigen::RowVectorXd &) { return true; }); // test_named_arguments // Make sure named arguments are working properly: - m.def("matrix_multiply", [](const py::EigenDRef A, const py::EigenDRef B) - -> Eigen::MatrixXd { - if (A.cols() != B.rows()) throw std::domain_error("Nonconformable matrices!"); - return A * B; - }, py::arg("A"), py::arg("B")); + m.def( + "matrix_multiply", + [](const py::EigenDRef &A, + const py::EigenDRef &B) -> Eigen::MatrixXd { + if (A.cols() != B.rows()) + throw std::domain_error("Nonconformable matrices!"); + return A * B; + }, + py::arg("A"), + py::arg("B")); // test_custom_operator_new py::class_(m, "CustomOperatorNew") @@ -318,7 +330,7 @@ TEST_SUBMODULE(eigen, m) { // In case of a failure (the caster's temp array does not live long enough), creating // a new array (np.ones(10)) increases the chances that the temp array will be garbage // collected and/or that its memory will be overridden with different values. - m.def("get_elem_direct", [](Eigen::Ref v) { + m.def("get_elem_direct", [](const Eigen::Ref &v) { py::module_::import("numpy").attr("ones")(10); return v(5); }); diff --git a/thirdparty/pybind11/tests/test_embed/test_interpreter.cpp b/thirdparty/pybind11/tests/test_embed/test_interpreter.cpp index 944334ce66..cd50e952f6 100644 --- a/thirdparty/pybind11/tests/test_embed/test_interpreter.cpp +++ b/thirdparty/pybind11/tests/test_embed/test_interpreter.cpp @@ -8,16 +8,17 @@ #include -#include #include #include +#include +#include namespace py = pybind11; using namespace py::literals; class Widget { public: - Widget(std::string message) : message(message) { } + Widget(std::string message) : message(std::move(message)) {} virtual ~Widget() = default; std::string the_message() const { return message; } @@ -102,7 +103,7 @@ bool has_pybind11_internals_builtin() { bool has_pybind11_internals_static() { auto **&ipp = py::detail::get_internals_pp(); - return ipp && *ipp; + return (ipp != nullptr) && (*ipp != nullptr); } TEST_CASE("Restart the interpreter") { diff --git a/thirdparty/pybind11/tests/test_eval.cpp b/thirdparty/pybind11/tests/test_eval.cpp index 5416c2ec4d..16cdf17f22 100644 --- a/thirdparty/pybind11/tests/test_eval.cpp +++ b/thirdparty/pybind11/tests/test_eval.cpp @@ -9,7 +9,9 @@ #include + #include "pybind11_tests.h" +#include TEST_SUBMODULE(eval_, m) { // test_evals @@ -64,10 +66,10 @@ TEST_SUBMODULE(eval_, m) { auto local = py::dict(); local["y"] = py::int_(43); - int val_out; + int val_out = 0; local["call_test2"] = py::cpp_function([&](int value) { val_out = value; }); - auto result = py::eval_file(filename, global, local); + auto result = py::eval_file(std::move(filename), global, local); return val_out == 43 && result.is_none(); }); diff --git a/thirdparty/pybind11/tests/test_exceptions.cpp b/thirdparty/pybind11/tests/test_exceptions.cpp index e27c16dfef..f7bacd07e4 100644 --- a/thirdparty/pybind11/tests/test_exceptions.cpp +++ b/thirdparty/pybind11/tests/test_exceptions.cpp @@ -7,7 +7,10 @@ BSD-style license that can be found in the LICENSE file. */ +#include "test_exceptions.h" + #include "pybind11_tests.h" +#include // A type that should be raised as an exception in Python class MyException : public std::exception { @@ -198,34 +201,38 @@ TEST_SUBMODULE(exceptions, m) { throw py::error_already_set(); }); - m.def("python_call_in_destructor", [](py::dict d) { + m.def("python_call_in_destructor", [](const py::dict &d) { + bool retval = false; try { PythonCallInDestructor set_dict_in_destructor(d); PyErr_SetString(PyExc_ValueError, "foo"); throw py::error_already_set(); } catch (const py::error_already_set&) { - return true; + retval = true; } - return false; + return retval; }); - m.def("python_alreadyset_in_destructor", [](py::str s) { + m.def("python_alreadyset_in_destructor", [](const py::str &s) { PythonAlreadySetInDestructor alreadyset_in_destructor(s); return true; }); // test_nested_throws - m.def("try_catch", [m](py::object exc_type, py::function f, py::args args) { - try { f(*args); } - catch (py::error_already_set &ex) { - if (ex.matches(exc_type)) - py::print(ex.what()); - else - throw; - } - }); + m.def("try_catch", + [m](const py::object &exc_type, const py::function &f, const py::args &args) { + try { + f(*args); + } catch (py::error_already_set &ex) { + if (ex.matches(exc_type)) + py::print(ex.what()); + else + throw; + } + }); // Test repr that cannot be displayed m.def("simple_bool_passthrough", [](bool x) {return x;}); + m.def("throw_should_be_translated_to_key_error", []() { throw shared_exception(); }); } diff --git a/thirdparty/pybind11/tests/test_exceptions.h b/thirdparty/pybind11/tests/test_exceptions.h new file mode 100644 index 0000000000..9d428312eb --- /dev/null +++ b/thirdparty/pybind11/tests/test_exceptions.h @@ -0,0 +1,12 @@ +#pragma once +#include "pybind11_tests.h" +#include + +// shared exceptions for cross_module_tests + +class PYBIND11_EXPORT_EXCEPTION shared_exception : public pybind11::builtin_exception { +public: + using builtin_exception::builtin_exception; + explicit shared_exception() : shared_exception("") {} + void set_error() const override { PyErr_SetString(PyExc_RuntimeError, what()); } +}; diff --git a/thirdparty/pybind11/tests/test_exceptions.py b/thirdparty/pybind11/tests/test_exceptions.py index c6cb65299e..b9fc269381 100644 --- a/thirdparty/pybind11/tests/test_exceptions.py +++ b/thirdparty/pybind11/tests/test_exceptions.py @@ -3,6 +3,8 @@ import sys import pytest +import env # noqa: F401 + from pybind11_tests import exceptions as m import pybind11_cross_module_tests as cm @@ -44,6 +46,18 @@ def test_cross_module_exceptions(): cm.throw_stop_iteration() +# TODO: FIXME +@pytest.mark.xfail( + "env.PYPY and env.MACOS", + raises=RuntimeError, + reason="Expected failure with PyPy and libc++ (Issue #2847 & PR #2999)", +) +def test_cross_module_exception_translator(): + with pytest.raises(KeyError): + # translator registered in cross_module_tests + m.throw_should_be_translated_to_key_error() + + def test_python_call_in_catch(): d = {} assert m.python_call_in_destructor(d) is True diff --git a/thirdparty/pybind11/tests/test_factory_constructors.cpp b/thirdparty/pybind11/tests/test_factory_constructors.cpp index 7ff7e7b52c..235ec4dca6 100644 --- a/thirdparty/pybind11/tests/test_factory_constructors.cpp +++ b/thirdparty/pybind11/tests/test_factory_constructors.cpp @@ -8,10 +8,11 @@ BSD-style license that can be found in the LICENSE file. */ -#include "pybind11_tests.h" #include "constructor_stats.h" +#include "pybind11_tests.h" #include #include +#include // Classes for testing python construction via C++ factory function: // Not publicly constructible, copyable, or movable: @@ -20,12 +21,12 @@ class TestFactory1 { TestFactory1() : value("(empty)") { print_default_created(this); } TestFactory1(int v) : value(std::to_string(v)) { print_created(this, value); } TestFactory1(std::string v) : value(std::move(v)) { print_created(this, value); } +public: + std::string value; TestFactory1(TestFactory1 &&) = delete; TestFactory1(const TestFactory1 &) = delete; TestFactory1 &operator=(TestFactory1 &&) = delete; TestFactory1 &operator=(const TestFactory1 &) = delete; -public: - std::string value; ~TestFactory1() { print_destroyed(this); } }; // Non-public construction, but moveable: @@ -35,8 +36,15 @@ class TestFactory2 { TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); } TestFactory2(std::string v) : value(std::move(v)) { print_created(this, value); } public: - TestFactory2(TestFactory2 &&m) { value = std::move(m.value); print_move_created(this); } - TestFactory2 &operator=(TestFactory2 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; } + TestFactory2(TestFactory2 &&m) noexcept { + value = std::move(m.value); + print_move_created(this); + } + TestFactory2 &operator=(TestFactory2 &&m) noexcept { + value = std::move(m.value); + print_move_assigned(this); + return *this; + } std::string value; ~TestFactory2() { print_destroyed(this); } }; @@ -48,8 +56,15 @@ protected: TestFactory3(int v) : value(std::to_string(v)) { print_created(this, value); } public: TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); } - TestFactory3(TestFactory3 &&m) { value = std::move(m.value); print_move_created(this); } - TestFactory3 &operator=(TestFactory3 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; } + TestFactory3(TestFactory3 &&m) noexcept { + value = std::move(m.value); + print_move_created(this); + } + TestFactory3 &operator=(TestFactory3 &&m) noexcept { + value = std::move(m.value); + print_move_assigned(this); + return *this; + } std::string value; virtual ~TestFactory3() { print_destroyed(this); } }; @@ -73,11 +88,15 @@ protected: bool alias = false; public: TestFactory6(int i) : value{i} { print_created(this, i); } - TestFactory6(TestFactory6 &&f) { print_move_created(this); value = f.value; alias = f.alias; } + TestFactory6(TestFactory6 &&f) noexcept { + print_move_created(this); + value = f.value; + alias = f.alias; + } TestFactory6(const TestFactory6 &f) { print_copy_created(this); value = f.value; alias = f.alias; } virtual ~TestFactory6() { print_destroyed(this); } virtual int get() { return value; } - bool has_alias() { return alias; } + bool has_alias() const { return alias; } }; class PyTF6 : public TestFactory6 { public: @@ -85,7 +104,7 @@ public: // when an alias is needed: PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) { alias = true; print_created(this, "move", value); } PyTF6(int i) : TestFactory6(i) { alias = true; print_created(this, i); } - PyTF6(PyTF6 &&f) : TestFactory6(std::move(f)) { print_move_created(this); } + PyTF6(PyTF6 &&f) noexcept : TestFactory6(std::move(f)) { print_move_created(this); } PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); } PyTF6(std::string s) : TestFactory6((int) s.size()) { alias = true; print_created(this, s); } ~PyTF6() override { print_destroyed(this); } @@ -98,16 +117,20 @@ protected: bool alias = false; public: TestFactory7(int i) : value{i} { print_created(this, i); } - TestFactory7(TestFactory7 &&f) { print_move_created(this); value = f.value; alias = f.alias; } + TestFactory7(TestFactory7 &&f) noexcept { + print_move_created(this); + value = f.value; + alias = f.alias; + } TestFactory7(const TestFactory7 &f) { print_copy_created(this); value = f.value; alias = f.alias; } virtual ~TestFactory7() { print_destroyed(this); } virtual int get() { return value; } - bool has_alias() { return alias; } + bool has_alias() const { return alias; } }; class PyTF7 : public TestFactory7 { public: PyTF7(int i) : TestFactory7(i) { alias = true; print_created(this, i); } - PyTF7(PyTF7 &&f) : TestFactory7(std::move(f)) { print_move_created(this); } + PyTF7(PyTF7 &&f) noexcept : TestFactory7(std::move(f)) { print_move_created(this); } PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); } ~PyTF7() override { print_destroyed(this); } int get() override { PYBIND11_OVERRIDE(int, TestFactory7, get, /*no args*/); } @@ -122,7 +145,9 @@ public: // Holder: static std::unique_ptr construct1(int a) { return std::unique_ptr(new TestFactory1(a)); } // pointer again - static TestFactory1 *construct1_string(std::string a) { return new TestFactory1(a); } + static TestFactory1 *construct1_string(std::string a) { + return new TestFactory1(std::move(a)); + } // Moveable type: // pointer: @@ -130,7 +155,7 @@ public: // holder: static std::unique_ptr construct2(int a) { return std::unique_ptr(new TestFactory2(a)); } // by value moving: - static TestFactory2 construct2(std::string a) { return TestFactory2(a); } + static TestFactory2 construct2(std::string a) { return TestFactory2(std::move(a)); } // shared_ptr holder type: // pointer: @@ -173,10 +198,11 @@ TEST_SUBMODULE(factory_constructors, m) { ; py::class_(m, "TestFactory2") .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); })) - .def(py::init([](unique_ptr_tag, std::string v) { return TestFactoryHelper::construct2(v); })) + .def(py::init([](unique_ptr_tag, std::string v) { + return TestFactoryHelper::construct2(std::move(v)); + })) .def(py::init([](move_tag) { return TestFactoryHelper::construct2(); })) - .def_readwrite("value", &TestFactory2::value) - ; + .def_readwrite("value", &TestFactory2::value); // Stateful & reused: int c = 1; @@ -188,7 +214,9 @@ TEST_SUBMODULE(factory_constructors, m) { .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); })) .def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); })); ignoreOldStyleInitWarnings([&pyTestFactory3]() { - pyTestFactory3.def("__init__", [](TestFactory3 &self, std::string v) { new (&self) TestFactory3(v); }); // placement-new ctor + pyTestFactory3.def("__init__", [](TestFactory3 &self, std::string v) { + new (&self) TestFactory3(std::move(v)); + }); // placement-new ctor }); pyTestFactory3 // factories returning a derived type: @@ -219,52 +247,54 @@ TEST_SUBMODULE(factory_constructors, m) { py::class_(m, "TestFactory6") .def(py::init([](base_tag, int i) { return TestFactory6(i); })) .def(py::init([](alias_tag, int i) { return PyTF6(i); })) - .def(py::init([](alias_tag, std::string s) { return PyTF6(s); })) + .def(py::init([](alias_tag, std::string s) { return PyTF6(std::move(s)); })) .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); })) .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); })) - .def(py::init([](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); })) + .def(py::init( + [](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); })) .def("get", &TestFactory6::get) .def("has_alias", &TestFactory6::has_alias) - .def_static("get_cstats", &ConstructorStats::get, py::return_value_policy::reference) - .def_static("get_alias_cstats", &ConstructorStats::get, py::return_value_policy::reference) - ; + .def_static( + "get_cstats", &ConstructorStats::get, py::return_value_policy::reference) + .def_static( + "get_alias_cstats", &ConstructorStats::get, py::return_value_policy::reference); // test_init_factory_dual // Separate alias constructor testing py::class_>(m, "TestFactory7") - .def(py::init( - [](int i) { return TestFactory7(i); }, - [](int i) { return PyTF7(i); })) - .def(py::init( - [](pointer_tag, int i) { return new TestFactory7(i); }, - [](pointer_tag, int i) { return new PyTF7(i); })) - .def(py::init( - [](mixed_tag, int i) { return new TestFactory7(i); }, - [](mixed_tag, int i) { return PyTF7(i); })) - .def(py::init( - [](mixed_tag, std::string s) { return TestFactory7((int) s.size()); }, - [](mixed_tag, std::string s) { return new PyTF7((int) s.size()); })) - .def(py::init( - [](base_tag, pointer_tag, int i) { return new TestFactory7(i); }, - [](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); })) - .def(py::init( - [](alias_tag, pointer_tag, int i) { return new PyTF7(i); }, - [](alias_tag, pointer_tag, int i) { return new PyTF7(10*i); })) + .def(py::init([](int i) { return TestFactory7(i); }, [](int i) { return PyTF7(i); })) + .def(py::init([](pointer_tag, int i) { return new TestFactory7(i); }, + [](pointer_tag, int i) { return new PyTF7(i); })) + .def(py::init([](mixed_tag, int i) { return new TestFactory7(i); }, + [](mixed_tag, int i) { return PyTF7(i); })) + .def(py::init([](mixed_tag, const std::string &s) { return TestFactory7((int) s.size()); }, + [](mixed_tag, const std::string &s) { return new PyTF7((int) s.size()); })) + .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory7(i); }, + [](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); })) + .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF7(i); }, + [](alias_tag, pointer_tag, int i) { return new PyTF7(10 * i); })) .def(py::init( [](shared_ptr_tag, base_tag, int i) { return std::make_shared(i); }, - [](shared_ptr_tag, base_tag, int i) { auto *p = new PyTF7(i); return std::shared_ptr(p); })) - .def(py::init( - [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared(i); }, - [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared(i); })) // <-- invalid alias factory + [](shared_ptr_tag, base_tag, int i) { + auto *p = new PyTF7(i); + return std::shared_ptr(p); + })) + .def(py::init([](shared_ptr_tag, + invalid_base_tag, + int i) { return std::make_shared(i); }, + [](shared_ptr_tag, invalid_base_tag, int i) { + return std::make_shared(i); + })) // <-- invalid alias factory .def("get", &TestFactory7::get) .def("has_alias", &TestFactory7::has_alias) - .def_static("get_cstats", &ConstructorStats::get, py::return_value_policy::reference) - .def_static("get_alias_cstats", &ConstructorStats::get, py::return_value_policy::reference) - ; + .def_static( + "get_cstats", &ConstructorStats::get, py::return_value_policy::reference) + .def_static( + "get_alias_cstats", &ConstructorStats::get, py::return_value_policy::reference); // test_placement_new_alternative // Class with a custom new operator but *without* a placement new operator (issue #948) @@ -331,12 +361,10 @@ TEST_SUBMODULE(factory_constructors, m) { pyNoisyAlloc.def(py::init([](int i, double) { return new NoisyAlloc(i); })); // Regular again: requires yet another preallocation ignoreOldStyleInitWarnings([&pyNoisyAlloc]() { - pyNoisyAlloc.def("__init__", [](NoisyAlloc &a, int i, std::string) { new (&a) NoisyAlloc(i); }); + pyNoisyAlloc.def( + "__init__", [](NoisyAlloc &a, int i, const std::string &) { new (&a) NoisyAlloc(i); }); }); - - - // static_assert testing (the following def's should all fail with appropriate compilation errors): #if 0 struct BadF1Base {}; diff --git a/thirdparty/pybind11/tests/test_factory_constructors.py b/thirdparty/pybind11/tests/test_factory_constructors.py index ffcce6fd4d..8c6ca173ac 100644 --- a/thirdparty/pybind11/tests/test_factory_constructors.py +++ b/thirdparty/pybind11/tests/test_factory_constructors.py @@ -486,7 +486,9 @@ def test_invalid_self(): # Same as above, but for a class with an alias: class BrokenTF6(m.TestFactory6): def __init__(self, bad): - if bad == 1: + if bad == 0: + m.TestFactory6.__init__() + elif bad == 1: a = m.TestFactory2(tag.pointer, 1) m.TestFactory6.__init__(a, tag.base, 1) elif bad == 2: @@ -506,13 +508,13 @@ def test_invalid_self(): BrokenTF1(arg) assert ( str(excinfo.value) - == "__init__(self, ...) called with invalid `self` argument" + == "__init__(self, ...) called with invalid or missing `self` argument" ) - for arg in (1, 2, 3, 4): + for arg in (0, 1, 2, 3, 4): with pytest.raises(TypeError) as excinfo: BrokenTF6(arg) assert ( str(excinfo.value) - == "__init__(self, ...) called with invalid `self` argument" + == "__init__(self, ...) called with invalid or missing `self` argument" ) diff --git a/thirdparty/pybind11/tests/test_gil_scoped.cpp b/thirdparty/pybind11/tests/test_gil_scoped.cpp index b6a45a5f03..b261085c88 100644 --- a/thirdparty/pybind11/tests/test_gil_scoped.cpp +++ b/thirdparty/pybind11/tests/test_gil_scoped.cpp @@ -35,20 +35,15 @@ TEST_SUBMODULE(gil_scoped, m) { .def("virtual_func", &VirtClass::virtual_func) .def("pure_virtual_func", &VirtClass::pure_virtual_func); - m.def("test_callback_py_obj", - [](py::object func) { func(); }); - m.def("test_callback_std_func", - [](const std::function &func) { func(); }); - m.def("test_callback_virtual_func", - [](VirtClass &virt) { virt.virtual_func(); }); - m.def("test_callback_pure_virtual_func", - [](VirtClass &virt) { virt.pure_virtual_func(); }); - m.def("test_cross_module_gil", - []() { - auto cm = py::module_::import("cross_module_gil_utils"); - auto gil_acquire = reinterpret_cast( - PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr())); - py::gil_scoped_release gil_release; - gil_acquire(); - }); + m.def("test_callback_py_obj", [](py::object &func) { func(); }); + m.def("test_callback_std_func", [](const std::function &func) { func(); }); + m.def("test_callback_virtual_func", [](VirtClass &virt) { virt.virtual_func(); }); + m.def("test_callback_pure_virtual_func", [](VirtClass &virt) { virt.pure_virtual_func(); }); + m.def("test_cross_module_gil", []() { + auto cm = py::module_::import("cross_module_gil_utils"); + auto gil_acquire + = reinterpret_cast(PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr())); + py::gil_scoped_release gil_release; + gil_acquire(); + }); } diff --git a/thirdparty/pybind11/tests/test_iostream.cpp b/thirdparty/pybind11/tests/test_iostream.cpp index 1be0655dfb..c620b59493 100644 --- a/thirdparty/pybind11/tests/test_iostream.cpp +++ b/thirdparty/pybind11/tests/test_iostream.cpp @@ -15,17 +15,18 @@ #include "pybind11_tests.h" #include #include +#include +#include #include - -void noisy_function(std::string msg, bool flush) { +void noisy_function(const std::string &msg, bool flush) { std::cout << msg; if (flush) std::cout << std::flush; } -void noisy_funct_dual(std::string msg, std::string emsg) { +void noisy_funct_dual(const std::string &msg, const std::string &emsg) { std::cout << msg; std::cerr << emsg; } @@ -34,10 +35,20 @@ void noisy_funct_dual(std::string msg, std::string emsg) { // simply repeatedly write to std::cerr until stopped // redirect is called at some point to test the safety of scoped_estream_redirect struct TestThread { - TestThread() : t_{nullptr}, stop_{false} { + TestThread() : stop_{false} { auto thread_f = [this] { + static std::mutex cout_mutex; while (!stop_) { - std::cout << "x" << std::flush; + { + // #HelpAppreciated: Work on iostream.h thread safety. + // Without this lock, the clang ThreadSanitizer (tsan) reliably reports a + // data race, and this test is predictably flakey on Windows. + // For more background see the discussion under + // https://github.com/pybind/pybind11/pull/2982 and + // https://github.com/pybind/pybind11/pull/2995. + const std::lock_guard lock(cout_mutex); + std::cout << "x" << std::flush; + } std::this_thread::sleep_for(std::chrono::microseconds(50)); } }; t_ = new std::thread(std::move(thread_f)); @@ -49,7 +60,7 @@ struct TestThread { void stop() { stop_ = true; } - void join() { + void join() const { py::gil_scoped_release gil_lock; t_->join(); } @@ -59,7 +70,7 @@ struct TestThread { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } - std::thread * t_; + std::thread *t_{nullptr}; std::atomic stop_; }; @@ -70,12 +81,12 @@ TEST_SUBMODULE(iostream, m) { // test_evals - m.def("captured_output_default", [](std::string msg) { + m.def("captured_output_default", [](const std::string &msg) { py::scoped_ostream_redirect redir; std::cout << msg << std::flush; }); - m.def("captured_output", [](std::string msg) { + m.def("captured_output", [](const std::string &msg) { py::scoped_ostream_redirect redir(std::cout, py::module_::import("sys").attr("stdout")); std::cout << msg << std::flush; }); @@ -84,7 +95,7 @@ TEST_SUBMODULE(iostream, m) { py::call_guard(), py::arg("msg"), py::arg("flush")=true); - m.def("captured_err", [](std::string msg) { + m.def("captured_err", [](const std::string &msg) { py::scoped_ostream_redirect redir(std::cerr, py::module_::import("sys").attr("stderr")); std::cerr << msg << std::flush; }); @@ -95,15 +106,11 @@ TEST_SUBMODULE(iostream, m) { py::call_guard(), py::arg("msg"), py::arg("emsg")); - m.def("raw_output", [](std::string msg) { - std::cout << msg << std::flush; - }); + m.def("raw_output", [](const std::string &msg) { std::cout << msg << std::flush; }); - m.def("raw_err", [](std::string msg) { - std::cerr << msg << std::flush; - }); + m.def("raw_err", [](const std::string &msg) { std::cerr << msg << std::flush; }); - m.def("captured_dual", [](std::string msg, std::string emsg) { + m.def("captured_dual", [](const std::string &msg, const std::string &emsg) { py::scoped_ostream_redirect redirout(std::cout, py::module_::import("sys").attr("stdout")); py::scoped_ostream_redirect redirerr(std::cerr, py::module_::import("sys").attr("stderr")); std::cout << msg << std::flush; diff --git a/thirdparty/pybind11/tests/test_iostream.py b/thirdparty/pybind11/tests/test_iostream.py index 6d493beda3..e2b74d01cb 100644 --- a/thirdparty/pybind11/tests/test_iostream.py +++ b/thirdparty/pybind11/tests/test_iostream.py @@ -69,6 +69,96 @@ def test_captured_large_string(capsys): assert stderr == "" +def test_captured_utf8_2byte_offset0(capsys): + msg = "\u07FF" + msg = "" + msg * (1024 // len(msg) + 1) + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == "" + + +def test_captured_utf8_2byte_offset1(capsys): + msg = "\u07FF" + msg = "1" + msg * (1024 // len(msg) + 1) + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == "" + + +def test_captured_utf8_3byte_offset0(capsys): + msg = "\uFFFF" + msg = "" + msg * (1024 // len(msg) + 1) + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == "" + + +def test_captured_utf8_3byte_offset1(capsys): + msg = "\uFFFF" + msg = "1" + msg * (1024 // len(msg) + 1) + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == "" + + +def test_captured_utf8_3byte_offset2(capsys): + msg = "\uFFFF" + msg = "12" + msg * (1024 // len(msg) + 1) + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == "" + + +def test_captured_utf8_4byte_offset0(capsys): + msg = "\U0010FFFF" + msg = "" + msg * (1024 // len(msg) + 1) + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == "" + + +def test_captured_utf8_4byte_offset1(capsys): + msg = "\U0010FFFF" + msg = "1" + msg * (1024 // len(msg) + 1) + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == "" + + +def test_captured_utf8_4byte_offset2(capsys): + msg = "\U0010FFFF" + msg = "12" + msg * (1024 // len(msg) + 1) + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == "" + + +def test_captured_utf8_4byte_offset3(capsys): + msg = "\U0010FFFF" + msg = "123" + msg * (1024 // len(msg) + 1) + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == "" + + def test_guard_capture(capsys): msg = "I've been redirected to Python, I hope!" m.guard_output(msg) diff --git a/thirdparty/pybind11/tests/test_kwargs_and_defaults.cpp b/thirdparty/pybind11/tests/test_kwargs_and_defaults.cpp index 627a79690e..63332d32ea 100644 --- a/thirdparty/pybind11/tests/test_kwargs_and_defaults.cpp +++ b/thirdparty/pybind11/tests/test_kwargs_and_defaults.cpp @@ -11,6 +11,8 @@ #include "constructor_stats.h" #include +#include + TEST_SUBMODULE(kwargs_and_defaults, m) { auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); }; @@ -37,18 +39,16 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { m.def("args_function", [](py::args args) -> py::tuple { return std::move(args); }); - m.def("args_kwargs_function", [](py::args args, py::kwargs kwargs) { + m.def("args_kwargs_function", [](const py::args &args, const py::kwargs &kwargs) { return py::make_tuple(args, kwargs); }); // test_mixed_args_and_kwargs - m.def("mixed_plus_args", [](int i, double j, py::args args) { - return py::make_tuple(i, j, args); - }); - m.def("mixed_plus_kwargs", [](int i, double j, py::kwargs kwargs) { - return py::make_tuple(i, j, kwargs); - }); - auto mixed_plus_both = [](int i, double j, py::args args, py::kwargs kwargs) { + m.def("mixed_plus_args", + [](int i, double j, const py::args &args) { return py::make_tuple(i, j, args); }); + m.def("mixed_plus_kwargs", + [](int i, double j, const py::kwargs &kwargs) { return py::make_tuple(i, j, kwargs); }); + auto mixed_plus_both = [](int i, double j, const py::args &args, const py::kwargs &kwargs) { return py::make_tuple(i, j, args, kwargs); }; m.def("mixed_plus_args_kwargs", mixed_plus_both); @@ -65,7 +65,10 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { #endif m.def("arg_refcount_h", [](py::handle h) { GC_IF_NEEDED; return h.ref_count(); }); m.def("arg_refcount_h", [](py::handle h, py::handle, py::handle) { GC_IF_NEEDED; return h.ref_count(); }); - m.def("arg_refcount_o", [](py::object o) { GC_IF_NEEDED; return o.ref_count(); }); + m.def("arg_refcount_o", [](const py::object &o) { + GC_IF_NEEDED; + return o.ref_count(); + }); m.def("args_refcount", [](py::args a) { GC_IF_NEEDED; py::tuple t(a.size()); @@ -74,7 +77,7 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { t[i] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast(i))); return t; }); - m.def("mixed_args_refcount", [](py::object o, py::args a) { + m.def("mixed_args_refcount", [](const py::object &o, py::args a) { GC_IF_NEEDED; py::tuple t(a.size() + 1); t[0] = o.ref_count(); @@ -103,9 +106,15 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { py::arg() = 3, "j"_a = 4, py::kw_only(), "k"_a = 5, "z"_a); m.def("kw_only_mixed", [](int i, int j) { return py::make_tuple(i, j); }, "i"_a, py::kw_only(), "j"_a); - m.def("kw_only_plus_more", [](int i, int j, int k, py::kwargs kwargs) { - return py::make_tuple(i, j, k, kwargs); }, - py::arg() /* positional */, py::arg("j") = -1 /* both */, py::kw_only(), py::arg("k") /* kw-only */); + m.def( + "kw_only_plus_more", + [](int i, int j, int k, const py::kwargs &kwargs) { + return py::make_tuple(i, j, k, kwargs); + }, + py::arg() /* positional */, + py::arg("j") = -1 /* both */, + py::kw_only(), + py::arg("k") /* kw-only */); m.def("register_invalid_kw_only", [](py::module_ m) { m.def("bad_kw_only", [](int i, int j) { return py::make_tuple(i, j); }, @@ -137,6 +146,8 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { // Make sure a class (not an instance) can be used as a default argument. // The return value doesn't matter, only that the module is importable. - m.def("class_default_argument", [](py::object a) { return py::repr(a); }, + m.def( + "class_default_argument", + [](py::object a) { return py::repr(std::move(a)); }, "a"_a = py::module_::import("decimal").attr("Decimal")); } diff --git a/thirdparty/pybind11/tests/test_local_bindings.cpp b/thirdparty/pybind11/tests/test_local_bindings.cpp index c61e388833..bfbab3ed3b 100644 --- a/thirdparty/pybind11/tests/test_local_bindings.cpp +++ b/thirdparty/pybind11/tests/test_local_bindings.cpp @@ -10,9 +10,12 @@ #include "pybind11_tests.h" #include "local_bindings.h" + #include #include + #include +#include TEST_SUBMODULE(local_bindings, m) { // test_load_external @@ -86,7 +89,10 @@ TEST_SUBMODULE(local_bindings, m) { m.def("return_self", [](LocalVec *v) { return v; }); m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); }); - class Cat : public pets::Pet { public: Cat(std::string name) : Pet(name) {}; }; + class Cat : public pets::Pet { + public: + Cat(std::string name) : Pet(std::move(name)) {} + }; py::class_(m, "Pet", py::module_local()) .def("get_name", &pets::Pet::name); // Binding for local extending class: diff --git a/thirdparty/pybind11/tests/test_methods_and_attributes.cpp b/thirdparty/pybind11/tests/test_methods_and_attributes.cpp index f99909bda7..4cf6f08b85 100644 --- a/thirdparty/pybind11/tests/test_methods_and_attributes.cpp +++ b/thirdparty/pybind11/tests/test_methods_and_attributes.cpp @@ -22,16 +22,18 @@ public: 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(ExampleMandA &&e) noexcept : value(e.value) { print_move_created(this); } ~ExampleMandA() { print_destroyed(this); } - std::string toString() { - return "ExampleMandA[value=" + std::to_string(value) + "]"; - } + std::string toString() const { return "ExampleMandA[value=" + std::to_string(value) + "]"; } void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; } - void operator=(ExampleMandA &&e) { print_move_assigned(this); value = e.value; } + void operator=(ExampleMandA &&e) noexcept { + print_move_assigned(this); + value = e.value; + } + // NOLINTNEXTLINE(performance-unnecessary-value-param) void add1(ExampleMandA other) { value += other.value; } // passing by value void add2(ExampleMandA &other) { value += other.value; } // passing by reference void add3(const ExampleMandA &other) { value += other.value; } // passing by const reference @@ -41,6 +43,7 @@ public: void add6(int other) { value += other; } // passing by value void add7(int &other) { value += other; } // passing by reference void add8(const int &other) { value += other; } // passing by const reference + // NOLINTNEXTLINE(readability-non-const-parameter) Deliberately non-const for testing void add9(int *other) { value += *other; } // passing by pointer void add10(const int *other) { value += *other; } // passing by const pointer @@ -48,13 +51,13 @@ public: ExampleMandA self1() { return *this; } // return by value ExampleMandA &self2() { return *this; } // return by reference - const ExampleMandA &self3() { return *this; } // return by const reference + const ExampleMandA &self3() const { return *this; } // return by const reference ExampleMandA *self4() { return this; } // return by pointer - const ExampleMandA *self5() { return this; } // return by const pointer + const ExampleMandA *self5() const { return this; } // return by const pointer - int internal1() { return value; } // return by value + int internal1() const { return value; } // return by value int &internal2() { return value; } // return by reference - const int &internal3() { return value; } // return by const reference + const int &internal3() const { return value; } // return by const reference int *internal4() { return &value; } // return by pointer const int *internal5() { return &value; } // return by const pointer @@ -114,7 +117,15 @@ int none1(const NoneTester &obj) { return obj.answer; } int none2(NoneTester *obj) { return obj ? obj->answer : -1; } int none3(std::shared_ptr &obj) { return obj ? obj->answer : -1; } int none4(std::shared_ptr *obj) { return obj && *obj ? (*obj)->answer : -1; } -int none5(std::shared_ptr obj) { return obj ? obj->answer : -1; } +int none5(const std::shared_ptr &obj) { return obj ? obj->answer : -1; } + +// Issue #2778: implicit casting from None to object (not pointer) +class NoneCastTester { +public: + int answer = -1; + NoneCastTester() = default; + NoneCastTester(int v) : answer(v) {} +}; struct StrIssue { int val = -1; @@ -228,36 +239,41 @@ TEST_SUBMODULE(methods_and_attributes, m) { .def(py::init<>()) .def_readonly("def_readonly", &TestProperties::value) .def_readwrite("def_readwrite", &TestProperties::value) - .def_property("def_writeonly", nullptr, - [](TestProperties& s,int v) { s.value = v; } ) + .def_property("def_writeonly", nullptr, [](TestProperties &s, int v) { s.value = v; }) .def_property("def_property_writeonly", nullptr, &TestProperties::set) .def_property_readonly("def_property_readonly", &TestProperties::get) .def_property("def_property", &TestProperties::get, &TestProperties::set) .def_property("def_property_impossible", nullptr, nullptr) .def_readonly_static("def_readonly_static", &TestProperties::static_value) .def_readwrite_static("def_readwrite_static", &TestProperties::static_value) - .def_property_static("def_writeonly_static", nullptr, - [](py::object, int v) { TestProperties::static_value = v; }) - .def_property_readonly_static("def_property_readonly_static", - [](py::object) { return TestProperties::static_get(); }) - .def_property_static("def_property_writeonly_static", nullptr, - [](py::object, int v) { return TestProperties::static_set(v); }) - .def_property_static("def_property_static", - [](py::object) { return TestProperties::static_get(); }, - [](py::object, int v) { TestProperties::static_set(v); }) - .def_property_static("static_cls", - [](py::object cls) { return cls; }, - [](py::object cls, py::function f) { f(cls); }); + .def_property_static("def_writeonly_static", + nullptr, + [](const py::object &, int v) { TestProperties::static_value = v; }) + .def_property_readonly_static( + "def_property_readonly_static", + [](const py::object &) { return TestProperties::static_get(); }) + .def_property_static( + "def_property_writeonly_static", + nullptr, + [](const py::object &, int v) { return TestProperties::static_set(v); }) + .def_property_static( + "def_property_static", + [](const py::object &) { return TestProperties::static_get(); }, + [](const py::object &, int v) { TestProperties::static_set(v); }) + .def_property_static( + "static_cls", + [](py::object cls) { return cls; }, + [](const py::object &cls, const py::function &f) { f(cls); }); py::class_(m, "TestPropertiesOverride") .def(py::init<>()) .def_readonly("def_readonly", &TestPropertiesOverride::value) .def_readonly_static("def_readonly_static", &TestPropertiesOverride::static_value); - auto static_get1 = [](py::object) -> const UserType & { return TestPropRVP::sv1; }; - auto static_get2 = [](py::object) -> const UserType & { return TestPropRVP::sv2; }; - auto static_set1 = [](py::object, int v) { TestPropRVP::sv1.set(v); }; - auto static_set2 = [](py::object, int v) { TestPropRVP::sv2.set(v); }; + auto static_get1 = [](const py::object &) -> const UserType & { return TestPropRVP::sv1; }; + auto static_get2 = [](const py::object &) -> const UserType & { return TestPropRVP::sv2; }; + auto static_set1 = [](const py::object &, int v) { TestPropRVP::sv1.set(v); }; + auto static_set2 = [](const py::object &, int v) { TestPropRVP::sv2.set(v); }; auto rvp_copy = py::return_value_policy::copy; // test_property_return_value_policies @@ -268,25 +284,28 @@ TEST_SUBMODULE(methods_and_attributes, m) { .def_property_readonly("ro_func", py::cpp_function(&TestPropRVP::get2, rvp_copy)) .def_property("rw_ref", &TestPropRVP::get1, &TestPropRVP::set1) .def_property("rw_copy", &TestPropRVP::get2, &TestPropRVP::set2, rvp_copy) - .def_property("rw_func", py::cpp_function(&TestPropRVP::get2, rvp_copy), &TestPropRVP::set2) + .def_property( + "rw_func", py::cpp_function(&TestPropRVP::get2, rvp_copy), &TestPropRVP::set2) .def_property_readonly_static("static_ro_ref", static_get1) .def_property_readonly_static("static_ro_copy", static_get2, rvp_copy) .def_property_readonly_static("static_ro_func", py::cpp_function(static_get2, rvp_copy)) .def_property_static("static_rw_ref", static_get1, static_set1) .def_property_static("static_rw_copy", static_get2, static_set2, rvp_copy) - .def_property_static("static_rw_func", py::cpp_function(static_get2, rvp_copy), static_set2) + .def_property_static( + "static_rw_func", py::cpp_function(static_get2, rvp_copy), static_set2) // test_property_rvalue_policy .def_property_readonly("rvalue", &TestPropRVP::get_rvalue) - .def_property_readonly_static("static_rvalue", [](py::object) { return UserType(1); }); + .def_property_readonly_static("static_rvalue", + [](const py::object &) { return UserType(1); }); // test_metaclass_override struct MetaclassOverride { }; py::class_(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type)) - .def_property_readonly_static("readonly", [](py::object) { return 1; }); + .def_property_readonly_static("readonly", [](const py::object &) { return 1; }); // test_overload_ordering - m.def("overload_order", [](std::string) { return 1; }); - m.def("overload_order", [](std::string) { return 2; }); + m.def("overload_order", [](const std::string &) { return 1; }); + m.def("overload_order", [](const std::string &) { return 2; }); m.def("overload_order", [](int) { return 3; }); m.def("overload_order", [](int) { return 4; }, py::prepend{}); @@ -341,6 +360,16 @@ TEST_SUBMODULE(methods_and_attributes, m) { m.def("no_none_kwarg", &none2, "a"_a.none(false)); m.def("no_none_kwarg_kw_only", &none2, py::kw_only(), "a"_a.none(false)); + // test_casts_none + // Issue #2778: implicit casting from None to object (not pointer) + py::class_(m, "NoneCastTester") + .def(py::init<>()) + .def(py::init()) + .def(py::init([](py::none const&) { return NoneCastTester{}; })); + py::implicitly_convertible(); + m.def("ok_obj_or_none", [](NoneCastTester const& foo) { return foo.answer; }); + + // test_str_issue // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid py::class_(m, "StrIssue") @@ -362,14 +391,14 @@ TEST_SUBMODULE(methods_and_attributes, m) { .def("increase_value", &RegisteredDerived::increase_value) .def_readwrite("rw_value", &RegisteredDerived::rw_value) .def_readonly("ro_value", &RegisteredDerived::ro_value) - // These should trigger a static_assert if uncommented - //.def_readwrite("fails", &UserType::value) // should trigger a static_assert if uncommented - //.def_readonly("fails", &UserType::value) // should trigger a static_assert if uncommented + // Uncommenting the next line should trigger a static_assert: + // .def_readwrite("fails", &UserType::value) + // Uncommenting the next line should trigger a static_assert: + // .def_readonly("fails", &UserType::value) .def_property("rw_value_prop", &RegisteredDerived::get_int, &RegisteredDerived::set_int) .def_property_readonly("ro_value_prop", &RegisteredDerived::get_double) // This one is in the registered class: - .def("sum", &RegisteredDerived::sum) - ; + .def("sum", &RegisteredDerived::sum); using Adapted = decltype(py::method_adaptor(&RegisteredDerived::do_nothing)); static_assert(std::is_same::value, ""); diff --git a/thirdparty/pybind11/tests/test_methods_and_attributes.py b/thirdparty/pybind11/tests/test_methods_and_attributes.py index 2aaf9331fd..750ec02f89 100644 --- a/thirdparty/pybind11/tests/test_methods_and_attributes.py +++ b/thirdparty/pybind11/tests/test_methods_and_attributes.py @@ -431,6 +431,17 @@ def test_accepts_none(msg): assert "incompatible function arguments" in str(excinfo.value) +def test_casts_none(): + """#2778: implicit casting from None to object (not pointer)""" + a = m.NoneCastTester() + assert m.ok_obj_or_none(a) == -1 + a = m.NoneCastTester(4) + assert m.ok_obj_or_none(a) == 4 + a = m.NoneCastTester(None) + assert m.ok_obj_or_none(a) == -1 + assert m.ok_obj_or_none(None) == -1 + + def test_str_issue(msg): """#283: __str__ called on uninitialized instance when constructor arguments invalid""" diff --git a/thirdparty/pybind11/tests/test_modules.cpp b/thirdparty/pybind11/tests/test_modules.cpp index 67387e809b..5867135404 100644 --- a/thirdparty/pybind11/tests/test_modules.cpp +++ b/thirdparty/pybind11/tests/test_modules.cpp @@ -24,7 +24,8 @@ TEST_SUBMODULE(modules, m) { ~A() { print_destroyed(this); } A(const A&) { print_copy_created(this); } A& operator=(const A ©) { print_copy_assigned(this); v = copy.v; return *this; } - std::string toString() { return "A[" + std::to_string(v) + "]"; } + std::string toString() const { return "A[" + std::to_string(v) + "]"; } + private: int v; }; diff --git a/thirdparty/pybind11/tests/test_multiple_inheritance.cpp b/thirdparty/pybind11/tests/test_multiple_inheritance.cpp index e67200809d..d6b24d34da 100644 --- a/thirdparty/pybind11/tests/test_multiple_inheritance.cpp +++ b/thirdparty/pybind11/tests/test_multiple_inheritance.cpp @@ -11,6 +11,8 @@ #include "pybind11_tests.h" #include "constructor_stats.h" +namespace { + // Many bases for testing that multiple inheritance from many classes (i.e. requiring extra // space for holder constructed flags) works. template struct BaseN { @@ -43,13 +45,40 @@ int WithStatic2::static_value2 = 2; int VanillaStaticMix1::static_value = 12; int VanillaStaticMix2::static_value = 12; +// test_multiple_inheritance_virtbase +struct Base1a { + Base1a(int i) : i(i) { } + int foo() const { return i; } + int i; +}; +struct Base2a { + Base2a(int i) : i(i) { } + int bar() const { return i; } + int i; +}; +struct Base12a : Base1a, Base2a { + Base12a(int i, int j) : Base1a(i), Base2a(j) { } +}; + +// test_mi_unaligned_base +// test_mi_base_return +struct I801B1 { int a = 1; I801B1() = default; I801B1(const I801B1 &) = default; virtual ~I801B1() = default; }; +struct I801B2 { int b = 2; I801B2() = default; I801B2(const I801B2 &) = default; virtual ~I801B2() = default; }; +struct I801C : I801B1, I801B2 {}; +struct I801D : I801C {}; // Indirect MI + +} // namespace + TEST_SUBMODULE(multiple_inheritance, m) { + // Please do not interleave `struct` and `class` definitions with bindings code, + // but implement `struct`s and `class`es in the anonymous namespace above. + // This helps keeping the smart_holder branch in sync with master. // test_multiple_inheritance_mix1 // test_multiple_inheritance_mix2 struct Base1 { Base1(int i) : i(i) { } - int foo() { return i; } + int foo() const { return i; } int i; }; py::class_ b1(m, "Base1"); @@ -58,7 +87,7 @@ TEST_SUBMODULE(multiple_inheritance, m) { struct Base2 { Base2(int i) : i(i) { } - int bar() { return i; } + int bar() const { return i; } int i; }; py::class_ b2(m, "Base2"); @@ -99,41 +128,24 @@ TEST_SUBMODULE(multiple_inheritance, m) { // test_multiple_inheritance_virtbase // Test the case where not all base classes are specified, and where pybind11 requires the // py::multiple_inheritance flag to perform proper casting between types. - struct Base1a { - Base1a(int i) : i(i) { } - int foo() { return i; } - int i; - }; py::class_>(m, "Base1a") .def(py::init()) .def("foo", &Base1a::foo); - struct Base2a { - Base2a(int i) : i(i) { } - int bar() { return i; } - int i; - }; py::class_>(m, "Base2a") .def(py::init()) .def("bar", &Base2a::bar); - struct Base12a : Base1a, Base2a { - Base12a(int i, int j) : Base1a(i), Base2a(j) { } - }; py::class_>(m, "Base12a", py::multiple_inheritance()) .def(py::init()); m.def("bar_base2a", [](Base2a *b) { return b->bar(); }); - m.def("bar_base2a_sharedptr", [](std::shared_ptr b) { return b->bar(); }); + m.def("bar_base2a_sharedptr", [](const std::shared_ptr &b) { return b->bar(); }); // test_mi_unaligned_base // test_mi_base_return // Issue #801: invalid casting to derived type with MI bases - struct I801B1 { int a = 1; I801B1() = default; I801B1(const I801B1 &) = default; virtual ~I801B1() = default; }; - struct I801B2 { int b = 2; I801B2() = default; I801B2(const I801B2 &) = default; virtual ~I801B2() = default; }; - struct I801C : I801B1, I801B2 {}; - struct I801D : I801C {}; // Indirect MI // Unregistered classes: struct I801B3 { int c = 3; virtual ~I801B3() = default; }; struct I801E : I801B3, I801D {}; diff --git a/thirdparty/pybind11/tests/test_numpy_array.cpp b/thirdparty/pybind11/tests/test_numpy_array.cpp index dca7145f9d..5c22a3d25b 100644 --- a/thirdparty/pybind11/tests/test_numpy_array.cpp +++ b/thirdparty/pybind11/tests/test_numpy_array.cpp @@ -13,6 +13,7 @@ #include #include +#include // Size / dtype checks. struct DtypeCheck { @@ -192,7 +193,7 @@ TEST_SUBMODULE(numpy_array, sm) { sm.def("scalar_int", []() { return py::array(py::dtype("i"), {}, {}, &data_i); }); // test_wrap - sm.def("wrap", [](py::array a) { + sm.def("wrap", [](const py::array &a) { return py::array( a.dtype(), {a.shape(), a.shape() + a.ndim()}, @@ -222,9 +223,10 @@ TEST_SUBMODULE(numpy_array, sm) { // test_isinstance sm.def("isinstance_untyped", [](py::object yes, py::object no) { - return py::isinstance(yes) && !py::isinstance(no); + return py::isinstance(std::move(yes)) + && !py::isinstance(std::move(no)); }); - sm.def("isinstance_typed", [](py::object o) { + sm.def("isinstance_typed", [](const py::object &o) { return py::isinstance>(o) && !py::isinstance>(o); }); @@ -236,7 +238,7 @@ TEST_SUBMODULE(numpy_array, sm) { "array_t"_a=py::array_t() ); }); - sm.def("converting_constructors", [](py::object o) { + sm.def("converting_constructors", [](const py::object &o) { return py::dict( "array"_a=py::array(o), "array_t"_a=py::array_t(o), @@ -245,40 +247,47 @@ TEST_SUBMODULE(numpy_array, sm) { }); // test_overload_resolution - sm.def("overloaded", [](py::array_t) { return "double"; }); - sm.def("overloaded", [](py::array_t) { return "float"; }); - sm.def("overloaded", [](py::array_t) { return "int"; }); - sm.def("overloaded", [](py::array_t) { return "unsigned short"; }); - sm.def("overloaded", [](py::array_t) { return "long long"; }); - sm.def("overloaded", [](py::array_t>) { return "double complex"; }); - sm.def("overloaded", [](py::array_t>) { return "float complex"; }); + sm.def("overloaded", [](const py::array_t &) { return "double"; }); + sm.def("overloaded", [](const py::array_t &) { return "float"; }); + sm.def("overloaded", [](const py::array_t &) { return "int"; }); + sm.def("overloaded", [](const py::array_t &) { return "unsigned short"; }); + sm.def("overloaded", [](const py::array_t &) { return "long long"; }); + sm.def("overloaded", + [](const py::array_t> &) { return "double complex"; }); + sm.def("overloaded", [](const py::array_t> &) { return "float complex"; }); - sm.def("overloaded2", [](py::array_t>) { return "double complex"; }); - sm.def("overloaded2", [](py::array_t) { return "double"; }); - sm.def("overloaded2", [](py::array_t>) { return "float complex"; }); - sm.def("overloaded2", [](py::array_t) { return "float"; }); + sm.def("overloaded2", + [](const py::array_t> &) { return "double complex"; }); + sm.def("overloaded2", [](const py::array_t &) { return "double"; }); + sm.def("overloaded2", + [](const py::array_t> &) { return "float complex"; }); + sm.def("overloaded2", [](const py::array_t &) { return "float"; }); // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works. // Only accept the exact types: - sm.def("overloaded3", [](py::array_t) { return "int"; }, py::arg{}.noconvert()); - sm.def("overloaded3", [](py::array_t) { return "double"; }, py::arg{}.noconvert()); + sm.def( + "overloaded3", [](const py::array_t &) { return "int"; }, py::arg{}.noconvert()); + sm.def( + "overloaded3", + [](const py::array_t &) { return "double"; }, + py::arg{}.noconvert()); // Make sure we don't do unsafe coercion (e.g. float to int) when not using forcecast, but // rather that float gets converted via the safe (conversion to double) overload: - sm.def("overloaded4", [](py::array_t) { return "long long"; }); - sm.def("overloaded4", [](py::array_t) { return "double"; }); + sm.def("overloaded4", [](const py::array_t &) { return "long long"; }); + sm.def("overloaded4", [](const py::array_t &) { return "double"; }); // But we do allow conversion to int if forcecast is enabled (but only if no overload matches // without conversion) - sm.def("overloaded5", [](py::array_t) { return "unsigned int"; }); - sm.def("overloaded5", [](py::array_t) { return "double"; }); + sm.def("overloaded5", [](const py::array_t &) { return "unsigned int"; }); + sm.def("overloaded5", [](const py::array_t &) { return "double"; }); // test_greedy_string_overload // Issue 685: ndarray shouldn't go to std::string overload - sm.def("issue685", [](std::string) { return "string"; }); - sm.def("issue685", [](py::array) { return "array"; }); - sm.def("issue685", [](py::object) { return "other"; }); + sm.def("issue685", [](const std::string &) { return "string"; }); + sm.def("issue685", [](const py::array &) { return "array"; }); + sm.def("issue685", [](const py::object &) { return "other"; }); // test_array_unchecked_fixed_dims sm.def("proxy_add2", [](py::array_t a, double v) { @@ -306,7 +315,7 @@ TEST_SUBMODULE(numpy_array, sm) { r(i, j, k) = start++; return a; }); - sm.def("proxy_squared_L2_norm", [](py::array_t a) { + sm.def("proxy_squared_L2_norm", [](const py::array_t &a) { auto r = a.unchecked<1>(); double sumsq = 0; for (py::ssize_t i = 0; i < r.shape(0); i++) @@ -396,45 +405,58 @@ TEST_SUBMODULE(numpy_array, sm) { return a; }); - sm.def("index_using_ellipsis", [](py::array a) { - return a[py::make_tuple(0, py::ellipsis(), 0)]; - }); + sm.def("index_using_ellipsis", + [](const py::array &a) { return a[py::make_tuple(0, py::ellipsis(), 0)]; }); // test_argument_conversions - sm.def("accept_double", - [](py::array_t) {}, - py::arg("a")); - sm.def("accept_double_forcecast", - [](py::array_t) {}, - py::arg("a")); - sm.def("accept_double_c_style", - [](py::array_t) {}, - py::arg("a")); - sm.def("accept_double_c_style_forcecast", - [](py::array_t) {}, - py::arg("a")); - sm.def("accept_double_f_style", - [](py::array_t) {}, - py::arg("a")); - sm.def("accept_double_f_style_forcecast", - [](py::array_t) {}, - py::arg("a")); - sm.def("accept_double_noconvert", - [](py::array_t) {}, - "a"_a.noconvert()); - sm.def("accept_double_forcecast_noconvert", - [](py::array_t) {}, - "a"_a.noconvert()); - sm.def("accept_double_c_style_noconvert", - [](py::array_t) {}, - "a"_a.noconvert()); - sm.def("accept_double_c_style_forcecast_noconvert", - [](py::array_t) {}, - "a"_a.noconvert()); - sm.def("accept_double_f_style_noconvert", - [](py::array_t) {}, - "a"_a.noconvert()); - sm.def("accept_double_f_style_forcecast_noconvert", - [](py::array_t) {}, - "a"_a.noconvert()); + sm.def( + "accept_double", [](const py::array_t &) {}, py::arg("a")); + sm.def( + "accept_double_forcecast", + [](const py::array_t &) {}, + py::arg("a")); + sm.def( + "accept_double_c_style", + [](const py::array_t &) {}, + py::arg("a")); + sm.def( + "accept_double_c_style_forcecast", + [](const py::array_t &) {}, + py::arg("a")); + sm.def( + "accept_double_f_style", + [](const py::array_t &) {}, + py::arg("a")); + sm.def( + "accept_double_f_style_forcecast", + [](const py::array_t &) {}, + py::arg("a")); + sm.def( + "accept_double_noconvert", [](const py::array_t &) {}, "a"_a.noconvert()); + sm.def( + "accept_double_forcecast_noconvert", + [](const py::array_t &) {}, + "a"_a.noconvert()); + sm.def( + "accept_double_c_style_noconvert", + [](const py::array_t &) {}, + "a"_a.noconvert()); + sm.def( + "accept_double_c_style_forcecast_noconvert", + [](const py::array_t &) {}, + "a"_a.noconvert()); + sm.def( + "accept_double_f_style_noconvert", + [](const py::array_t &) {}, + "a"_a.noconvert()); + sm.def( + "accept_double_f_style_forcecast_noconvert", + [](const py::array_t &) {}, + "a"_a.noconvert()); + + // Check that types returns correct npy format descriptor + sm.def("test_fmt_desc_float", [](const py::array_t &) {}); + sm.def("test_fmt_desc_double", [](const py::array_t &) {}); + sm.def("test_fmt_desc_const_float", [](const py::array_t &) {}); + sm.def("test_fmt_desc_const_double", [](const py::array_t &) {}); } diff --git a/thirdparty/pybind11/tests/test_numpy_array.py b/thirdparty/pybind11/tests/test_numpy_array.py index 02f3ecfc0e..548c84bab1 100644 --- a/thirdparty/pybind11/tests/test_numpy_array.py +++ b/thirdparty/pybind11/tests/test_numpy_array.py @@ -482,6 +482,19 @@ def test_index_using_ellipsis(): assert a.shape == (6,) +@pytest.mark.parametrize( + "test_func", + [ + m.test_fmt_desc_float, + m.test_fmt_desc_double, + m.test_fmt_desc_const_float, + m.test_fmt_desc_const_double, + ], +) +def test_format_descriptors_for_floating_point_types(test_func): + assert "numpy.ndarray[numpy.float" in test_func.__doc__ + + @pytest.mark.parametrize("forcecast", [False, True]) @pytest.mark.parametrize("contiguity", [None, "C", "F"]) @pytest.mark.parametrize("noconvert", [False, True]) diff --git a/thirdparty/pybind11/tests/test_numpy_dtypes.cpp b/thirdparty/pybind11/tests/test_numpy_dtypes.cpp index 9dece73ec3..340c972db2 100644 --- a/thirdparty/pybind11/tests/test_numpy_dtypes.cpp +++ b/thirdparty/pybind11/tests/test_numpy_dtypes.cpp @@ -108,9 +108,11 @@ PYBIND11_PACKED(struct EnumStruct { std::ostream& operator<<(std::ostream& os, const StringStruct& v) { os << "a='"; - for (size_t i = 0; i < 3 && v.a[i]; i++) os << v.a[i]; + for (size_t i = 0; i < 3 && (v.a[i] != 0); i++) + os << v.a[i]; os << "',b='"; - for (size_t i = 0; i < 3 && v.b[i]; i++) os << v.b[i]; + for (size_t i = 0; i < 3 && (v.b[i] != 0); i++) + os << v.b[i]; return os << "'"; } @@ -266,10 +268,11 @@ TEST_SUBMODULE(numpy_dtypes, m) { .def_readwrite("uint_", &SimpleStruct::uint_) .def_readwrite("float_", &SimpleStruct::float_) .def_readwrite("ldbl_", &SimpleStruct::ldbl_) - .def("astuple", [](const SimpleStruct& self) { - return py::make_tuple(self.bool_, self.uint_, self.float_, self.ldbl_); - }) - .def_static("fromtuple", [](const py::tuple tup) { + .def("astuple", + [](const SimpleStruct &self) { + return py::make_tuple(self.bool_, self.uint_, self.float_, self.ldbl_); + }) + .def_static("fromtuple", [](const py::tuple &tup) { if (py::len(tup) != 4) { throw py::cast_error("Invalid size"); } diff --git a/thirdparty/pybind11/tests/test_numpy_vectorize.cpp b/thirdparty/pybind11/tests/test_numpy_vectorize.cpp index 274b7558a9..b08a9f7edd 100644 --- a/thirdparty/pybind11/tests/test_numpy_vectorize.cpp +++ b/thirdparty/pybind11/tests/test_numpy_vectorize.cpp @@ -11,6 +11,8 @@ #include "pybind11_tests.h" #include +#include + double my_func(int x, float y, double z) { py::print("my_func(x:int={}, y:float={:.0f}, z:float={:.0f})"_s.format(x, y, z)); return (float) x*y*z; @@ -25,11 +27,10 @@ TEST_SUBMODULE(numpy_vectorize, m) { m.def("vectorized_func", py::vectorize(my_func)); // Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization) - m.def("vectorized_func2", - [](py::array_t x, py::array_t y, float z) { - return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(x, y); - } - ); + m.def("vectorized_func2", [](py::array_t x, py::array_t y, float z) { + return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(std::move(x), + std::move(y)); + }); // Vectorize a complex-valued function m.def("vectorized_func3", py::vectorize( @@ -38,10 +39,14 @@ TEST_SUBMODULE(numpy_vectorize, m) { // test_type_selection // NumPy function which only accepts specific data types - m.def("selective_func", [](py::array_t) { return "Int branch taken."; }); - m.def("selective_func", [](py::array_t) { return "Float branch taken."; }); - m.def("selective_func", [](py::array_t, py::array::c_style>) { return "Complex float branch taken."; }); - + // A lot of these no lints could be replaced with const refs, and probably should at some point. + m.def("selective_func", + [](const py::array_t &) { return "Int branch taken."; }); + m.def("selective_func", + [](const py::array_t &) { return "Float branch taken."; }); + m.def("selective_func", [](const py::array_t, py::array::c_style> &) { + return "Complex float branch taken."; + }); // test_passthrough_arguments // Passthrough test: references and non-pod types should be automatically passed through (in the @@ -53,16 +58,21 @@ TEST_SUBMODULE(numpy_vectorize, m) { py::class_(m, "NonPODClass") .def(py::init()) .def_readwrite("value", &NonPODClass::value); - m.def("vec_passthrough", py::vectorize( - [](double *a, double b, py::array_t c, const int &d, int &e, NonPODClass f, const double g) { - return *a + b + c.at(0) + d + e + f.value + g; - } - )); + m.def("vec_passthrough", + py::vectorize([](const double *a, + double b, + // Changing this broke things + // NOLINTNEXTLINE(performance-unnecessary-value-param) + py::array_t c, + const int &d, + int &e, + NonPODClass f, + const double g) { return *a + b + c.at(0) + d + e + f.value + g; })); // test_method_vectorization struct VectorizeTestClass { VectorizeTestClass(int v) : value{v} {}; - float method(int x, float y) { return y + (float) (x + value); } + float method(int x, float y) const { return y + (float) (x + value); } int value = 0; }; py::class_ vtc(m, "VectorizeTestClass"); @@ -78,16 +88,16 @@ TEST_SUBMODULE(numpy_vectorize, m) { .value("f_trivial", py::detail::broadcast_trivial::f_trivial) .value("c_trivial", py::detail::broadcast_trivial::c_trivial) .value("non_trivial", py::detail::broadcast_trivial::non_trivial); - m.def("vectorized_is_trivial", []( - py::array_t arg1, - py::array_t arg2, - py::array_t arg3 - ) { - py::ssize_t ndim; - std::vector shape; - std::array buffers {{ arg1.request(), arg2.request(), arg3.request() }}; - return py::detail::broadcast(buffers, ndim, shape); - }); + m.def("vectorized_is_trivial", + [](const py::array_t &arg1, + const py::array_t &arg2, + const py::array_t &arg3) { + py::ssize_t ndim = 0; + std::vector shape; + std::array 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/thirdparty/pybind11/tests/test_opaque_types.cpp b/thirdparty/pybind11/tests/test_opaque_types.cpp index 5a23431635..804de6d4ff 100644 --- a/thirdparty/pybind11/tests/test_opaque_types.cpp +++ b/thirdparty/pybind11/tests/test_opaque_types.cpp @@ -44,7 +44,7 @@ TEST_SUBMODULE(opaque_types, m) { m.def("print_opaque_list", [](const StringList &l) { std::string ret = "Opaque list: ["; bool first = true; - for (auto entry : l) { + for (const auto &entry : l) { if (!first) ret += ", "; ret += entry; diff --git a/thirdparty/pybind11/tests/test_operator_overloading.cpp b/thirdparty/pybind11/tests/test_operator_overloading.cpp index 0a27bfd57b..0b6c496cf2 100644 --- a/thirdparty/pybind11/tests/test_operator_overloading.cpp +++ b/thirdparty/pybind11/tests/test_operator_overloading.cpp @@ -16,9 +16,18 @@ class Vector2 { public: Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); } Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); } - Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; } + Vector2(Vector2 &&v) noexcept : x(v.x), y(v.y) { + print_move_created(this); + v.x = v.y = 0; + } Vector2 &operator=(const Vector2 &v) { x = v.x; y = v.y; print_copy_assigned(this); return *this; } - Vector2 &operator=(Vector2 &&v) { x = v.x; y = v.y; v.x = v.y = 0; print_move_assigned(this); return *this; } + Vector2 &operator=(Vector2 &&v) noexcept { + x = v.x; + y = v.y; + v.x = v.y = 0; + print_move_assigned(this); + return *this; + } ~Vector2() { print_destroyed(this); } std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; } @@ -80,8 +89,8 @@ std::string abs(const Vector2&) { return "abs(Vector2)"; } -// MSVC warns about unknown pragmas, and warnings are errors. -#ifndef _MSC_VER +// MSVC & Intel warns about unknown pragmas, and warnings are errors. +#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma GCC diagnostic push // clang 7.0.0 and Apple LLVM 10.0.1 introduce `-Wself-assign-overloaded` to // `-Wall`, which is used here for overloading (e.g. `py::self += py::self `). @@ -221,6 +230,6 @@ TEST_SUBMODULE(operators, m) { .def(py::self == py::self); } -#ifndef _MSC_VER +#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER) #pragma GCC diagnostic pop #endif diff --git a/thirdparty/pybind11/tests/test_pickling.cpp b/thirdparty/pybind11/tests/test_pickling.cpp index 1a48595af6..0d5827315f 100644 --- a/thirdparty/pybind11/tests/test_pickling.cpp +++ b/thirdparty/pybind11/tests/test_pickling.cpp @@ -1,7 +1,9 @@ +// clang-format off /* tests/test_pickling.cpp -- pickle support Copyright (c) 2016 Wenzel Jakob + Copyright (c) 2021 The Pybind Development Team. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. @@ -9,6 +11,58 @@ #include "pybind11_tests.h" +// clang-format on + +#include +#include +#include + +namespace exercise_trampoline { + +struct SimpleBase { + int num = 0; + virtual ~SimpleBase() = default; + + // For compatibility with old clang versions: + SimpleBase() = default; + SimpleBase(const SimpleBase &) = default; +}; + +struct SimpleBaseTrampoline : SimpleBase {}; + +struct SimpleCppDerived : SimpleBase {}; + +void wrap(py::module m) { + py::class_(m, "SimpleBase") + .def(py::init<>()) + .def_readwrite("num", &SimpleBase::num) + .def(py::pickle( + [](const py::object &self) { + py::dict d; + if (py::hasattr(self, "__dict__")) + d = self.attr("__dict__"); + return py::make_tuple(self.attr("num"), d); + }, + [](const py::tuple &t) { + if (t.size() != 2) + throw std::runtime_error("Invalid state!"); + auto cpp_state = std::unique_ptr(new SimpleBaseTrampoline); + cpp_state->num = t[0].cast(); + auto py_state = t[1].cast(); + return std::make_pair(std::move(cpp_state), py_state); + })); + + m.def("make_SimpleCppDerivedAsBase", + []() { return std::unique_ptr(new SimpleCppDerived); }); + m.def("check_dynamic_cast_SimpleCppDerived", [](const SimpleBase *base_ptr) { + return dynamic_cast(base_ptr) != nullptr; + }); +} + +} // namespace exercise_trampoline + +// clang-format off + TEST_SUBMODULE(pickling, m) { // test_roundtrip class Pickleable { @@ -46,17 +100,16 @@ TEST_SUBMODULE(pickling, m) { return py::make_tuple(p.value(), p.extra1(), p.extra2()); }); ignoreOldStyleInitWarnings([&pyPickleable]() { - pyPickleable - .def("__setstate__", [](Pickleable &p, py::tuple t) { - if (t.size() != 3) - throw std::runtime_error("Invalid state!"); - /* Invoke the constructor (need to use in-place version) */ - new (&p) Pickleable(t[0].cast()); + pyPickleable.def("__setstate__", [](Pickleable &p, const py::tuple &t) { + if (t.size() != 3) + throw std::runtime_error("Invalid state!"); + /* Invoke the constructor (need to use in-place version) */ + new (&p) Pickleable(t[0].cast()); - /* Assign any additional state */ - p.setExtra1(t[1].cast()); - p.setExtra2(t[2].cast()); - }); + /* Assign any additional state */ + p.setExtra1(t[1].cast()); + p.setExtra2(t[2].cast()); + }); }); py::class_(m, "PickleableNew") @@ -65,7 +118,7 @@ TEST_SUBMODULE(pickling, m) { [](const PickleableNew &p) { return py::make_tuple(p.value(), p.extra1(), p.extra2()); }, - [](py::tuple t) { + [](const py::tuple &t) { if (t.size() != 3) throw std::runtime_error("Invalid state!"); auto p = PickleableNew(t[0].cast()); @@ -73,8 +126,7 @@ TEST_SUBMODULE(pickling, m) { p.setExtra1(t[1].cast()); p.setExtra2(t[2].cast()); return p; - } - )); + })); #if !defined(PYPY_VERSION) // test_roundtrip_with_dict @@ -92,35 +144,33 @@ TEST_SUBMODULE(pickling, m) { }; py::class_ pyPickleableWithDict(m, "PickleableWithDict", py::dynamic_attr()); - pyPickleableWithDict - .def(py::init()) + pyPickleableWithDict.def(py::init()) .def_readwrite("value", &PickleableWithDict::value) .def_readwrite("extra", &PickleableWithDict::extra) - .def("__getstate__", [](py::object self) { + .def("__getstate__", [](const py::object &self) { /* Also include __dict__ in state */ return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__")); }); ignoreOldStyleInitWarnings([&pyPickleableWithDict]() { - pyPickleableWithDict - .def("__setstate__", [](py::object self, py::tuple t) { - if (t.size() != 3) - throw std::runtime_error("Invalid state!"); - /* Cast and construct */ - auto& p = self.cast(); - new (&p) PickleableWithDict(t[0].cast()); + pyPickleableWithDict.def("__setstate__", [](const py::object &self, const py::tuple &t) { + if (t.size() != 3) + throw std::runtime_error("Invalid state!"); + /* Cast and construct */ + auto &p = self.cast(); + new (&p) PickleableWithDict(t[0].cast()); - /* Assign C++ state */ - p.extra = t[1].cast(); + /* Assign C++ state */ + p.extra = t[1].cast(); - /* Assign Python state */ - self.attr("__dict__") = t[2]; - }); + /* Assign Python state */ + self.attr("__dict__") = t[2]; + }); }); py::class_(m, "PickleableWithDictNew") .def(py::init()) .def(py::pickle( - [](py::object self) { + [](const py::object &self) { return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__")); }, [](const py::tuple &t) { @@ -132,7 +182,8 @@ TEST_SUBMODULE(pickling, m) { auto py_state = t[2].cast(); return std::make_pair(cpp_state, py_state); - } - )); + })); #endif + + exercise_trampoline::wrap(m); } diff --git a/thirdparty/pybind11/tests/test_pickling.py b/thirdparty/pybind11/tests/test_pickling.py index 6b27a73a57..303213068d 100644 --- a/thirdparty/pybind11/tests/test_pickling.py +++ b/thirdparty/pybind11/tests/test_pickling.py @@ -45,3 +45,39 @@ def test_enum_pickle(): data = pickle.dumps(e.EOne, 2) assert e.EOne == pickle.loads(data) + + +# +# exercise_trampoline +# +class SimplePyDerived(m.SimpleBase): + pass + + +def test_roundtrip_simple_py_derived(): + p = SimplePyDerived() + p.num = 202 + p.stored_in_dict = 303 + data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL) + p2 = pickle.loads(data) + assert isinstance(p2, SimplePyDerived) + assert p2.num == 202 + assert p2.stored_in_dict == 303 + + +def test_roundtrip_simple_cpp_derived(): + p = m.make_SimpleCppDerivedAsBase() + assert m.check_dynamic_cast_SimpleCppDerived(p) + p.num = 404 + if not env.PYPY: + # To ensure that this unit test is not accidentally invalidated. + with pytest.raises(AttributeError): + # Mimics the `setstate` C++ implementation. + setattr(p, "__dict__", {}) # noqa: B010 + data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL) + p2 = pickle.loads(data) + assert isinstance(p2, m.SimpleBase) + assert p2.num == 404 + # Issue #3062: pickleable base C++ classes can incur object slicing + # if derived typeid is not registered with pybind11 + assert not m.check_dynamic_cast_SimpleCppDerived(p2) diff --git a/thirdparty/pybind11/tests/test_pytypes.cpp b/thirdparty/pybind11/tests/test_pytypes.cpp index 6921796aa0..d70536d3f0 100644 --- a/thirdparty/pybind11/tests/test_pytypes.cpp +++ b/thirdparty/pybind11/tests/test_pytypes.cpp @@ -7,6 +7,8 @@ BSD-style license that can be found in the LICENSE file. */ +#include + #include "pybind11_tests.h" @@ -27,16 +29,14 @@ TEST_SUBMODULE(pytypes, m) { list.insert(2, "inserted-2"); return list; }); - m.def("print_list", [](py::list list) { + m.def("print_list", [](const py::list &list) { int index = 0; for (auto item : list) py::print("list item {}: {}"_s.format(index++, item)); }); // test_none m.def("get_none", []{return py::none();}); - m.def("print_none", [](py::none none) { - py::print("none: {}"_s.format(none)); - }); + m.def("print_none", [](const py::none &none) { py::print("none: {}"_s.format(none)); }); // test_set m.def("get_set", []() { @@ -46,20 +46,17 @@ TEST_SUBMODULE(pytypes, m) { set.add(std::string("key3")); return set; }); - m.def("print_set", [](py::set set) { + m.def("print_set", [](const py::set &set) { for (auto item : set) py::print("key:", item); }); - m.def("set_contains", [](py::set set, py::object key) { - return set.contains(key); - }); - m.def("set_contains", [](py::set set, const char* key) { - return set.contains(key); - }); + m.def("set_contains", + [](const py::set &set, const py::object &key) { return set.contains(key); }); + m.def("set_contains", [](const py::set &set, const char *key) { return set.contains(key); }); // test_dict m.def("get_dict", []() { return py::dict("key"_a="value"); }); - m.def("print_dict", [](py::dict dict) { + m.def("print_dict", [](const py::dict &dict) { for (auto item : dict) py::print("key: {}, value={}"_s.format(item.first, item.second)); }); @@ -68,12 +65,10 @@ TEST_SUBMODULE(pytypes, m) { auto d2 = py::dict("z"_a=3, **d1); return d2; }); - m.def("dict_contains", [](py::dict dict, py::object val) { - return dict.contains(val); - }); - m.def("dict_contains", [](py::dict dict, const char* val) { - return dict.contains(val); - }); + m.def("dict_contains", + [](const py::dict &dict, py::object val) { return dict.contains(val); }); + m.def("dict_contains", + [](const py::dict &dict, const char *val) { return dict.contains(val); }); // test_str m.def("str_from_string", []() { return py::str(std::string("baz")); }); @@ -81,6 +76,9 @@ TEST_SUBMODULE(pytypes, m) { m.def("str_from_object", [](const py::object& obj) { return py::str(obj); }); m.def("repr_from_object", [](const py::object& obj) { return py::repr(obj); }); m.def("str_from_handle", [](py::handle h) { return py::str(h); }); + m.def("str_from_string_from_str", [](const py::str& obj) { + return py::str(static_cast(obj)); + }); m.def("str_format", []() { auto s1 = "{} + {} = {}"_s.format(1, 2, 3); @@ -137,7 +135,7 @@ TEST_SUBMODULE(pytypes, m) { }); // test_accessors - m.def("accessor_api", [](py::object o) { + m.def("accessor_api", [](const py::object &o) { auto d = py::dict(); d["basic_attr"] = o.attr("basic_attr"); @@ -178,7 +176,7 @@ TEST_SUBMODULE(pytypes, m) { return d; }); - m.def("tuple_accessor", [](py::tuple existing_t) { + m.def("tuple_accessor", [](const py::tuple &existing_t) { try { existing_t[0] = 1; } catch (const py::error_already_set &) { @@ -226,7 +224,7 @@ TEST_SUBMODULE(pytypes, m) { ); }); - m.def("converting_constructors", [](py::dict d) { + m.def("converting_constructors", [](const py::dict &d) { return py::dict( "bytes"_a=py::bytes(d["bytes"]), "bytearray"_a=py::bytearray(d["bytearray"]), @@ -242,7 +240,7 @@ TEST_SUBMODULE(pytypes, m) { ); }); - m.def("cast_functions", [](py::dict d) { + m.def("cast_functions", [](const py::dict &d) { // When converting between Python types, obj.cast() should be the same as T(obj) return py::dict( "bytes"_a=d["bytes"].cast(), @@ -259,23 +257,24 @@ TEST_SUBMODULE(pytypes, m) { ); }); - m.def("convert_to_pybind11_str", [](py::object o) { return py::str(o); }); + m.def("convert_to_pybind11_str", [](const py::object &o) { return py::str(o); }); - m.def("nonconverting_constructor", [](std::string type, py::object value, bool move) -> py::object { - if (type == "bytes") { - return move ? py::bytes(std::move(value)) : py::bytes(value); - } - else if (type == "none") { - return move ? py::none(std::move(value)) : py::none(value); - } - else if (type == "ellipsis") { - return move ? py::ellipsis(std::move(value)) : py::ellipsis(value); - } - else if (type == "type") { - return move ? py::type(std::move(value)) : py::type(value); - } - throw std::runtime_error("Invalid type"); - }); + m.def("nonconverting_constructor", + [](const std::string &type, py::object value, bool move) -> py::object { + if (type == "bytes") { + return move ? py::bytes(std::move(value)) : py::bytes(value); + } + if (type == "none") { + return move ? py::none(std::move(value)) : py::none(value); + } + if (type == "ellipsis") { + return move ? py::ellipsis(std::move(value)) : py::ellipsis(value); + } + if (type == "type") { + return move ? py::type(std::move(value)) : py::type(value); + } + throw std::runtime_error("Invalid type"); + }); m.def("get_implicit_casting", []() { py::dict d; @@ -333,9 +332,9 @@ TEST_SUBMODULE(pytypes, m) { m.def("print_failure", []() { py::print(42, UnregisteredType()); }); - m.def("hash_function", [](py::object obj) { return py::hash(obj); }); + m.def("hash_function", [](py::object obj) { return py::hash(std::move(obj)); }); - m.def("test_number_protocol", [](py::object a, py::object b) { + m.def("test_number_protocol", [](const py::object &a, const py::object &b) { py::list l; l.append(a.equal(b)); l.append(a.not_equal(b)); @@ -355,9 +354,7 @@ TEST_SUBMODULE(pytypes, m) { return l; }); - m.def("test_list_slicing", [](py::list a) { - return a[py::slice(0, -1, 2)]; - }); + m.def("test_list_slicing", [](const py::list &a) { return a[py::slice(0, -1, 2)]; }); // See #2361 m.def("issue2361_str_implicit_copy_none", []() { @@ -369,13 +366,10 @@ TEST_SUBMODULE(pytypes, m) { return is_this_none; }); - m.def("test_memoryview_object", [](py::buffer b) { - return py::memoryview(b); - }); + m.def("test_memoryview_object", [](const py::buffer &b) { return py::memoryview(b); }); - m.def("test_memoryview_buffer_info", [](py::buffer b) { - return py::memoryview(b.request()); - }); + m.def("test_memoryview_buffer_info", + [](const py::buffer &b) { return py::memoryview(b.request()); }); m.def("test_memoryview_from_buffer", [](bool is_unsigned) { static const int16_t si16[] = { 3, 1, 4, 1, 5 }; @@ -383,9 +377,7 @@ TEST_SUBMODULE(pytypes, m) { if (is_unsigned) return py::memoryview::from_buffer( ui16, { 4 }, { sizeof(uint16_t) }); - else - return py::memoryview::from_buffer( - si16, { 5 }, { sizeof(int16_t) }); + return py::memoryview::from_buffer(si16, {5}, {sizeof(int16_t)}); }); m.def("test_memoryview_from_buffer_nativeformat", []() { @@ -425,20 +417,21 @@ TEST_SUBMODULE(pytypes, m) { m.attr("PYBIND11_STR_LEGACY_PERMISSIVE") = true; #endif - m.def("isinstance_pybind11_bytes", [](py::object o) { return py::isinstance(o); }); - m.def("isinstance_pybind11_str", [](py::object o) { return py::isinstance(o); }); + m.def("isinstance_pybind11_bytes", + [](py::object o) { return py::isinstance(std::move(o)); }); + m.def("isinstance_pybind11_str", + [](py::object o) { return py::isinstance(std::move(o)); }); - m.def("pass_to_pybind11_bytes", [](py::bytes b) { return py::len(b); }); - m.def("pass_to_pybind11_str", [](py::str s) { return py::len(s); }); - m.def("pass_to_std_string", [](std::string s) { return s.size(); }); + m.def("pass_to_pybind11_bytes", [](py::bytes b) { return py::len(std::move(b)); }); + m.def("pass_to_pybind11_str", [](py::str s) { return py::len(std::move(s)); }); + m.def("pass_to_std_string", [](const std::string &s) { return s.size(); }); // test_weakref m.def("weakref_from_handle", [](py::handle h) { return py::weakref(h); }); m.def("weakref_from_handle_and_function", - [](py::handle h, py::function f) { return py::weakref(h, f); }); - m.def("weakref_from_object", - [](py::object o) { return py::weakref(o); }); + [](py::handle h, py::function f) { return py::weakref(h, std::move(f)); }); + m.def("weakref_from_object", [](const py::object &o) { return py::weakref(o); }); m.def("weakref_from_object_and_function", - [](py::object o, py::function f) { return py::weakref(o, f); }); + [](py::object o, py::function f) { return py::weakref(std::move(o), std::move(f)); }); } diff --git a/thirdparty/pybind11/tests/test_pytypes.py b/thirdparty/pybind11/tests/test_pytypes.py index f17bf76b77..66d6d30a0c 100644 --- a/thirdparty/pybind11/tests/test_pytypes.py +++ b/thirdparty/pybind11/tests/test_pytypes.py @@ -65,7 +65,7 @@ def test_set(capture, doc): """ ) - assert not m.set_contains(set([]), 42) + assert not m.set_contains(set(), 42) assert m.set_contains({42}, 42) assert m.set_contains({"foo"}, "foo") @@ -133,6 +133,14 @@ def test_str(doc): else: assert m.str_from_handle(malformed_utf8) == "b'\\x80'" + assert m.str_from_string_from_str("this is a str") == "this is a str" + ucs_surrogates_str = u"\udcc3" + if env.PY2: + assert u"\udcc3" == m.str_from_string_from_str(ucs_surrogates_str) + else: + with pytest.raises(UnicodeEncodeError): + m.str_from_string_from_str(ucs_surrogates_str) + def test_bytes(doc): assert m.bytes_from_string().decode() == "foo" @@ -372,10 +380,10 @@ def test_print(capture): with pytest.raises(RuntimeError) as excinfo: m.print_failure() - assert str(excinfo.value) == "make_tuple(): unable to convert " + ( - "argument of type 'UnregisteredType' to Python object" + assert str(excinfo.value) == "Unable to convert call argument " + ( + "'1' of type 'UnregisteredType' to Python object" if debug_enabled - else "arguments to Python object (compile in debug mode for details)" + else "to Python object (compile in debug mode for details)" ) @@ -448,7 +456,7 @@ def test_memoryview(method, args, fmt, expected_view): 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] + view_as_list = [max(ord(c) for c in s) for s in view] assert view_as_list == list(expected_view) diff --git a/thirdparty/pybind11/tests/test_sequences_and_iterators.cpp b/thirdparty/pybind11/tests/test_sequences_and_iterators.cpp index d318052a48..d49fb1f459 100644 --- a/thirdparty/pybind11/tests/test_sequences_and_iterators.cpp +++ b/thirdparty/pybind11/tests/test_sequences_and_iterators.cpp @@ -14,6 +14,7 @@ #include #include +#include template class NonZeroIterator { @@ -80,18 +81,17 @@ TEST_SUBMODULE(sequences_and_iterators, m) { int start,stop,step; int size; }; - py::class_(m,"Sliceable") + py::class_(m, "Sliceable") .def(py::init()) - .def("__getitem__",[](const Sliceable &s, py::slice slice) { - py::ssize_t start, stop, step, slicelength; - if (!slice.compute(s.size, &start, &stop, &step, &slicelength)) - throw py::error_already_set(); - int istart = static_cast(start); - int istop = static_cast(stop); - int istep = static_cast(step); - return std::make_tuple(istart,istop,istep); - }) - ; + .def("__getitem__", [](const Sliceable &s, const py::slice &slice) { + py::ssize_t start = 0, stop = 0, step = 0, slicelength = 0; + if (!slice.compute(s.size, &start, &stop, &step, &slicelength)) + throw py::error_already_set(); + int istart = static_cast(start); + int istop = static_cast(stop); + int istep = static_cast(step); + return std::make_tuple(istart, istop, istep); + }); // test_sequence class Sequence { @@ -111,7 +111,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) { m_data = new float[m_size]; memcpy(m_data, s.m_data, sizeof(float)*m_size); } - Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) { + Sequence(Sequence &&s) noexcept : m_size(s.m_size), m_data(s.m_data) { print_move_created(this); s.m_size = 0; s.m_data = nullptr; @@ -130,7 +130,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) { return *this; } - Sequence &operator=(Sequence &&s) { + Sequence &operator=(Sequence &&s) noexcept { if (&s != this) { delete[] m_data; m_size = s.m_size; @@ -179,43 +179,54 @@ TEST_SUBMODULE(sequences_and_iterators, m) { }; py::class_(m, "Sequence") .def(py::init()) - .def(py::init&>()) + .def(py::init &>()) /// Bare bones interface - .def("__getitem__", [](const Sequence &s, size_t i) { - if (i >= s.size()) throw py::index_error(); - return s[i]; - }) - .def("__setitem__", [](Sequence &s, size_t i, float v) { - if (i >= s.size()) throw py::index_error(); - s[i] = v; - }) + .def("__getitem__", + [](const Sequence &s, size_t i) { + if (i >= s.size()) + throw py::index_error(); + return s[i]; + }) + .def("__setitem__", + [](Sequence &s, size_t i, float v) { + if (i >= s.size()) + throw py::index_error(); + s[i] = v; + }) .def("__len__", &Sequence::size) /// Optional sequence protocol operations - .def("__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); }, - py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */) + .def( + "__iter__", + [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); }, + py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */) .def("__contains__", [](const Sequence &s, float v) { return s.contains(v); }) .def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); }) /// Slicing protocol (optional) - .def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* { - size_t start, stop, step, slicelength; - if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) - throw py::error_already_set(); - auto *seq = new Sequence(slicelength); - for (size_t i = 0; i < slicelength; ++i) { - (*seq)[i] = s[start]; start += step; - } - return seq; - }) - .def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) { - size_t start, stop, step, slicelength; - if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) - throw py::error_already_set(); - if (slicelength != value.size()) - throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); - for (size_t i = 0; i < slicelength; ++i) { - s[start] = value[i]; start += step; - } - }) + .def("__getitem__", + [](const Sequence &s, const py::slice &slice) -> Sequence * { + size_t start = 0, stop = 0, step = 0, slicelength = 0; + if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) + throw py::error_already_set(); + auto *seq = new Sequence(slicelength); + for (size_t i = 0; i < slicelength; ++i) { + (*seq)[i] = s[start]; + start += step; + } + return seq; + }) + .def("__setitem__", + [](Sequence &s, const py::slice &slice, const Sequence &value) { + size_t start = 0, stop = 0, step = 0, slicelength = 0; + if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) + throw py::error_already_set(); + if (slicelength != value.size()) + throw std::runtime_error( + "Left and right hand size of slice assignment have different sizes!"); + for (size_t i = 0; i < slicelength; ++i) { + s[start] = value[i]; + start += step; + } + }) /// Comparisons .def(py::self == py::self) .def(py::self != py::self) @@ -231,8 +242,8 @@ TEST_SUBMODULE(sequences_and_iterators, m) { StringMap(std::unordered_map init) : map(std::move(init)) {} - void set(std::string key, std::string val) { map[key] = val; } - std::string get(std::string key) const { return map.at(key); } + void set(const std::string &key, std::string val) { map[key] = std::move(val); } + std::string get(const std::string &key) const { return map.at(key); } size_t size() const { return map.size(); } private: std::unordered_map map; @@ -243,19 +254,24 @@ TEST_SUBMODULE(sequences_and_iterators, m) { py::class_(m, "StringMap") .def(py::init<>()) .def(py::init>()) - .def("__getitem__", [](const StringMap &map, std::string key) { - try { return map.get(key); } - catch (const std::out_of_range&) { - throw py::key_error("key '" + key + "' does not exist"); - } - }) + .def("__getitem__", + [](const StringMap &map, const std::string &key) { + try { + return map.get(key); + } catch (const std::out_of_range &) { + throw py::key_error("key '" + key + "' does not exist"); + } + }) .def("__setitem__", &StringMap::set) .def("__len__", &StringMap::size) - .def("__iter__", [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); }, - py::keep_alive<0, 1>()) - .def("items", [](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); }, - py::keep_alive<0, 1>()) - ; + .def( + "__iter__", + [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); }, + py::keep_alive<0, 1>()) + .def( + "items", + [](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); }, + py::keep_alive<0, 1>()); // test_generalized_iterators class IntPairs { @@ -304,7 +320,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) { #endif // test_python_iterator_in_cpp - m.def("object_to_list", [](py::object o) { + m.def("object_to_list", [](const py::object &o) { auto l = py::list(); for (auto item : o) { l.append(item); @@ -322,22 +338,22 @@ TEST_SUBMODULE(sequences_and_iterators, m) { }); // test_sequence_length: check that Python sequences can be converted to py::sequence. - m.def("sequence_length", [](py::sequence seq) { return seq.size(); }); + m.def("sequence_length", [](const py::sequence &seq) { return seq.size(); }); // Make sure that py::iterator works with std algorithms - m.def("count_none", [](py::object o) { + m.def("count_none", [](const py::object &o) { return std::count_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); }); - m.def("find_none", [](py::object o) { + m.def("find_none", [](const py::object &o) { auto it = std::find_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); return it->is_none(); }); - m.def("count_nonzeros", [](py::dict d) { - return std::count_if(d.begin(), d.end(), [](std::pair p) { - return p.second.cast() != 0; - }); + m.def("count_nonzeros", [](const py::dict &d) { + return std::count_if(d.begin(), d.end(), [](std::pair p) { + return p.second.cast() != 0; + }); }); m.def("tuple_iterator", &test_random_access_iterator); diff --git a/thirdparty/pybind11/tests/test_sequences_and_iterators.py b/thirdparty/pybind11/tests/test_sequences_and_iterators.py index c3b608c436..70fb697f95 100644 --- a/thirdparty/pybind11/tests/test_sequences_and_iterators.py +++ b/thirdparty/pybind11/tests/test_sequences_and_iterators.py @@ -104,7 +104,7 @@ def test_sequence(): def test_sequence_length(): - """#2076: Exception raised by len(arg) should be propagated """ + """#2076: Exception raised by len(arg) should be propagated""" class BadLen(RuntimeError): pass @@ -187,7 +187,7 @@ def test_iterator_passthrough(): def test_iterator_rvp(): - """#388: Can't make iterators via make_iterator() with different r/v policies """ + """#388: Can't make iterators via make_iterator() with different r/v policies""" import pybind11_tests.sequences_and_iterators as m assert list(m.make_iterator_1()) == [1, 2, 3] diff --git a/thirdparty/pybind11/tests/test_smart_ptr.cpp b/thirdparty/pybind11/tests/test_smart_ptr.cpp index e0af249790..57b2d894e2 100644 --- a/thirdparty/pybind11/tests/test_smart_ptr.cpp +++ b/thirdparty/pybind11/tests/test_smart_ptr.cpp @@ -24,7 +24,7 @@ template class huge_unique_ptr { std::unique_ptr ptr; uint64_t padding[10]; public: - huge_unique_ptr(T *p) : ptr(p) {}; + huge_unique_ptr(T *p) : ptr(p) {} T *get() { return ptr.get(); } }; @@ -101,7 +101,7 @@ private: // test_unique_nodelete // Object with a private destructor class MyObject4; -static std::unordered_set myobject4_instances; +std::unordered_set myobject4_instances; class MyObject4 { public: MyObject4(int value) : value{value} { @@ -127,7 +127,7 @@ private: // Object with std::unique_ptr where D is not matching the base class // Object with a protected destructor class MyObject4a; -static std::unordered_set myobject4a_instances; +std::unordered_set myobject4a_instances; class MyObject4a { public: MyObject4a(int i) { @@ -170,7 +170,7 @@ struct SharedPtrRef { struct A { A() { print_created(this); } A(const A &) { print_copy_created(this); } - A(A &&) { print_move_created(this); } + A(A &&) noexcept { print_move_created(this); } ~A() { print_destroyed(this); } }; @@ -183,7 +183,7 @@ struct SharedFromThisRef { struct B : std::enable_shared_from_this { B() { print_created(this); } B(const B &) : std::enable_shared_from_this() { print_copy_created(this); } - B(B &&) : std::enable_shared_from_this() { print_move_created(this); } + B(B &&) noexcept : std::enable_shared_from_this() { print_move_created(this); } ~B() { print_destroyed(this); } }; @@ -209,7 +209,9 @@ struct C { struct TypeForHolderWithAddressOf { TypeForHolderWithAddressOf() { print_created(this); } TypeForHolderWithAddressOf(const TypeForHolderWithAddressOf &) { print_copy_created(this); } - TypeForHolderWithAddressOf(TypeForHolderWithAddressOf &&) { print_move_created(this); } + TypeForHolderWithAddressOf(TypeForHolderWithAddressOf &&) noexcept { + print_move_created(this); + } ~TypeForHolderWithAddressOf() { print_destroyed(this); } std::string toString() const { return "TypeForHolderWithAddressOf[" + std::to_string(value) + "]"; @@ -240,12 +242,12 @@ struct ElementBase { struct ElementA : ElementBase { ElementA(int v) : v(v) { } - int value() { return v; } + int value() const { return v; } int v; }; struct ElementList { - void add(std::shared_ptr e) { l.push_back(e); } + void add(const std::shared_ptr &e) { l.push_back(e); } std::vector> l; }; @@ -308,6 +310,7 @@ TEST_SUBMODULE(smart_ptr, m) { m.def("make_myobject2_1", []() { return new MyObject2(6); }); m.def("make_myobject2_2", []() { return std::make_shared(7); }); m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); }); + // NOLINTNEXTLINE(performance-unnecessary-value-param) m.def("print_myobject2_2", [](std::shared_ptr obj) { py::print(obj->toString()); }); m.def("print_myobject2_3", [](const std::shared_ptr &obj) { py::print(obj->toString()); }); m.def("print_myobject2_4", [](const std::shared_ptr *obj) { py::print((*obj)->toString()); }); @@ -317,6 +320,7 @@ TEST_SUBMODULE(smart_ptr, m) { m.def("make_myobject3_1", []() { return new MyObject3(8); }); m.def("make_myobject3_2", []() { return std::make_shared(9); }); m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); }); + // NOLINTNEXTLINE(performance-unnecessary-value-param) m.def("print_myobject3_2", [](std::shared_ptr obj) { py::print(obj->toString()); }); m.def("print_myobject3_3", [](const std::shared_ptr &obj) { py::print(obj->toString()); }); m.def("print_myobject3_4", [](const std::shared_ptr *obj) { py::print((*obj)->toString()); }); @@ -358,12 +362,15 @@ TEST_SUBMODULE(smart_ptr, m) { py::class_>(m, "SharedPtrRef") .def(py::init<>()) .def_readonly("ref", &SharedPtrRef::value) - .def_property_readonly("copy", [](const SharedPtrRef &s) { return s.value; }, - py::return_value_policy::copy) + .def_property_readonly( + "copy", [](const SharedPtrRef &s) { return s.value; }, py::return_value_policy::copy) .def_readonly("holder_ref", &SharedPtrRef::shared) - .def_property_readonly("holder_copy", [](const SharedPtrRef &s) { return s.shared; }, - py::return_value_policy::copy) + .def_property_readonly( + "holder_copy", + [](const SharedPtrRef &s) { return s.shared; }, + py::return_value_policy::copy) .def("set_ref", [](SharedPtrRef &, const A &) { return true; }) + // NOLINTNEXTLINE(performance-unnecessary-value-param) .def("set_holder", [](SharedPtrRef &, std::shared_ptr) { return true; }); // test_shared_ptr_from_this_and_references @@ -372,13 +379,19 @@ TEST_SUBMODULE(smart_ptr, m) { py::class_>(m, "SharedFromThisRef") .def(py::init<>()) .def_readonly("bad_wp", &SharedFromThisRef::value) - .def_property_readonly("ref", [](const SharedFromThisRef &s) -> const B & { return *s.shared; }) - .def_property_readonly("copy", [](const SharedFromThisRef &s) { return s.value; }, - py::return_value_policy::copy) + .def_property_readonly("ref", + [](const SharedFromThisRef &s) -> const B & { return *s.shared; }) + .def_property_readonly( + "copy", + [](const SharedFromThisRef &s) { return s.value; }, + py::return_value_policy::copy) .def_readonly("holder_ref", &SharedFromThisRef::shared) - .def_property_readonly("holder_copy", [](const SharedFromThisRef &s) { return s.shared; }, - py::return_value_policy::copy) + .def_property_readonly( + "holder_copy", + [](const SharedFromThisRef &s) { return s.shared; }, + py::return_value_policy::copy) .def("set_ref", [](SharedFromThisRef &, const B &) { return true; }) + // NOLINTNEXTLINE(performance-unnecessary-value-param) .def("set_holder", [](SharedFromThisRef &, std::shared_ptr) { return true; }); // Issue #865: shared_from_this doesn't work with virtual inheritance @@ -396,10 +409,14 @@ TEST_SUBMODULE(smart_ptr, m) { py::class_(m, "TypeForHolderWithAddressOf") .def_static("make", []() { return HolderWithAddressOf(new TypeForHolderWithAddressOf); }) .def("get", [](const HolderWithAddressOf &self) { return self.get(); }) - .def("print_object_1", [](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); }) + .def("print_object_1", + [](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); }) + // NOLINTNEXTLINE(performance-unnecessary-value-param) .def("print_object_2", [](HolderWithAddressOf obj) { py::print(obj.get()->toString()); }) - .def("print_object_3", [](const HolderWithAddressOf &obj) { py::print(obj.get()->toString()); }) - .def("print_object_4", [](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); }); + .def("print_object_3", + [](const HolderWithAddressOf &obj) { py::print(obj.get()->toString()); }) + .def("print_object_4", + [](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); }); // test_move_only_holder_with_addressof_operator using MoveOnlyHolderWithAddressOf = unique_ptr_with_addressof_operator; @@ -411,6 +428,7 @@ TEST_SUBMODULE(smart_ptr, m) { // test_smart_ptr_from_default py::class_>(m, "HeldByDefaultHolder") .def(py::init<>()) + // NOLINTNEXTLINE(performance-unnecessary-value-param) .def_static("load_shared_ptr", [](std::shared_ptr) {}); // test_shared_ptr_gc diff --git a/thirdparty/pybind11/tests/test_stl.cpp b/thirdparty/pybind11/tests/test_stl.cpp index 0590162770..23e2c07b32 100644 --- a/thirdparty/pybind11/tests/test_stl.cpp +++ b/thirdparty/pybind11/tests/test_stl.cpp @@ -11,6 +11,11 @@ #include "constructor_stats.h" #include +#ifndef PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL +#define PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL +#endif +#include + #include #include @@ -97,7 +102,7 @@ TEST_SUBMODULE(stl, m) { // test_set m.def("cast_set", []() { return std::set{"key1", "key2"}; }); m.def("load_set", [](const std::set &set) { - return set.count("key1") && set.count("key2") && set.count("key3"); + return (set.count("key1") != 0u) && (set.count("key2") != 0u) && (set.count("key3") != 0u); }); // test_recursive_casting @@ -191,9 +196,7 @@ TEST_SUBMODULE(stl, m) { m.def("double_or_zero", [](const opt_int& x) -> int { return x.value_or(0) * 2; }); - m.def("half_or_none", [](int x) -> opt_int { - return x ? opt_int(x / 2) : opt_int(); - }); + m.def("half_or_none", [](int x) -> opt_int { return x != 0 ? opt_int(x / 2) : opt_int(); }); m.def("test_nullopt", [](opt_int x) { return x.value_or(42); }, py::arg_v("x", std::nullopt, "None")); @@ -202,7 +205,7 @@ TEST_SUBMODULE(stl, m) { }, py::arg_v("x", std::nullopt, "None")); m.def("nodefer_none_optional", [](std::optional) { return true; }); - m.def("nodefer_none_optional", [](py::none) { return false; }); + m.def("nodefer_none_optional", [](const py::none &) { return false; }); using opt_holder = OptionalHolder; py::class_(m, "OptionalHolder", "Class with optional member") @@ -237,6 +240,12 @@ TEST_SUBMODULE(stl, m) { .def("member_initialized", &opt_exp_holder::member_initialized); #endif +#ifdef PYBIND11_HAS_FILESYSTEM + // test_fs_path + m.attr("has_filesystem") = true; + m.def("parent_path", [](const std::filesystem::path& p) { return p.parent_path(); }); +#endif + #ifdef PYBIND11_HAS_VARIANT static_assert(std::is_same::value, "visitor::result_type is required by boost::variant in C++11 mode"); @@ -245,13 +254,13 @@ TEST_SUBMODULE(stl, m) { using result_type = const char *; result_type operator()(int) { return "int"; } - result_type operator()(std::string) { return "std::string"; } + result_type operator()(const std::string &) { return "std::string"; } result_type operator()(double) { return "double"; } result_type operator()(std::nullptr_t) { return "std::nullptr_t"; } }; // test_variant - m.def("load_variant", [](variant v) { + m.def("load_variant", [](const variant &v) { return py::detail::visit_helper::call(visitor(), v); }); m.def("load_variant_2pass", [](variant v) { @@ -287,9 +296,11 @@ TEST_SUBMODULE(stl, m) { m.def("stl_pass_by_pointer", [](std::vector* v) { return *v; }, "v"_a=nullptr); // #1258: pybind11/stl.h converts string to vector - m.def("func_with_string_or_vector_string_arg_overload", [](std::vector) { return 1; }); - m.def("func_with_string_or_vector_string_arg_overload", [](std::list) { return 2; }); - m.def("func_with_string_or_vector_string_arg_overload", [](std::string) { return 3; }); + m.def("func_with_string_or_vector_string_arg_overload", + [](const std::vector &) { return 1; }); + m.def("func_with_string_or_vector_string_arg_overload", + [](const std::list &) { return 2; }); + m.def("func_with_string_or_vector_string_arg_overload", [](const std::string &) { return 3; }); class Placeholder { public: @@ -321,4 +332,10 @@ TEST_SUBMODULE(stl, m) { py::class_(m, "Issue1561Outer") .def(py::init<>()) .def_readwrite("list", &Issue1561Outer::list); + + m.def( + "return_vector_bool_raw_ptr", + []() { return new std::vector(4513); }, + // Without explicitly specifying `take_ownership`, this function leaks. + py::return_value_policy::take_ownership); } diff --git a/thirdparty/pybind11/tests/test_stl.py b/thirdparty/pybind11/tests/test_stl.py index 330017544d..6f08459043 100644 --- a/thirdparty/pybind11/tests/test_stl.py +++ b/thirdparty/pybind11/tests/test_stl.py @@ -162,6 +162,25 @@ def test_exp_optional(): assert holder.member_initialized() +@pytest.mark.skipif(not hasattr(m, "has_filesystem"), reason="no ") +def test_fs_path(): + from pathlib import Path + + class PseudoStrPath: + def __fspath__(self): + return "foo/bar" + + class PseudoBytesPath: + def __fspath__(self): + return b"foo/bar" + + assert m.parent_path(Path("foo/bar")) == Path("foo") + assert m.parent_path("foo/bar") == Path("foo") + assert m.parent_path(b"foo/bar") == Path("foo") + assert m.parent_path(PseudoStrPath()) == Path("foo") + assert m.parent_path(PseudoBytesPath()) == Path("foo") + + @pytest.mark.skipif(not hasattr(m, "load_variant"), reason="no ") def test_variant(doc): assert m.load_variant(1) == "int" @@ -259,8 +278,15 @@ def test_array_cast_sequence(): def test_issue_1561(): - """ check fix for issue #1561 """ + """check fix for issue #1561""" bar = m.Issue1561Outer() bar.list = [m.Issue1561Inner("bar")] bar.list assert bar.list[0].data == "bar" + + +def test_return_vector_bool_raw_ptr(): + # Add `while True:` for manual leak checking. + v = m.return_vector_bool_raw_ptr() + assert isinstance(v, list) + assert len(v) == 4513 diff --git a/thirdparty/pybind11/tests/test_stl_binders.cpp b/thirdparty/pybind11/tests/test_stl_binders.cpp index c791477e3e..22847eb7a1 100644 --- a/thirdparty/pybind11/tests/test_stl_binders.cpp +++ b/thirdparty/pybind11/tests/test_stl_binders.cpp @@ -125,5 +125,7 @@ TEST_SUBMODULE(stl_binders, m) { PYBIND11_NUMPY_DTYPE(VStruct, w, x, y, z); py::class_(m, "VStruct").def_readwrite("x", &VStruct::x); py::bind_vector>(m, "VectorStruct", py::buffer_protocol()); - m.def("get_vectorstruct", [] {return std::vector {{0, 5, 3.0, 1}, {1, 30, -1e4, 0}};}); + m.def("get_vectorstruct", [] { + return std::vector{{false, 5, 3.0, true}, {true, 30, -1e4, false}}; + }); } diff --git a/thirdparty/pybind11/tests/test_virtual_functions.cpp b/thirdparty/pybind11/tests/test_virtual_functions.cpp index 685d64a7ca..5280af8eb6 100644 --- a/thirdparty/pybind11/tests/test_virtual_functions.cpp +++ b/thirdparty/pybind11/tests/test_virtual_functions.cpp @@ -17,7 +17,10 @@ class ExampleVirt { public: ExampleVirt(int state) : state(state) { print_created(this, state); } ExampleVirt(const ExampleVirt &e) : state(e.state) { print_copy_created(this); } - ExampleVirt(ExampleVirt &&e) : state(e.state) { print_move_created(this); e.state = 0; } + ExampleVirt(ExampleVirt &&e) noexcept : state(e.state) { + print_move_created(this); + e.state = 0; + } virtual ~ExampleVirt() { print_destroyed(this); } virtual int run(int value) { @@ -100,13 +103,18 @@ public: class NonCopyable { public: NonCopyable(int a, int b) : value{new int(a*b)} { print_created(this, a, b); } - NonCopyable(NonCopyable &&o) { value = std::move(o.value); print_move_created(this); } + NonCopyable(NonCopyable &&o) noexcept { + value = std::move(o.value); + print_move_created(this); + } NonCopyable(const NonCopyable &) = delete; NonCopyable() = delete; void operator=(const NonCopyable &) = delete; void operator=(NonCopyable &&) = delete; std::string get_value() const { - if (value) return std::to_string(*value); else return "(null)"; + if (value) + return std::to_string(*value); + return "(null)"; } ~NonCopyable() { print_destroyed(this); } @@ -120,7 +128,10 @@ class Movable { public: Movable(int a, int b) : value{a+b} { print_created(this, a, b); } Movable(const Movable &m) { value = m.value; print_copy_created(this); } - Movable(Movable &&m) { value = std::move(m.value); print_move_created(this); } + Movable(Movable &&m) noexcept { + value = m.value; + print_move_created(this); + } std::string get_value() const { return std::to_string(value); } ~Movable() { print_destroyed(this); } private: diff --git a/thirdparty/pybind11/tests/valgrind-numpy-scipy.supp b/thirdparty/pybind11/tests/valgrind-numpy-scipy.supp index e8ff680dd3..16db302c17 100644 --- a/thirdparty/pybind11/tests/valgrind-numpy-scipy.supp +++ b/thirdparty/pybind11/tests/valgrind-numpy-scipy.supp @@ -2,7 +2,7 @@ # # On updating a dependency, to get a list of "default" leaks in e.g. NumPy, run # `PYTHONMALLOC=malloc valgrind --leak-check=full --show-leak-kinds=definite,indirect python3.9-dbg -c "import numpy"` -# To use theses suppression files, add e.g. `--suppressions=valgrind-numpy-scipy.supp` +# To use these suppression files, add e.g. `--suppressions=valgrind-numpy-scipy.supp` { Leaks when importing NumPy @@ -111,7 +111,7 @@ fun:_Znwm fun:PyInit_pypocketfft fun:_PyImport_LoadDynamicModuleWithSpec - fun:_imp_create_dynamic_impl.constprop.3 + fun:_imp_create_dynamic_impl* fun:_imp_create_dynamic fun:cfunction_vectorcall_FASTCALL fun:PyVectorcall_Call diff --git a/thirdparty/pybind11/tools/FindPythonLibsNew.cmake b/thirdparty/pybind11/tools/FindPythonLibsNew.cmake index 4dab195a9e..3605aebcf3 100644 --- a/thirdparty/pybind11/tools/FindPythonLibsNew.cmake +++ b/thirdparty/pybind11/tools/FindPythonLibsNew.cmake @@ -190,19 +190,6 @@ if(CMAKE_HOST_WIN32) set(PYTHON_LIBRARY "${_PYTHON_ROOT}/libs/python${PYTHON_LIBRARY_SUFFIX}.lib") endif() - if(DEFINED VCPKG_TOOLCHAIN) - unset(PYTHON_LIBRARY) - find_library( - PYTHON_LIBRARY - NAMES "python${PYTHON_LIBRARY_SUFFIX}" - NO_SYSTEM_ENVIRONMENT_PATH) - - find_library(PYTHON_DEBUG_LIBRARY - NAMES python${PYTHON_LIBRARY_SUFFIX}_d - NO_SYSTEM_ENVIRONMENT_PATH - ) - endif() - # if we are in MSYS & MINGW, and we didn't find windows python lib, look for system python lib if(DEFINED ENV{MSYSTEM} AND MINGW @@ -246,7 +233,7 @@ else() endif() endif() -mark_as_advanced(PYTHON_DEBUG_LIBRARY PYTHON_LIBRARY PYTHON_INCLUDE_DIR) +mark_as_advanced(PYTHON_LIBRARY PYTHON_INCLUDE_DIR) # We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the # cache entries because they are meant to specify the location of a single @@ -259,10 +246,6 @@ if(NOT PYTHON_DEBUG_LIBRARY) endif() set(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}") -set(PYTHON_LIBRARY_DEBUG "${PYTHON_DEBUG_LIBRARY}") -set(PYTHON_LIBRARY_RELEASE "${PYTHON_LIBRARY}") -select_library_configurations(PYTHON) - find_package_message(PYTHON "Found PythonLibs: ${PYTHON_LIBRARY}" "${PYTHON_EXECUTABLE}${PYTHON_VERSION_STRING}") diff --git a/thirdparty/pybind11/tools/check-style.sh b/thirdparty/pybind11/tools/check-style.sh index f7af2a4169..6d832523a7 100755 --- a/thirdparty/pybind11/tools/check-style.sh +++ b/thirdparty/pybind11/tools/check-style.sh @@ -16,11 +16,11 @@ check_style_errors=0 IFS=$'\n' -found="$(grep '\<\(if\|for\|while\|catch\)(\|){' $@ -rn --color=always)" +found="$(grep '\<\(if\|for\|while\|catch\)(\|){' "$@" -rn --color=always)" if [ -n "$found" ]; then echo -e '\033[31;01mError: found the following coding style problems:\033[0m' check_style_errors=1 - echo "$found" | sed -e 's/^/ /' + echo "${found//^/ /}" fi found="$(awk ' @@ -34,7 +34,7 @@ last && /^\s*{/ { last="" } { last = /(if|for|while|catch|switch)\s*\(.*\)\s*$/ ? $0 : "" } -' $(find include -type f) $@)" +' "$(find include -type f)" "$@")" if [ -n "$found" ]; then check_style_errors=1 echo -e '\033[31;01mError: braces should occur on the same line as the if/while/.. statement. Found issues in the following files:\033[0m' diff --git a/thirdparty/pybind11/tools/make_changelog.py b/thirdparty/pybind11/tools/make_changelog.py index 609ce2f194..4e8fbf5b00 100755 --- a/thirdparty/pybind11/tools/make_changelog.py +++ b/thirdparty/pybind11/tools/make_changelog.py @@ -27,7 +27,10 @@ print() api = ghapi.all.GhApi(owner="pybind", repo="pybind11") -issues = api.issues.list_for_repo(labels="needs changelog", state="closed") +issues_pages = ghapi.page.paged( + api.issues.list_for_repo, labels="needs changelog", state="closed" +) +issues = (issue for page in issues_pages for issue in page) missing = [] for issue in issues: @@ -41,7 +44,7 @@ for issue in issues: msg += f"\n `#{issue.number} <{issue.html_url}>`_" - print(Syntax(msg, "rst", theme="ansi_light")) + print(Syntax(msg, "rst", theme="ansi_light", word_wrap=True)) print() else: diff --git a/thirdparty/pybind11/tools/pybind11Common.cmake b/thirdparty/pybind11/tools/pybind11Common.cmake index 57e42536e1..7afb0d0b1a 100644 --- a/thirdparty/pybind11/tools/pybind11Common.cmake +++ b/thirdparty/pybind11/tools/pybind11Common.cmake @@ -302,13 +302,18 @@ function(_pybind11_return_if_cxx_and_linker_flags_work result cxxflags linkerfla endfunction() function(_pybind11_generate_lto target prefer_thin_lto) + if(MINGW) + message(STATUS "${target} disabled (problems with undefined symbols for MinGW for now)") + return() + endif() + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") set(cxx_append "") set(linker_append "") if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT APPLE) # Clang Gold plugin does not support -Os; append -O3 to MinSizeRel builds to override it set(linker_append ";$<$:-O3>") - elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND NOT MINGW) set(cxx_append ";-fno-fat-lto-objects") endif() diff --git a/thirdparty/pybind11/tools/pybind11Config.cmake.in b/thirdparty/pybind11/tools/pybind11Config.cmake.in index 9921aeb355..73ec104a0e 100644 --- a/thirdparty/pybind11/tools/pybind11Config.cmake.in +++ b/thirdparty/pybind11/tools/pybind11Config.cmake.in @@ -139,7 +139,7 @@ This module defines the following commands to assist with creating Python module pybind11_add_module( [STATIC|SHARED|MODULE] - [THIN_LTO] [OPT_SIZE] [NO_EXTRAS] [WITHOUT_SOBAI] + [THIN_LTO] [OPT_SIZE] [NO_EXTRAS] [WITHOUT_SOABI] ... ) @@ -201,7 +201,8 @@ Using ``find_package`` with version info is not recommended except for release v @PACKAGE_INIT@ # Location of pybind11/pybind11.h -set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@") +# This will be relative unless explicitly set as absolute +set(pybind11_INCLUDE_DIR "@pybind11_INCLUDEDIR@") set(pybind11_LIBRARY "") set(pybind11_DEFINITIONS USING_pybind11) diff --git a/thirdparty/pybind11/tools/pybind11NewTools.cmake b/thirdparty/pybind11/tools/pybind11NewTools.cmake index 18da8be170..a20803bc74 100644 --- a/thirdparty/pybind11/tools/pybind11NewTools.cmake +++ b/thirdparty/pybind11/tools/pybind11NewTools.cmake @@ -230,7 +230,7 @@ function(pybind11_add_module target_name) endif() # If we don't pass a WITH_SOABI or WITHOUT_SOABI, use our own default handling of extensions - if(NOT ARG_WITHOUT_SOABI OR NOT "WITH_SOABI" IN_LIST ARG_UNPARSED_ARGUMENTS) + if(NOT ARG_WITHOUT_SOABI AND NOT "WITH_SOABI" IN_LIST ARG_UNPARSED_ARGUMENTS) pybind11_extension(${target_name}) endif() diff --git a/thirdparty/pybind11/tools/pybind11Tools.cmake b/thirdparty/pybind11/tools/pybind11Tools.cmake index 8de92c624d..3231353998 100644 --- a/thirdparty/pybind11/tools/pybind11Tools.cmake +++ b/thirdparty/pybind11/tools/pybind11Tools.cmake @@ -120,11 +120,8 @@ set_property( TARGET pybind11::module APPEND PROPERTY - INTERFACE_LINK_LIBRARIES pybind11::python_link_helper) - -if(WIN32) - target_link_libraries(pybind11::module INTERFACE ${PYTHON_LIBRARIES}) -endif() + INTERFACE_LINK_LIBRARIES pybind11::python_link_helper + "$<$,$>:$>") if(PYTHON_VERSION VERSION_LESS 3) set_property( @@ -133,13 +130,10 @@ if(PYTHON_VERSION VERSION_LESS 3) PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python2_no_register) endif() -# KiCad Workaround, this ends tying release libraries into debug builds which doesn't end well set_property( - TARGET pybind11::embed - APPEND - PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11) - -target_link_libraries(pybind11::embed INTERFACE ${PYTHON_LIBRARIES}) + TARGET pybind11::embed + APPEND + PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11 $) function(pybind11_extension name) # The prefix and extension are provided by FindPythonLibsNew.cmake diff --git a/thirdparty/pybind11/tools/setup_global.py.in b/thirdparty/pybind11/tools/setup_global.py.in index 4cf040b2d8..8b7e538714 100644 --- a/thirdparty/pybind11/tools/setup_global.py.in +++ b/thirdparty/pybind11/tools/setup_global.py.in @@ -33,8 +33,9 @@ class InstallHeadersNested(install_headers): main_headers = glob.glob("pybind11/include/pybind11/*.h") detail_headers = glob.glob("pybind11/include/pybind11/detail/*.h") +stl_headers = glob.glob("pybind11/include/pybind11/stl/*.h") cmake_files = glob.glob("pybind11/share/cmake/pybind11/*.cmake") -headers = main_headers + detail_headers +headers = main_headers + detail_headers + stl_headers cmdclass = {"install_headers": InstallHeadersNested} $extra_cmd @@ -58,6 +59,7 @@ setup( (base + "share/cmake/pybind11", cmake_files), (base + "include/pybind11", main_headers), (base + "include/pybind11/detail", detail_headers), + (base + "include/pybind11/stl", stl_headers), ], cmdclass=cmdclass, ) diff --git a/thirdparty/pybind11/tools/setup_main.py.in b/thirdparty/pybind11/tools/setup_main.py.in index 2231a08fdc..533a75ae71 100644 --- a/thirdparty/pybind11/tools/setup_main.py.in +++ b/thirdparty/pybind11/tools/setup_main.py.in @@ -16,12 +16,14 @@ setup( "pybind11", "pybind11.include.pybind11", "pybind11.include.pybind11.detail", + "pybind11.include.pybind11.stl", "pybind11.share.cmake.pybind11", ], package_data={ "pybind11": ["py.typed", "*.pyi"], "pybind11.include.pybind11": ["*.h"], "pybind11.include.pybind11.detail": ["*.h"], + "pybind11.include.pybind11.stl": ["*.h"], "pybind11.share.cmake.pybind11": ["*.cmake"], }, extras_require={ @@ -30,6 +32,9 @@ setup( entry_points={ "console_scripts": [ "pybind11-config = pybind11.__main__:main", + ], + "pipx.run": [ + "pybind11 = pybind11.__main__:main", ] }, cmdclass=cmdclass