Update to pybind11 v2.7.1
This commit is contained in:
parent
aeb61d5984
commit
84c7cc6c21
|
@ -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})
|
||||
|
|
|
@ -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<T>`` | 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).
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 <https://stackoverflow.com/questions/19496643/using-clang-fvisibility-hidden-and-typeinfo-and-type-erasure/28827430>`_
|
||||
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 <https://gcc.gnu.org/wiki/Visibility>`_.
|
||||
|
||||
.. _handling_python_exceptions_cpp:
|
||||
|
||||
Handling exceptions from Python in C++
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
===========
|
||||
|
|
|
@ -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 <https://github.com/pybind/pybind11/pull/2982>`_ and
|
||||
`PR #2995 <https://github.com/pybind/pybind11/pull/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
|
||||
|
|
|
@ -6,8 +6,86 @@ Changelog
|
|||
Starting with version 1.8.0, pybind11 releases use a `semantic versioning
|
||||
<http://semver.org>`_ 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 <https://github.com/pybind/pybind11/pull/2650>`_
|
||||
|
||||
v2.7.1 (Aug 3, 2021)
|
||||
---------------------
|
||||
|
||||
Minor missing functionality added:
|
||||
|
||||
* Allow Python builtins to be used as callbacks in CPython.
|
||||
`#1413 <https://github.com/pybind/pybind11/pull/1413>`_
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* Fix regression in CMake Python package config: improper use of absolute path.
|
||||
`#3144 <https://github.com/pybind/pybind11/pull/3144>`_
|
||||
|
||||
* Fix Mingw64 and add to the CI testing matrix.
|
||||
`#3132 <https://github.com/pybind/pybind11/pull/3132>`_
|
||||
|
||||
* Specified UTF8-encoding in setup.py calls of open().
|
||||
`#3137 <https://github.com/pybind/pybind11/pull/3137>`_
|
||||
|
||||
* Add clang-tidy-readability rules to make boolean casts explicit improving
|
||||
code readability. Also enabled other misc and readability clang-tidy checks.
|
||||
`#3148 <https://github.com/pybind/pybind11/pull/3148>`_
|
||||
|
||||
* Move object in ``.pop()`` for list.
|
||||
`#3116 <https://github.com/pybind/pybind11/pull/3116>`_
|
||||
|
||||
Backend and tidying up:
|
||||
|
||||
* Removed and fixed warning suppressions.
|
||||
`#3127 <https://github.com/pybind/pybind11/pull/3127>`_
|
||||
`#3129 <https://github.com/pybind/pybind11/pull/3129>`_
|
||||
`#3135 <https://github.com/pybind/pybind11/pull/3135>`_
|
||||
`#3141 <https://github.com/pybind/pybind11/pull/3141>`_
|
||||
`#3142 <https://github.com/pybind/pybind11/pull/3142>`_
|
||||
`#3150 <https://github.com/pybind/pybind11/pull/3150>`_
|
||||
`#3152 <https://github.com/pybind/pybind11/pull/3152>`_
|
||||
`#3160 <https://github.com/pybind/pybind11/pull/3160>`_
|
||||
`#3161 <https://github.com/pybind/pybind11/pull/3161>`_
|
||||
|
||||
|
||||
v2.7.0 (Jul 16, 2021)
|
||||
---------------------
|
||||
|
||||
New features:
|
||||
|
||||
* Enable ``py::implicitly_convertible<py::none, ...>`` for
|
||||
``py::class_``-wrapped types.
|
||||
`#3059 <https://github.com/pybind/pybind11/pull/3059>`_
|
||||
|
||||
* Allow function pointer extraction from overloaded functions.
|
||||
`#2944 <https://github.com/pybind/pybind11/pull/2944>`_
|
||||
|
||||
* NumPy: added ``.char_()`` to type which gives the NumPy public ``char``
|
||||
result, which also distinguishes types by bit length (unlike ``.kind()``).
|
||||
`#2864 <https://github.com/pybind/pybind11/pull/2864>`_
|
||||
|
||||
* Add ``pybind11::bytearray`` to manipulate ``bytearray`` similar to ``bytes``.
|
||||
`#2799 <https://github.com/pybind/pybind11/pull/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 <https://github.com/pybind/pybind11/pull/2730>`_
|
||||
|
||||
* A ``PYBIND11_VERSION_HEX`` define was added, similar to ``PY_VERSION_HEX``.
|
||||
`#3120 <https://github.com/pybind/pybind11/pull/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 <https://github.com/pybind/pybind11/pull/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 <https://github.com/pybind/pybind11/pull/2919>`_
|
||||
|
||||
* Catch a missing ``self`` argument in calls to ``__init__()``.
|
||||
`#2914 <https://github.com/pybind/pybind11/pull/2914>`_
|
||||
|
||||
* Use ``std::string_view`` if available to avoid a copy when passing an object
|
||||
to a ``std::ostream``.
|
||||
`#3042 <https://github.com/pybind/pybind11/pull/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 <https://github.com/pybind/pybind11/pull/2995>`_
|
||||
|
||||
|
||||
Fixes:
|
||||
|
||||
* Performance: avoid unnecessary strlen calls.
|
||||
`#3058 <https://github.com/pybind/pybind11/pull/3058>`_
|
||||
|
||||
* Fix auto-generated documentation string when using ``const T`` in
|
||||
``pyarray_t``.
|
||||
`#3020 <https://github.com/pybind/pybind11/pull/3020>`_
|
||||
|
||||
* Unify error messages thrown by ``simple_collector``/``unpacking_collector``.
|
||||
`#3013 <https://github.com/pybind/pybind11/pull/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 <https://github.com/pybind/pybind11/pull/2999>`_
|
||||
|
||||
* Fixed exception when printing UTF-8 to a ``scoped_ostream_redirect``.
|
||||
`#2982 <https://github.com/pybind/pybind11/pull/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 <https://github.com/pybind/pybind11/pull/2972>`_
|
||||
|
||||
* Allow negative timedelta values to roundtrip.
|
||||
`#2870 <https://github.com/pybind/pybind11/pull/2870>`_
|
||||
|
||||
* Fix unchecked errors could potentially swallow signals/other exceptions.
|
||||
`#2863 <https://github.com/pybind/pybind11/pull/2863>`_
|
||||
|
||||
* Add null pointer check with ``std::localtime``.
|
||||
`#2846 <https://github.com/pybind/pybind11/pull/2846>`_
|
||||
|
||||
* Fix the ``weakref`` constructor from ``py::object`` to create a new
|
||||
``weakref`` on conversion.
|
||||
`#2832 <https://github.com/pybind/pybind11/pull/2832>`_
|
||||
|
||||
* Avoid relying on exceptions in C++17 when getting a ``shared_ptr`` holder
|
||||
from a ``shared_from_this`` class.
|
||||
`#2819 <https://github.com/pybind/pybind11/pull/2819>`_
|
||||
|
||||
* Allow the codec's exception to be raised instead of :code:`RuntimeError` when
|
||||
casting from :code:`py::str` to :code:`std::string`.
|
||||
`#2903 <https://github.com/pybind/pybind11/pull/2903>`_
|
||||
|
||||
|
||||
Build system improvements:
|
||||
|
||||
* In ``setup_helpers.py``, test for platforms that have some multiprocessing
|
||||
features but lack semaphores, which ``ParallelCompile`` requires.
|
||||
`#3043 <https://github.com/pybind/pybind11/pull/3043>`_
|
||||
|
||||
* Fix ``pybind11_INCLUDE_DIR`` in case ``CMAKE_INSTALL_INCLUDEDIR`` is
|
||||
absolute.
|
||||
`#3005 <https://github.com/pybind/pybind11/pull/3005>`_
|
||||
|
||||
* Fix bug not respecting ``WITH_SOABI`` or ``WITHOUT_SOABI`` to CMake.
|
||||
`#2938 <https://github.com/pybind/pybind11/pull/2938>`_
|
||||
|
||||
* Fix the default ``Pybind11Extension`` compilation flags with a Mingw64 python.
|
||||
`#2921 <https://github.com/pybind/pybind11/pull/2921>`_
|
||||
|
||||
* Clang on Windows: do not pass ``/MP`` (ignored flag).
|
||||
`#2824 <https://github.com/pybind/pybind11/pull/2824>`_
|
||||
|
||||
* ``pybind11.setup_helpers.intree_extensions`` can be used to generate
|
||||
``Pybind11Extension`` instances from cpp files placed in the Python package
|
||||
source tree.
|
||||
`#2831 <https://github.com/pybind/pybind11/pull/2831>`_
|
||||
|
||||
Backend and tidying up:
|
||||
|
||||
* Enable clang-tidy performance, readability, and modernization checks
|
||||
throughout the codebase to enforce best coding practices.
|
||||
`#3046 <https://github.com/pybind/pybind11/pull/3046>`_,
|
||||
`#3049 <https://github.com/pybind/pybind11/pull/3049>`_,
|
||||
`#3051 <https://github.com/pybind/pybind11/pull/3051>`_,
|
||||
`#3052 <https://github.com/pybind/pybind11/pull/3052>`_,
|
||||
`#3080 <https://github.com/pybind/pybind11/pull/3080>`_, and
|
||||
`#3094 <https://github.com/pybind/pybind11/pull/3094>`_
|
||||
|
||||
|
||||
* Checks for common misspellings were added to the pre-commit hooks.
|
||||
`#3076 <https://github.com/pybind/pybind11/pull/3076>`_
|
||||
|
||||
* Changed ``Werror`` to stricter ``Werror-all`` for Intel compiler and fixed
|
||||
minor issues.
|
||||
`#2948 <https://github.com/pybind/pybind11/pull/2948>`_
|
||||
|
||||
* Fixed compilation with GCC < 5 when the user defines ``_GLIBCXX_USE_CXX11_ABI``.
|
||||
`#2956 <https://github.com/pybind/pybind11/pull/2956>`_
|
||||
|
||||
* Added nox support for easier local testing and linting of contributions.
|
||||
`#3101 <https://github.com/pybind/pybind11/pull/3101>`_ and
|
||||
`#3121 <https://github.com/pybind/pybind11/pull/3121>`_
|
||||
|
||||
* Avoid RTD style issue with docutils 0.17+.
|
||||
`#3119 <https://github.com/pybind/pybind11/pull/3119>`_
|
||||
|
||||
* Support pipx run, such as ``pipx run pybind11 --include`` for a quick compile.
|
||||
`#3117 <https://github.com/pybind/pybind11/pull/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 <https://github.com/pybind/pybind11/pull/2683>`_
|
||||
|
||||
* Fix issue with a test failing on PyTest 6.2.
|
||||
* Fix issue with a test failing on pytest 6.2.
|
||||
`#2741 <https://github.com/pybind/pybind11/pull/2741>`_
|
||||
|
||||
Warning fixes:
|
||||
|
@ -504,7 +706,7 @@ v2.4.0 (Sep 19, 2019)
|
|||
`#1888 <https://github.com/pybind/pybind11/pull/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 <https://github.com/pybind/pybind11/pull/1581>`_.
|
||||
|
||||
* Fixed ``get_include()`` on Conda.
|
||||
|
|
|
@ -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 <faq:symhidden>` contains an explanation on why these are needed.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <https://github.com/python/cpython/pull/22670>`_. 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 <https://github.com/python/cpython/pull/22670>`_.
|
||||
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.
|
||||
|
|
|
@ -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 <https://github.com/pybind/pybind11/pulls?q=is%3Apr+is%3Aclosed+label%3A%22needs+changelog%22>`_
|
||||
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 <https://github.com/pybind/pybind11/pulls?q=is%3Apr+is%3Aclosed+label%3A%22needs+changelog%22>`_
|
||||
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 <release branch>``, ``git push``
|
||||
- New branch: ``git checkout -b vX.Y``, ``git push -u origin vX.Y``
|
||||
- Update branch: ``git checkout vX.Y``, ``git merge <release branch>``, ``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``.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<is_new_style_constructor> : 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;
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ struct buffer_info {
|
|||
view->strides
|
||||
? std::vector<ssize_t>(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;
|
||||
|
|
|
@ -85,25 +85,28 @@ public:
|
|||
operator std::reference_wrapper<type>() { return cast_op<type &>(subcaster); }
|
||||
};
|
||||
|
||||
#define PYBIND11_TYPE_CASTER(type, py_name) \
|
||||
protected: \
|
||||
type value; \
|
||||
public: \
|
||||
static constexpr auto name = py_name; \
|
||||
template <typename T_, enable_if_t<std::is_same<type, remove_cv_t<T_>>::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 <typename T_> using cast_op_type = pybind11::detail::movable_cast_op_type<T_>
|
||||
|
||||
#define PYBIND11_TYPE_CASTER(type, py_name) \
|
||||
protected: \
|
||||
type value; \
|
||||
\
|
||||
public: \
|
||||
static constexpr auto name = py_name; \
|
||||
template <typename T_, enable_if_t<std::is_same<type, remove_cv_t<T_>>::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 <typename T_> \
|
||||
using cast_op_type = pybind11::detail::movable_cast_op_type<T_>
|
||||
|
||||
template <typename CharT> using is_std_char_type = any_of<
|
||||
std::is_same<CharT, char>, /* std::string */
|
||||
|
@ -178,7 +181,7 @@ public:
|
|||
// Signed/unsigned checks happen elsewhere
|
||||
if (py_err || (std::is_integral<T>::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<object>(std::is_floating_point<T>::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<std::is_integral<T>::value>("int", "float"));
|
||||
PYBIND11_TYPE_CASTER(T, _<std::is_integral<T>::value>("int", "float"));
|
||||
};
|
||||
|
||||
template<typename T> 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<void_type> : public void_caster<void_type> {};
|
||||
|
@ -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 <typename T> 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<bool> {
|
|||
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 <typename StringType, bool IsView = false> 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 <typename StringType, bool IsView = false> 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<unsigned char>(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 <typename _T> 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<Ts>::name...) + _x("]");
|
||||
static constexpr auto name = _("Tuple[") + concat(make_caster<Ts>::name...) + _("]");
|
||||
|
||||
template <typename T> using cast_op_type = type;
|
||||
|
||||
|
@ -664,14 +678,14 @@ protected:
|
|||
value = v_h.value_ptr();
|
||||
holder = v_h.template holder<holder_type>();
|
||||
return true;
|
||||
} else {
|
||||
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
|
||||
#if defined(NDEBUG)
|
||||
"(compile in debug mode for type information)");
|
||||
#else
|
||||
"of type '" + type_id<holder_type>() + "''");
|
||||
#endif
|
||||
}
|
||||
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
|
||||
#if defined(NDEBUG)
|
||||
"(compile in debug mode for type information)");
|
||||
#else
|
||||
"of type '"
|
||||
+ type_id<holder_type>() + "''");
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T = holder_type, detail::enable_if_t<!std::is_constructible<T, const T &, type*>::value, int> = 0>
|
||||
|
@ -743,14 +757,14 @@ template <typename base, typename holder> struct is_holder_type :
|
|||
template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> :
|
||||
std::true_type {};
|
||||
|
||||
template <typename T> struct handle_type_name { static constexpr auto name = _x<T>(); };
|
||||
template <> struct handle_type_name<bytes> { static constexpr auto name = _x(PYBIND11_BYTES_NAME); };
|
||||
template <> struct handle_type_name<int_> { static constexpr auto name = _x("int"); };
|
||||
template <> struct handle_type_name<iterable> { static constexpr auto name = _x("Iterable"); };
|
||||
template <> struct handle_type_name<iterator> { static constexpr auto name = _x("Iterator"); };
|
||||
template <> struct handle_type_name<none> { static constexpr auto name = _x("None"); };
|
||||
template <> struct handle_type_name<args> { static constexpr auto name = _x("*args"); };
|
||||
template <> struct handle_type_name<kwargs> { static constexpr auto name = _x("**kwargs"); };
|
||||
template <typename T> struct handle_type_name { static constexpr auto name = _<T>(); };
|
||||
template <> struct handle_type_name<bytes> { static constexpr auto name = _(PYBIND11_BYTES_NAME); };
|
||||
template <> struct handle_type_name<int_> { static constexpr auto name = _("int"); };
|
||||
template <> struct handle_type_name<iterable> { static constexpr auto name = _("Iterable"); };
|
||||
template <> struct handle_type_name<iterator> { static constexpr auto name = _("Iterator"); };
|
||||
template <> struct handle_type_name<none> { static constexpr auto name = _("None"); };
|
||||
template <> struct handle_type_name<args> { static constexpr auto name = _("*args"); };
|
||||
template <> struct handle_type_name<kwargs> { static constexpr auto name = _("**kwargs"); };
|
||||
|
||||
template <typename type>
|
||||
struct pyobject_caster {
|
||||
|
@ -917,8 +931,7 @@ template <typename T> detail::enable_if_t<detail::move_always<T>::value, T> cast
|
|||
template <typename T> detail::enable_if_t<detail::move_if_unreferenced<T>::value, T> cast(object &&object) {
|
||||
if (object.ref_count() > 1)
|
||||
return cast<T>(object);
|
||||
else
|
||||
return move<T>(std::move(object));
|
||||
return move<T>(std::move(object));
|
||||
}
|
||||
template <typename T> detail::enable_if_t<detail::move_never<T>::value, T> cast(object &&object) {
|
||||
return cast<T>(object);
|
||||
|
@ -958,6 +971,21 @@ template <> inline void cast_safe<void>(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 <return_value_policy policy = return_value_policy::automatic_reference>
|
||||
tuple make_tuple() { return tuple(0); }
|
||||
|
||||
|
@ -971,11 +999,10 @@ template <return_value_policy policy = return_value_policy::automatic_reference,
|
|||
for (size_t i = 0; i < args.size(); i++) {
|
||||
if (!args[i]) {
|
||||
#if defined(NDEBUG)
|
||||
throw cast_error("make_tuple(): unable to convert arguments to Python object (compile in debug mode for details)");
|
||||
throw cast_error_unable_to_convert_call_arg();
|
||||
#else
|
||||
std::array<std::string, size> argtypes { {type_id<Args>()...} };
|
||||
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 <typename T>
|
||||
arg_v arg::operator=(T &&value) const { return {std::move(*this), std::forward<T>(value)}; }
|
||||
arg_v arg::operator=(T &&value) const {
|
||||
return {*this, std::forward<T>(value)};
|
||||
}
|
||||
|
||||
/// Alias for backward compatibility -- to be removed in version 2.0
|
||||
template <typename /*unused*/> using arg_t = arg_v;
|
||||
|
@ -1228,9 +1257,10 @@ private:
|
|||
auto o = reinterpret_steal<object>(detail::make_caster<T>::cast(std::forward<T>(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<T>());
|
||||
throw cast_error_unable_to_convert_call_arg(
|
||||
std::to_string(args_list.size()), type_id<T>());
|
||||
#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<policy> collect_arguments(Args &&...args) {
|
|||
template <typename Derived>
|
||||
template <return_value_policy policy, typename... Args>
|
||||
object object_api<Derived>::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<policy>(std::forward<Args>(args)...).call(derived().ptr());
|
||||
}
|
||||
|
||||
|
|
|
@ -11,9 +11,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "pybind11.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <datetime.h>
|
||||
|
||||
// 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<uint_fast32_t, std::ratio<86400>>;
|
||||
using days = std::chrono::duration<int_least32_t, std::ratio<86400>>; // 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<rep, period>>(duration<double>(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<std::mutex> 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 <typename Duration> class type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
||||
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<system_clock::duration>(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,
|
||||
|
|
|
@ -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<ssize_t>(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<int>(info->readonly);
|
||||
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
|
||||
view->format = const_cast<char *>(info->format.c_str());
|
||||
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
|
||||
|
|
|
@ -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 <Python.h>
|
||||
|
@ -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 <typename T> void operator()(T*) { } };
|
|||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
template <typename... Args>
|
||||
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 <typename Return>
|
||||
constexpr auto operator()(Return (*pf)(Args...)) const noexcept
|
||||
|
|
|
@ -23,9 +23,9 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||
/* Concatenate type signatures at compile time */
|
||||
template <size_t N, typename... Ts>
|
||||
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<N>()) { }
|
||||
|
||||
template <size_t... Is>
|
||||
|
@ -51,8 +51,8 @@ constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a, c
|
|||
}
|
||||
|
||||
template <size_t N>
|
||||
constexpr descr<N - 1> _x(char const(&text)[N]) { return descr<N - 1>(text); }
|
||||
constexpr descr<0> _x(char const(&)[1]) { return {}; }
|
||||
constexpr descr<N - 1> _(char const(&text)[N]) { return descr<N - 1>(text); }
|
||||
constexpr descr<0> _(char const(&)[1]) { return {}; }
|
||||
|
||||
template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { };
|
||||
template <size_t...Digits> struct int_to_str<0, Digits...> {
|
||||
|
@ -61,24 +61,24 @@ template <size_t...Digits> struct int_to_str<0, Digits...> {
|
|||
|
||||
// Ternary description (like std::conditional)
|
||||
template <bool B, size_t N1, size_t N2>
|
||||
constexpr enable_if_t<B, descr<N1 - 1>> _x(char const(&text1)[N1], char const(&)[N2]) {
|
||||
return _x(text1);
|
||||
constexpr enable_if_t<B, descr<N1 - 1>> _(char const(&text1)[N1], char const(&)[N2]) {
|
||||
return _(text1);
|
||||
}
|
||||
template <bool B, size_t N1, size_t N2>
|
||||
constexpr enable_if_t<!B, descr<N2 - 1>> _x(char const(&)[N1], char const(&text2)[N2]) {
|
||||
return _x(text2);
|
||||
constexpr enable_if_t<!B, descr<N2 - 1>> _(char const(&)[N1], char const(&text2)[N2]) {
|
||||
return _(text2);
|
||||
}
|
||||
|
||||
template <bool B, typename T1, typename T2>
|
||||
constexpr enable_if_t<B, T1> _x(const T1 &d, const T2 &) { return d; }
|
||||
constexpr enable_if_t<B, T1> _(const T1 &d, const T2 &) { return d; }
|
||||
template <bool B, typename T1, typename T2>
|
||||
constexpr enable_if_t<!B, T2> _x(const T1 &, const T2 &d) { return d; }
|
||||
constexpr enable_if_t<!B, T2> _(const T1 &, const T2 &d) { return d; }
|
||||
|
||||
template <size_t Size> auto constexpr _x() -> decltype(int_to_str<Size / 10, Size % 10>::digits) {
|
||||
template <size_t Size> auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) {
|
||||
return int_to_str<Size / 10, Size % 10>::digits;
|
||||
}
|
||||
|
||||
template <typename Type> constexpr descr<1, Type> _x() { return {'%'}; }
|
||||
template <typename Type> constexpr descr<1, Type> _() { return {'%'}; }
|
||||
|
||||
constexpr descr<0> concat() { return {}; }
|
||||
|
||||
|
@ -88,12 +88,12 @@ constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) { return descr; }
|
|||
template <size_t N, typename... Ts, typename... Args>
|
||||
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
|
||||
-> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
|
||||
return d + _x(", ") + concat(args...);
|
||||
return d + _(", ") + concat(args...);
|
||||
}
|
||||
|
||||
template <size_t N, typename... Ts>
|
||||
constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) {
|
||||
return _x("{") + descr + _x("}");
|
||||
return _("{") + descr + _("}");
|
||||
}
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
|
||||
template <typename> using cast_op_type = value_and_holder &;
|
||||
operator value_and_holder &() { return *value; }
|
||||
static constexpr auto name = _x<value_and_holder>();
|
||||
static constexpr auto name = _<value_and_holder>();
|
||||
|
||||
private:
|
||||
value_and_holder *value = nullptr;
|
||||
|
@ -293,7 +293,13 @@ template <typename Class, typename T, typename O,
|
|||
enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
|
||||
void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
|
||||
construct<Class>(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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -231,17 +231,17 @@ struct value_and_holder {
|
|||
return reinterpret_cast<V *&>(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 <typename H> H &holder() const {
|
||||
return reinterpret_cast<H &>(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<ThisT &>(*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<instance *>(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 <typename type> class type_caster_base : public type_caster_generic {
|
|||
using itype = intrinsic_t<type>;
|
||||
|
||||
public:
|
||||
static constexpr auto name = _x<type>();
|
||||
static constexpr auto name = _<type>();
|
||||
|
||||
type_caster_base() : type_caster_base(typeid(type)) { }
|
||||
explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { }
|
||||
|
|
|
@ -169,21 +169,18 @@ template <typename Type_> 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<Type>::value && is_eigen_mutable_map<Type>::value;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "pybind11.h"
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
|
@ -43,7 +45,7 @@ enum eval_mode {
|
|||
};
|
||||
|
||||
template <eval_mode mode = eval_expr>
|
||||
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<mode>(expr, global, local);
|
||||
}
|
||||
|
||||
inline void exec(str expr, object global = globals(), object local = object()) {
|
||||
eval<eval_statements>(expr, global, local);
|
||||
inline void exec(const str &expr, object global = globals(), object local = object()) {
|
||||
eval<eval_statements>(expr, std::move(global), std::move(local));
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
|
@ -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;
|
||||
|
|
|
@ -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<capsule>(PyCFunction_GET_SELF(cfunc.ptr()));
|
||||
auto rec = (function_record *) c;
|
||||
auto cfunc_self = PyCFunction_GET_SELF(cfunc.ptr());
|
||||
if (isinstance<capsule>(cfunc_self)) {
|
||||
auto c = reinterpret_borrow<capsule>(cfunc_self);
|
||||
auto rec = (function_record *) c;
|
||||
|
||||
if (rec && rec->is_stateless &&
|
||||
same_type(typeid(function_type), *reinterpret_cast<const std::type_info *>(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<const std::type_info *>(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>(args)...));
|
||||
|
@ -92,8 +106,7 @@ public:
|
|||
auto result = f_.template target<function_type>();
|
||||
if (result)
|
||||
return cpp_function(*result, policy).release();
|
||||
else
|
||||
return cpp_function(std::forward<Func>(f_), policy).release();
|
||||
return cpp_function(std::forward<Func>(f_), policy).release();
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster<Args>::name...) + _("], ")
|
||||
|
|
|
@ -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 <streambuf>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
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<char *>(pbase());
|
||||
const auto rpptr = std::reverse_iterator<char *>(pptr());
|
||||
auto is_ascii = [](char c) {
|
||||
return (static_cast<unsigned char>(c) & 0x80) == 0x00;
|
||||
};
|
||||
auto is_leading = [](char c) {
|
||||
return (static_cast<unsigned char>(c) & 0xC0) == 0xC0;
|
||||
};
|
||||
auto is_leading_2b = [](char c) {
|
||||
return static_cast<unsigned char>(c) <= 0xDF;
|
||||
};
|
||||
auto is_leading_3b = [](char c) {
|
||||
return static_cast<unsigned char>(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<size_t>(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<size_t>(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<size_t>(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<int>(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_<detail::OstreamRedirect> add_ostream_redirect(module_ m, std::string name = "ostream_redirect") {
|
||||
return class_<detail::OstreamRedirect>(m, name.c_str(), module_local())
|
||||
.def(init<bool,bool>(), arg("stdout")=true, arg("stderr")=true)
|
||||
inline class_<detail::OstreamRedirect>
|
||||
add_ostream_redirect(module_ m, const std::string &name = "ostream_redirect") {
|
||||
return class_<detail::OstreamRedirect>(std::move(m), name.c_str(), module_local())
|
||||
.def(init<bool, bool>(), 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)
|
||||
|
|
|
@ -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 <typename T> using remove_all_extents_t = typename array_info<T>::type;
|
|||
|
||||
template <typename T> using is_pod_struct = all_of<
|
||||
std::is_standard_layout<T>, // 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<T>,
|
||||
#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<T>,
|
||||
satisfies_any_of<T, std::has_trivial_copy_constructor, std::has_trivial_copy_assign>,
|
||||
#else
|
||||
std::is_trivially_copyable<T>,
|
||||
#endif
|
||||
satisfies_none_of<T, std::is_reference, std::is_array, is_std_array, std::is_arithmetic, is_complex, std::is_enum>
|
||||
>;
|
||||
|
@ -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<dtype>(ptr);
|
||||
}
|
||||
|
@ -543,7 +544,7 @@ private:
|
|||
auto name = spec[0].cast<pybind11::str>();
|
||||
auto format = spec[1].cast<tuple>()[0].cast<dtype>();
|
||||
auto offset = spec[1].cast<tuple>()[1].cast<pybind11::int_>();
|
||||
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<T, enable_if_t<std::is_integral<T>::value>> {
|
|||
|
||||
template <typename T>
|
||||
struct npy_format_descriptor_name<T, enable_if_t<std::is_floating_point<T>::value>> {
|
||||
static constexpr auto name = _<std::is_same<T, float>::value || std::is_same<T, double>::value>(
|
||||
static constexpr auto name = _<std::is_same<T, float>::value
|
||||
|| std::is_same<T, const float>::value
|
||||
|| std::is_same<T, double>::value
|
||||
|| std::is_same<T, const double>::value>(
|
||||
_("numpy.float") + _<sizeof(T)*8>(), _("numpy.longdouble")
|
||||
);
|
||||
};
|
||||
|
@ -1038,7 +1043,9 @@ struct npy_format_descriptor_name<T, enable_if_t<std::is_floating_point<T>::valu
|
|||
template <typename T>
|
||||
struct npy_format_descriptor_name<T, enable_if_t<is_complex<T>::value>> {
|
||||
static constexpr auto name = _<std::is_same<typename T::value_type, float>::value
|
||||
|| std::is_same<typename T::value_type, double>::value>(
|
||||
|| std::is_same<typename T::value_type, const float>::value
|
||||
|| std::is_same<typename T::value_type, double>::value
|
||||
|| std::is_same<typename T::value_type, const double>::value>(
|
||||
_("numpy.complex") + _<sizeof(typename T::value_type)*16>(), _("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<char*>(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<ssize_t> &shape) {
|
||||
if (trivial == broadcast_trivial::f_trivial)
|
||||
return array_t<Return, array::f_style>(shape);
|
||||
else
|
||||
return array_t<Return>(shape);
|
||||
return array_t<Return>(shape);
|
||||
}
|
||||
|
||||
static Return *mutable_data(Type &array) {
|
||||
|
|
|
@ -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 <memory>
|
||||
#include <new>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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 <cxxabi.h>
|
||||
#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<Func>(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<Func>::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<Func>(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<std::string>().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<PyCFunction>(reinterpret_cast<void (*) (void)>(*dispatcher));
|
||||
rec->def->ml_meth
|
||||
= reinterpret_cast<PyCFunction>(reinterpret_cast<void (*)()>(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<char *>(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<dict>(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<instance *>(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<instance *>(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 <typename D, typename... Extra>
|
||||
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 <typename D, typename... Extra>
|
||||
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<Extra...>::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<Extra...>::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<CppException> ®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 <class T> 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<const cname *>(this), name); \
|
||||
if (override) { \
|
||||
auto o = override(__VA_ARGS__); \
|
||||
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value) { \
|
||||
static pybind11::detail::override_caster_t<ret_type> caster; \
|
||||
return pybind11::detail::cast_ref<ret_type>(std::move(o), caster); \
|
||||
} \
|
||||
else return pybind11::detail::cast_safe<ret_type>(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<const cname *>(this), name); \
|
||||
if (override) { \
|
||||
auto o = override(__VA_ARGS__); \
|
||||
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value) { \
|
||||
static pybind11::detail::override_caster_t<ret_type> caster; \
|
||||
return pybind11::detail::cast_ref<ret_type>(std::move(o), caster); \
|
||||
} \
|
||||
return pybind11::detail::cast_safe<ret_type>(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
|
||||
|
|
|
@ -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<object>(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<object>(result);
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
return reinterpret_borrow<object>(default_);
|
||||
}
|
||||
PyErr_Clear();
|
||||
return reinterpret_borrow<object>(default_);
|
||||
}
|
||||
|
||||
inline object getattr(handle obj, const char *name, handle default_) {
|
||||
if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) {
|
||||
return reinterpret_steal<object>(result);
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
return reinterpret_borrow<object>(default_);
|
||||
}
|
||||
PyErr_Clear();
|
||||
return reinterpret_borrow<object>(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 <typename Policy>
|
||||
class accessor : public object_api<accessor<Policy>> {
|
||||
using key_type = typename Policy::key_type;
|
||||
|
@ -496,7 +545,7 @@ class accessor : public object_api<accessor<Policy>> {
|
|||
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<py::python_type>(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 <typename Policy_> \
|
||||
Name(const ::pybind11::detail::accessor<Policy_> &a) : Name(object(a)) { }
|
||||
|
@ -973,10 +1028,10 @@ public:
|
|||
if (PyUnicode_Check(m_ptr)) {
|
||||
temp = reinterpret_steal<object>(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<object>(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<object>(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<ssize_t> shape,
|
||||
detail::any_container<ssize_t> strides) {
|
||||
return memoryview::from_buffer(
|
||||
const_cast<void*>(ptr), itemsize, format, shape, strides, true);
|
||||
const_cast<void *>(ptr), itemsize, format, std::move(shape), std::move(strides), true);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -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;
|
||||
|
|
|
@ -159,10 +159,13 @@ template <typename Type, typename Value> struct list_caster {
|
|||
}
|
||||
|
||||
private:
|
||||
template <typename T = Type,
|
||||
enable_if_t<std::is_same<decltype(std::declval<T>().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<std::is_same<decltype(std::declval<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 <typename T>
|
||||
|
@ -275,7 +278,8 @@ template<typename T> 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<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> {
|
|||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
|
||||
#ifdef PYBIND11_HAS_STRING_VIEW
|
||||
os << str(obj).cast<std::string_view>();
|
||||
#else
|
||||
os << (std::string) str(obj);
|
||||
#endif
|
||||
return os;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <string>
|
||||
|
||||
#ifdef __has_include
|
||||
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
|
||||
PY_VERSION_HEX >= 0x03060000
|
||||
# include <filesystem>
|
||||
# define PYBIND11_HAS_FILESYSTEM 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
|
||||
# error \
|
||||
"#include <filesystem> 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<typename T> 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<char*>(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<object>(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<typename T::value_type, char>) {
|
||||
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<typename T::value_type, wchar_t>) {
|
||||
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<std::filesystem::path>
|
||||
: public path_caster<std::filesystem::path> {};
|
||||
#endif // PYBIND11_HAS_FILESYSTEM
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
@ -128,11 +128,11 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
|||
arg("x"),
|
||||
"Add an item to the end of the list");
|
||||
|
||||
cl.def(init([](iterable it) {
|
||||
cl.def(init([](const iterable &it) {
|
||||
auto v = std::unique_ptr<Vector>(new Vector());
|
||||
v->reserve(len_hint(it));
|
||||
for (handle h : it)
|
||||
v->push_back(h.cast<T>());
|
||||
v->push_back(h.cast<T>());
|
||||
return v.release();
|
||||
}));
|
||||
|
||||
|
@ -151,27 +151,28 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
|||
"Extend the list by appending all the items in the given list"
|
||||
);
|
||||
|
||||
cl.def("extend",
|
||||
[](Vector &v, 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<T>());
|
||||
}
|
||||
} catch (const cast_error &) {
|
||||
v.erase(v.begin() + static_cast<typename Vector::difference_type>(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<T>());
|
||||
}
|
||||
} catch (const cast_error &) {
|
||||
v.erase(v.begin() + static_cast<typename Vector::difference_type>(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<is_copy_constructible<typename Vector::value_t
|
|||
[](Vector &v) {
|
||||
if (v.empty())
|
||||
throw index_error();
|
||||
T t = v.back();
|
||||
T t = std::move(v.back());
|
||||
v.pop_back();
|
||||
return t;
|
||||
},
|
||||
|
@ -200,8 +201,8 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
|||
cl.def("pop",
|
||||
[wrap_i](Vector &v, DiffType i) {
|
||||
i = wrap_i(i, v.size());
|
||||
T t = v[(SizeType) i];
|
||||
v.erase(v.begin() + i);
|
||||
T t = std::move(v[(SizeType) i]);
|
||||
v.erase(std::next(v.begin(), i));
|
||||
return t;
|
||||
},
|
||||
arg("i"),
|
||||
|
@ -216,9 +217,10 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
|||
);
|
||||
|
||||
/// Slicing protocol
|
||||
cl.def("__getitem__",
|
||||
cl.def(
|
||||
"__getitem__",
|
||||
[](const Vector &v, slice slice) -> 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<is_copy_constructible<typename Vector::value_t
|
|||
return seq;
|
||||
},
|
||||
arg("s"),
|
||||
"Retrieve list elements using a slice object"
|
||||
);
|
||||
"Retrieve list elements using a slice object");
|
||||
|
||||
cl.def("__setitem__",
|
||||
[](Vector &v, slice slice, const Vector &value) {
|
||||
size_t start, stop, step, slicelength;
|
||||
cl.def(
|
||||
"__setitem__",
|
||||
[](Vector &v, slice slice, const Vector &value) {
|
||||
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
||||
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
|
||||
throw error_already_set();
|
||||
|
||||
|
@ -250,8 +252,7 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
|||
start += step;
|
||||
}
|
||||
},
|
||||
"Assign list elements using a slice object"
|
||||
);
|
||||
"Assign list elements using a slice object");
|
||||
|
||||
cl.def("__delitem__",
|
||||
[wrap_i](Vector &v, DiffType i) {
|
||||
|
@ -261,9 +262,10 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
|||
"Delete the list elements at index ``i``"
|
||||
);
|
||||
|
||||
cl.def("__delitem__",
|
||||
cl.def(
|
||||
"__delitem__",
|
||||
[](Vector &v, slice slice) {
|
||||
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();
|
||||
|
@ -277,9 +279,7 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
|
|||
}
|
||||
}
|
||||
},
|
||||
"Delete list elements using a slice object"
|
||||
);
|
||||
|
||||
"Delete list elements using a slice object");
|
||||
}
|
||||
|
||||
// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
|
||||
|
@ -400,7 +400,7 @@ void vector_buffer_impl(Class_& cl, std::true_type) {
|
|||
return buffer_info(v.data(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::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<ssize_t>(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;
|
||||
|
|
|
@ -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("."))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: ...
|
||||
|
||||
|
|
|
@ -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 <filesystem>\nint main(int argc, char ** argv) {\n std::filesystem::path p(argv[0]);\n return p.string().length();\n}"
|
||||
)
|
||||
try_compile(
|
||||
STD_FS_NO_LIB_NEEDED ${CMAKE_CURRENT_BINARY_DIR}
|
||||
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
||||
COMPILE_DEFINITIONS -std=c++17)
|
||||
try_compile(
|
||||
STD_FS_NEEDS_STDCXXFS ${CMAKE_CURRENT_BINARY_DIR}
|
||||
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
||||
COMPILE_DEFINITIONS -std=c++17
|
||||
LINK_LIBRARIES stdc++fs)
|
||||
try_compile(
|
||||
STD_FS_NEEDS_CXXFS ${CMAKE_CURRENT_BINARY_DIR}
|
||||
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
||||
COMPILE_DEFINITIONS -std=c++17
|
||||
LINK_LIBRARIES c++fs)
|
||||
endif()
|
||||
|
||||
if(${STD_FS_NEEDS_STDCXXFS})
|
||||
set(STD_FS_LIB stdc++fs)
|
||||
elseif(${STD_FS_NEEDS_CXXFS})
|
||||
set(STD_FS_LIB c++fs)
|
||||
elseif(${STD_FS_NO_LIB_NEEDED})
|
||||
set(STD_FS_LIB "")
|
||||
else()
|
||||
message(WARNING "Unknown 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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#pragma once
|
||||
#include <utility>
|
||||
|
||||
#include "pybind11_tests.h"
|
||||
|
||||
/// Simple class used to test py::local:
|
||||
|
@ -54,9 +56,9 @@ py::class_<T> 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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -9,8 +9,12 @@
|
|||
|
||||
#include "pybind11_tests.h"
|
||||
#include "local_bindings.h"
|
||||
#include "test_exceptions.h"
|
||||
|
||||
#include <pybind11/stl_bind.h>
|
||||
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
|
||||
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_<pets::Pet>(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<float>) { });
|
||||
m.def("missing_header_arg", [](const std::vector<float> &) {});
|
||||
m.def("missing_header_return", []() { return std::vector<float>(); });
|
||||
}
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
// This must be kept first for MSVC 2015.
|
||||
// Do not remove the empty line between the #includes.
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
#include <pybind11/eval.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1910
|
||||
// We get some really long type names here which causes MSVC 2015 to emit warnings
|
||||
# pragma warning(disable: 4503) // warning C4503: decorated name length exceeded, name was truncated
|
||||
# pragma warning( \
|
||||
disable : 4503) // warning C4503: decorated name length exceeded, name was truncated
|
||||
#endif
|
||||
|
||||
namespace py = pybind11;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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_<Matrix>(m, "Matrix", py::buffer_protocol())
|
||||
.def(py::init<py::ssize_t, py::ssize_t>())
|
||||
/// Construct from a buffer
|
||||
.def(py::init([](py::buffer const b) {
|
||||
.def(py::init([](const py::buffer &b) {
|
||||
py::buffer_info info = b.request();
|
||||
if (info.format != py::format_descriptor<float>::format() || info.ndim != 2)
|
||||
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<py::ssize_t, py::ssize_t> i) {
|
||||
if (i.first >= m.rows() || i.second >= m.cols())
|
||||
throw py::index_error();
|
||||
return m(i.first, i.second);
|
||||
})
|
||||
.def("__setitem__", [](Matrix &m, std::pair<py::ssize_t, py::ssize_t> i, float v) {
|
||||
if (i.first >= m.rows() || i.second >= m.cols())
|
||||
throw py::index_error();
|
||||
m(i.first, i.second) = v;
|
||||
})
|
||||
/// Provide buffer access
|
||||
.def_buffer([](Matrix &m) -> py::buffer_info {
|
||||
.def("__getitem__",
|
||||
[](const Matrix &m, std::pair<py::ssize_t, py::ssize_t> i) {
|
||||
if (i.first >= m.rows() || i.second >= m.cols())
|
||||
throw py::index_error();
|
||||
return m(i.first, i.second);
|
||||
})
|
||||
.def("__setitem__",
|
||||
[](Matrix &m, std::pair<py::ssize_t, py::ssize_t> i, float v) {
|
||||
if (i.first >= m.rows() || i.second >= m.cols())
|
||||
throw py::index_error();
|
||||
m(i.first, i.second) = v;
|
||||
})
|
||||
/// Provide buffer access
|
||||
.def_buffer([](Matrix &m) -> py::buffer_info {
|
||||
return py::buffer_info(
|
||||
m.data(), /* Pointer to buffer */
|
||||
{ m.rows(), m.cols() }, /* Buffer dimensions */
|
||||
{ sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */
|
||||
sizeof(float) }
|
||||
);
|
||||
})
|
||||
;
|
||||
|
||||
});
|
||||
|
||||
// test_inherited_protocol
|
||||
class SquareMatrix : public Matrix {
|
||||
|
@ -154,7 +154,7 @@ TEST_SUBMODULE(buffers, m) {
|
|||
py::format_descriptor<int32_t>::format(), 1);
|
||||
}
|
||||
|
||||
ConstBuffer() : value(new int32_t{0}) { };
|
||||
ConstBuffer() : value(new int32_t{0}) {}
|
||||
};
|
||||
py::class_<ConstBuffer>(m, "ConstBuffer", py::buffer_protocol())
|
||||
.def(py::init<>())
|
||||
|
@ -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(); });
|
||||
}
|
||||
|
|
|
@ -30,7 +30,11 @@ class type_caster<ConstRefCasted> {
|
|||
// 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<bool, std::string> input) {
|
||||
return std::make_pair(input.second, input.first);
|
||||
}, "Return a pair in reversed order");
|
||||
m.def(
|
||||
"pair_passthrough",
|
||||
[](const std::pair<bool, std::string> &input) {
|
||||
return std::make_pair(input.second, input.first);
|
||||
},
|
||||
"Return a pair in reversed order");
|
||||
m.def("tuple_passthrough", [](std::tuple<bool, std::string, int> input) {
|
||||
return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input));
|
||||
}, "Return a triple in reversed order");
|
||||
|
@ -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)));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_<Parent>(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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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<int(int)> &func) {
|
||||
return "func(43) = " + std::to_string(func(43)); });
|
||||
m.def("test_callback4", []() -> std::function<int(int)> { return [](int i) { return i+1; }; });
|
||||
|
@ -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<Payload>);
|
||||
/* Test cleanup of lambda closure */
|
||||
m.def("test_cleanup", []() -> std::function<void(void)> {
|
||||
m.def("test_cleanup", []() -> std::function<void()> {
|
||||
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<int(int)> 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<double(AbstractBase&)>) { });
|
||||
m.def("func_accepting_func_accepting_base",
|
||||
[](const std::function<double(AbstractBase &)> &) {});
|
||||
|
||||
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_<MovableObject>(m, "MovableObject");
|
||||
|
||||
// test_movable_object
|
||||
m.def("callback_with_movable", [](std::function<void(MovableObject &)> f) {
|
||||
m.def("callback_with_movable", [](const std::function<void(MovableObject &)> &f) {
|
||||
auto x = MovableObject();
|
||||
f(x); // lvalue reference shouldn't move out object
|
||||
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<double(py::iterable)> &sum_builtin, const py::iterable &i) {
|
||||
return sum_builtin(i);
|
||||
});
|
||||
|
||||
// test async Python callbacks
|
||||
using callback_f = std::function<void(int)>;
|
||||
m.def("test_async_callback", [](callback_f f, py::list work) {
|
||||
m.def("test_async_callback", [](const callback_f &f, const py::list &work) {
|
||||
// make detached thread that calls `f` with piece of work after a little delay
|
||||
auto start_f = [f](int j) {
|
||||
auto invoke_f = [f, j] {
|
||||
|
@ -172,4 +179,10 @@ TEST_SUBMODULE(callbacks, m) {
|
|||
for (auto i : work)
|
||||
start_f(py::cast<int>(i));
|
||||
});
|
||||
|
||||
m.def("callback_num_times", [](const py::function &f, std::size_t num) {
|
||||
for (std::size_t i = 0; i < num; i++) {
|
||||
f();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "local_bindings.h"
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#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<py::tuple>(l[0]),
|
||||
py::isinstance<py::dict>(l[1]),
|
||||
|
@ -151,21 +153,16 @@ TEST_SUBMODULE(class_, m) {
|
|||
// return py::type::of<int>();
|
||||
if (category == 1)
|
||||
return py::type::of<DerivedClass1>();
|
||||
else
|
||||
return py::type::of<Invalid>();
|
||||
return py::type::of<Invalid>();
|
||||
});
|
||||
|
||||
m.def("get_type_of", [](py::object ob) {
|
||||
return py::type::of(ob);
|
||||
});
|
||||
m.def("get_type_of", [](py::object ob) { return py::type::of(std::move(ob)); });
|
||||
|
||||
m.def("get_type_classic", [](py::handle h) {
|
||||
return h.get_type();
|
||||
});
|
||||
|
||||
m.def("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<UserType, ConvertibleFromUserType>();
|
||||
|
||||
m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; });
|
||||
m.def("implicitly_convert_variable", [](py::object o) {
|
||||
m.def("implicitly_convert_variable", [](const py::object &o) {
|
||||
// `o` is `UserType` and `r` is a reference to a temporary created by implicit
|
||||
// conversion. This is valid when called inside a bound function because the temp
|
||||
// object is attached to the same life support system as the arguments.
|
||||
|
@ -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_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>());
|
||||
py::implicitly_convertible<std::string, StringWrapper>();
|
||||
|
||||
|
@ -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_<Duplicate>(m, "Duplicate");
|
||||
py::class_<OtherDuplicate>(m, "Duplicate");
|
||||
});
|
||||
m.def("register_duplicate_class_type", [](py::module_ m) {
|
||||
m.def("register_duplicate_class_type", [](const py::module_ &m) {
|
||||
py::class_<OtherDuplicate>(m, "OtherDuplicate");
|
||||
py::class_<OtherDuplicate>(m, "YetAnotherDuplicate");
|
||||
});
|
||||
m.def("register_duplicate_nested_class_name", [](py::object gt) {
|
||||
m.def("register_duplicate_nested_class_name", [](const py::object >) {
|
||||
py::class_<DuplicateNested>(gt, "DuplicateNested");
|
||||
py::class_<OtherDuplicateNested>(gt, "DuplicateNested");
|
||||
});
|
||||
m.def("register_duplicate_nested_class_type", [](py::object gt) {
|
||||
m.def("register_duplicate_nested_class_type", [](const py::object >) {
|
||||
py::class_<OtherDuplicateNested>(gt, "OtherDuplicateNested");
|
||||
py::class_<OtherDuplicateNested>(gt, "YetAnotherDuplicateNested");
|
||||
});
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw byte strings
|
||||
tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw
|
||||
byte strings
|
||||
|
||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
|
||||
|
@ -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<std::string>(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, "<the answer>"), 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, "<the answer>"),
|
||||
py::arg_v("z", default_value));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -37,9 +37,16 @@ template <> lacking_move_ctor empty<lacking_move_ctor>::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<MoveOrCopyInt>(o).value; /* moves */
|
||||
r += py::cast<MoveOnlyInt>(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<MoveOnlyInt, MoveOrCopyInt> 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_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
|
||||
|
|
|
@ -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<DestructionTester> {
|
||||
|
@ -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());
|
||||
|
|
|
@ -54,8 +54,7 @@ void reset_refs() {
|
|||
}
|
||||
|
||||
// Returns element 2,1 from a matrix (used to test copy/nocopy)
|
||||
double get_elem(Eigen::Ref<const Eigen::MatrixXd> m) { return m(2, 1); };
|
||||
|
||||
double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); };
|
||||
|
||||
// Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix
|
||||
// reference is referencing rows/columns correctly).
|
||||
|
@ -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<Eigen::Vector3f> x) { x *= 2; });
|
||||
m.def("double_threer", [](py::EigenDRef<Eigen::RowVector3f> x) { x *= 2; });
|
||||
m.def("double_mat_cm", [](Eigen::MatrixXf x) -> Eigen::MatrixXf { return 2.0f * x; });
|
||||
m.def("double_mat_rm", [](DenseMatrixR x) -> DenseMatrixR { return 2.0f * x; });
|
||||
m.def("double_mat_cm", [](const Eigen::MatrixXf &x) -> Eigen::MatrixXf { return 2.0f * x; });
|
||||
m.def("double_mat_rm", [](const DenseMatrixR &x) -> DenseMatrixR { return 2.0f * x; });
|
||||
|
||||
// test_eigen_ref_to_python
|
||||
// Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended
|
||||
m.def("cholesky1", [](Eigen::Ref<MatrixXdR> x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
|
||||
m.def("cholesky1",
|
||||
[](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
|
||||
m.def("cholesky2", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
|
||||
m.def("cholesky3", [](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
|
||||
m.def("cholesky4", [](Eigen::Ref<const MatrixXdR> x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
|
||||
m.def("cholesky4", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd {
|
||||
return x.llt().matrixL();
|
||||
});
|
||||
|
||||
// test_eigen_ref_mutators
|
||||
// Mutators: these add some value to the given element using Eigen, but Eigen should be mapping into
|
||||
|
@ -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<FixedMatrixR>) {});
|
||||
m.def("fixed_mutator_c", [](Eigen::Ref<FixedMatrixC>) {});
|
||||
m.def("fixed_mutator_a", [](py::EigenDRef<FixedMatrixC>) {});
|
||||
m.def("fixed_mutator_r", [](const Eigen::Ref<FixedMatrixR> &) {});
|
||||
m.def("fixed_mutator_c", [](const Eigen::Ref<FixedMatrixC> &) {});
|
||||
m.def("fixed_mutator_a", [](const py::EigenDRef<FixedMatrixC> &) {});
|
||||
// test_dense
|
||||
m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); });
|
||||
m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); });
|
||||
m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; });
|
||||
m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; });
|
||||
// test_sparse, test_sparse_signature
|
||||
m.def("sparse_r", [mat]() -> SparseMatrixR { return Eigen::SparseView<Eigen::MatrixXf>(mat); }); //NOLINT(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
m.def("sparse_r", [mat]() -> SparseMatrixR {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return Eigen::SparseView<Eigen::MatrixXf>(mat);
|
||||
});
|
||||
m.def("sparse_c", [mat]() -> SparseMatrixC { return Eigen::SparseView<Eigen::MatrixXf>(mat); });
|
||||
m.def("sparse_copy_r", [](const SparseMatrixR &m) -> SparseMatrixR { return m; });
|
||||
m.def("sparse_copy_c", [](const SparseMatrixC &m) -> SparseMatrixC { return m; });
|
||||
|
@ -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<const Eigen::MatrixXd> m) -> double { return get_elem(m); },
|
||||
py::arg{}.noconvert());
|
||||
m.def(
|
||||
"get_elem_nocopy",
|
||||
[](const Eigen::Ref<const Eigen::MatrixXd> &m) -> double { return get_elem(m); },
|
||||
py::arg{}.noconvert());
|
||||
// Also test a row-major-only no-copy const ref:
|
||||
m.def("get_elem_rm_nocopy", [](Eigen::Ref<const Eigen::Matrix<long, -1, -1, Eigen::RowMajor>> &m) -> long { return m(2, 1); },
|
||||
py::arg{}.noconvert());
|
||||
|
@ -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<const Eigen::MatrixXd> A, const py::EigenDRef<const Eigen::MatrixXd> B)
|
||||
-> Eigen::MatrixXd {
|
||||
if (A.cols() != B.rows()) throw std::domain_error("Nonconformable matrices!");
|
||||
return A * B;
|
||||
}, py::arg("A"), py::arg("B"));
|
||||
m.def(
|
||||
"matrix_multiply",
|
||||
[](const py::EigenDRef<const Eigen::MatrixXd> &A,
|
||||
const py::EigenDRef<const Eigen::MatrixXd> &B) -> Eigen::MatrixXd {
|
||||
if (A.cols() != B.rows())
|
||||
throw std::domain_error("Nonconformable matrices!");
|
||||
return A * B;
|
||||
},
|
||||
py::arg("A"),
|
||||
py::arg("B"));
|
||||
|
||||
// test_custom_operator_new
|
||||
py::class_<CustomOperatorNew>(m, "CustomOperatorNew")
|
||||
|
@ -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<const Eigen::VectorXd> v) {
|
||||
m.def("get_elem_direct", [](const Eigen::Ref<const Eigen::VectorXd> &v) {
|
||||
py::module_::import("numpy").attr("ones")(10);
|
||||
return v(5);
|
||||
});
|
||||
|
|
|
@ -8,16 +8,17 @@
|
|||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
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") {
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
|
||||
|
||||
#include <pybind11/eval.h>
|
||||
|
||||
#include "pybind11_tests.h"
|
||||
#include <utility>
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "test_exceptions.h"
|
||||
|
||||
#include "pybind11_tests.h"
|
||||
#include <utility>
|
||||
|
||||
// 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(); });
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include "pybind11_tests.h"
|
||||
#include <stdexcept>
|
||||
|
||||
// shared exceptions for cross_module_tests
|
||||
|
||||
class PYBIND11_EXPORT_EXCEPTION shared_exception : public pybind11::builtin_exception {
|
||||
public:
|
||||
using builtin_exception::builtin_exception;
|
||||
explicit shared_exception() : shared_exception("") {}
|
||||
void set_error() const override { PyErr_SetString(PyExc_RuntimeError, what()); }
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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 <cmath>
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
// 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<TestFactory1> construct1(int a) { return std::unique_ptr<TestFactory1>(new TestFactory1(a)); }
|
||||
// pointer again
|
||||
static TestFactory1 *construct1_string(std::string a) { return new TestFactory1(a); }
|
||||
static TestFactory1 *construct1_string(std::string a) {
|
||||
return new TestFactory1(std::move(a));
|
||||
}
|
||||
|
||||
// Moveable type:
|
||||
// pointer:
|
||||
|
@ -130,7 +155,7 @@ public:
|
|||
// holder:
|
||||
static std::unique_ptr<TestFactory2> construct2(int a) { return std::unique_ptr<TestFactory2>(new TestFactory2(a)); }
|
||||
// by value moving:
|
||||
static TestFactory2 construct2(std::string a) { return TestFactory2(a); }
|
||||
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_<TestFactory2>(m, "TestFactory2")
|
||||
.def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); }))
|
||||
.def(py::init([](unique_ptr_tag, std::string v) { return TestFactoryHelper::construct2(v); }))
|
||||
.def(py::init([](unique_ptr_tag, std::string v) {
|
||||
return TestFactoryHelper::construct2(std::move(v));
|
||||
}))
|
||||
.def(py::init([](move_tag) { return TestFactoryHelper::construct2(); }))
|
||||
.def_readwrite("value", &TestFactory2::value)
|
||||
;
|
||||
.def_readwrite("value", &TestFactory2::value);
|
||||
|
||||
// Stateful & reused:
|
||||
int c = 1;
|
||||
|
@ -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_<TestFactory6, PyTF6>(m, "TestFactory6")
|
||||
.def(py::init([](base_tag, int i) { return TestFactory6(i); }))
|
||||
.def(py::init([](alias_tag, int i) { return PyTF6(i); }))
|
||||
.def(py::init([](alias_tag, std::string s) { return PyTF6(s); }))
|
||||
.def(py::init([](alias_tag, std::string s) { return PyTF6(std::move(s)); }))
|
||||
.def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); }))
|
||||
.def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); }))
|
||||
.def(py::init([](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); }))
|
||||
.def(py::init(
|
||||
[](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); }))
|
||||
|
||||
.def("get", &TestFactory6::get)
|
||||
.def("has_alias", &TestFactory6::has_alias)
|
||||
|
||||
.def_static("get_cstats", &ConstructorStats::get<TestFactory6>, py::return_value_policy::reference)
|
||||
.def_static("get_alias_cstats", &ConstructorStats::get<PyTF6>, py::return_value_policy::reference)
|
||||
;
|
||||
.def_static(
|
||||
"get_cstats", &ConstructorStats::get<TestFactory6>, py::return_value_policy::reference)
|
||||
.def_static(
|
||||
"get_alias_cstats", &ConstructorStats::get<PyTF6>, py::return_value_policy::reference);
|
||||
|
||||
// test_init_factory_dual
|
||||
// Separate alias constructor testing
|
||||
py::class_<TestFactory7, PyTF7, std::shared_ptr<TestFactory7>>(m, "TestFactory7")
|
||||
.def(py::init(
|
||||
[](int i) { return TestFactory7(i); },
|
||||
[](int i) { return PyTF7(i); }))
|
||||
.def(py::init(
|
||||
[](pointer_tag, int i) { return new TestFactory7(i); },
|
||||
[](pointer_tag, int i) { return new PyTF7(i); }))
|
||||
.def(py::init(
|
||||
[](mixed_tag, int i) { return new TestFactory7(i); },
|
||||
[](mixed_tag, int i) { return PyTF7(i); }))
|
||||
.def(py::init(
|
||||
[](mixed_tag, std::string s) { return TestFactory7((int) s.size()); },
|
||||
[](mixed_tag, std::string s) { return new PyTF7((int) s.size()); }))
|
||||
.def(py::init(
|
||||
[](base_tag, pointer_tag, int i) { return new TestFactory7(i); },
|
||||
[](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); }))
|
||||
.def(py::init(
|
||||
[](alias_tag, pointer_tag, int i) { return new PyTF7(i); },
|
||||
[](alias_tag, pointer_tag, int i) { return new PyTF7(10*i); }))
|
||||
.def(py::init([](int i) { return TestFactory7(i); }, [](int i) { return PyTF7(i); }))
|
||||
.def(py::init([](pointer_tag, int i) { return new TestFactory7(i); },
|
||||
[](pointer_tag, int i) { return new PyTF7(i); }))
|
||||
.def(py::init([](mixed_tag, int i) { return new TestFactory7(i); },
|
||||
[](mixed_tag, int i) { return PyTF7(i); }))
|
||||
.def(py::init([](mixed_tag, const std::string &s) { return TestFactory7((int) s.size()); },
|
||||
[](mixed_tag, const std::string &s) { return new PyTF7((int) s.size()); }))
|
||||
.def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory7(i); },
|
||||
[](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); }))
|
||||
.def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF7(i); },
|
||||
[](alias_tag, pointer_tag, int i) { return new PyTF7(10 * i); }))
|
||||
.def(py::init(
|
||||
[](shared_ptr_tag, base_tag, int i) { return std::make_shared<TestFactory7>(i); },
|
||||
[](shared_ptr_tag, base_tag, int i) { auto *p = new PyTF7(i); return std::shared_ptr<TestFactory7>(p); }))
|
||||
.def(py::init(
|
||||
[](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared<TestFactory7>(i); },
|
||||
[](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared<TestFactory7>(i); })) // <-- invalid alias factory
|
||||
[](shared_ptr_tag, base_tag, int i) {
|
||||
auto *p = new PyTF7(i);
|
||||
return std::shared_ptr<TestFactory7>(p);
|
||||
}))
|
||||
.def(py::init([](shared_ptr_tag,
|
||||
invalid_base_tag,
|
||||
int i) { return std::make_shared<TestFactory7>(i); },
|
||||
[](shared_ptr_tag, invalid_base_tag, int i) {
|
||||
return std::make_shared<TestFactory7>(i);
|
||||
})) // <-- invalid alias factory
|
||||
|
||||
.def("get", &TestFactory7::get)
|
||||
.def("has_alias", &TestFactory7::has_alias)
|
||||
|
||||
.def_static("get_cstats", &ConstructorStats::get<TestFactory7>, py::return_value_policy::reference)
|
||||
.def_static("get_alias_cstats", &ConstructorStats::get<PyTF7>, py::return_value_policy::reference)
|
||||
;
|
||||
.def_static(
|
||||
"get_cstats", &ConstructorStats::get<TestFactory7>, py::return_value_policy::reference)
|
||||
.def_static(
|
||||
"get_alias_cstats", &ConstructorStats::get<PyTF7>, py::return_value_policy::reference);
|
||||
|
||||
// test_placement_new_alternative
|
||||
// Class with a custom new operator but *without* a placement new operator (issue #948)
|
||||
|
@ -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 {};
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
|
|
@ -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<void()> &func) { func(); });
|
||||
m.def("test_callback_virtual_func",
|
||||
[](VirtClass &virt) { virt.virtual_func(); });
|
||||
m.def("test_callback_pure_virtual_func",
|
||||
[](VirtClass &virt) { virt.pure_virtual_func(); });
|
||||
m.def("test_cross_module_gil",
|
||||
[]() {
|
||||
auto cm = py::module_::import("cross_module_gil_utils");
|
||||
auto gil_acquire = reinterpret_cast<void (*)()>(
|
||||
PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr()));
|
||||
py::gil_scoped_release gil_release;
|
||||
gil_acquire();
|
||||
});
|
||||
m.def("test_callback_py_obj", [](py::object &func) { func(); });
|
||||
m.def("test_callback_std_func", [](const std::function<void()> &func) { func(); });
|
||||
m.def("test_callback_virtual_func", [](VirtClass &virt) { virt.virtual_func(); });
|
||||
m.def("test_callback_pure_virtual_func", [](VirtClass &virt) { virt.pure_virtual_func(); });
|
||||
m.def("test_cross_module_gil", []() {
|
||||
auto cm = py::module_::import("cross_module_gil_utils");
|
||||
auto gil_acquire
|
||||
= reinterpret_cast<void (*)()>(PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr()));
|
||||
py::gil_scoped_release gil_release;
|
||||
gil_acquire();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,17 +15,18 @@
|
|||
#include "pybind11_tests.h"
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
|
||||
void noisy_function(std::string msg, bool flush) {
|
||||
void noisy_function(const std::string &msg, bool flush) {
|
||||
|
||||
std::cout << msg;
|
||||
if (flush)
|
||||
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<std::mutex> lock(cout_mutex);
|
||||
std::cout << "x" << std::flush;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(50));
|
||||
} };
|
||||
t_ = new std::thread(std::move(thread_f));
|
||||
|
@ -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<bool> 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::scoped_ostream_redirect>(),
|
||||
py::arg("msg"), py::arg("flush")=true);
|
||||
|
||||
m.def("captured_err", [](std::string msg) {
|
||||
m.def("captured_err", [](const std::string &msg) {
|
||||
py::scoped_ostream_redirect redir(std::cerr, py::module_::import("sys").attr("stderr"));
|
||||
std::cerr << msg << std::flush;
|
||||
});
|
||||
|
@ -95,15 +106,11 @@ TEST_SUBMODULE(iostream, m) {
|
|||
py::call_guard<py::scoped_ostream_redirect, py::scoped_estream_redirect>(),
|
||||
py::arg("msg"), py::arg("emsg"));
|
||||
|
||||
m.def("raw_output", [](std::string msg) {
|
||||
std::cout << msg << std::flush;
|
||||
});
|
||||
m.def("raw_output", [](const std::string &msg) { std::cout << msg << std::flush; });
|
||||
|
||||
m.def("raw_err", [](std::string msg) {
|
||||
std::cerr << msg << std::flush;
|
||||
});
|
||||
m.def("raw_err", [](const std::string &msg) { std::cerr << msg << std::flush; });
|
||||
|
||||
m.def("captured_dual", [](std::string msg, std::string emsg) {
|
||||
m.def("captured_dual", [](const std::string &msg, const std::string &emsg) {
|
||||
py::scoped_ostream_redirect redirout(std::cout, py::module_::import("sys").attr("stdout"));
|
||||
py::scoped_ostream_redirect redirerr(std::cerr, py::module_::import("sys").attr("stderr"));
|
||||
std::cout << msg << std::flush;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "constructor_stats.h"
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
TEST_SUBMODULE(kwargs_and_defaults, m) {
|
||||
auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); };
|
||||
|
||||
|
@ -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<py::ssize_t>(i)));
|
||||
return t;
|
||||
});
|
||||
m.def("mixed_args_refcount", [](py::object o, py::args a) {
|
||||
m.def("mixed_args_refcount", [](const py::object &o, py::args a) {
|
||||
GC_IF_NEEDED;
|
||||
py::tuple t(a.size() + 1);
|
||||
t[0] = o.ref_count();
|
||||
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -10,9 +10,12 @@
|
|||
|
||||
#include "pybind11_tests.h"
|
||||
#include "local_bindings.h"
|
||||
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/stl_bind.h>
|
||||
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
|
||||
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_<pets::Pet>(m, "Pet", py::module_local())
|
||||
.def("get_name", &pets::Pet::name);
|
||||
// Binding for local extending class:
|
||||
|
|
|
@ -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<NoneTester> &obj) { return obj ? obj->answer : -1; }
|
||||
int none4(std::shared_ptr<NoneTester> *obj) { return obj && *obj ? (*obj)->answer : -1; }
|
||||
int none5(std::shared_ptr<NoneTester> obj) { return obj ? obj->answer : -1; }
|
||||
int none5(const std::shared_ptr<NoneTester> &obj) { return obj ? obj->answer : -1; }
|
||||
|
||||
// Issue #2778: implicit casting from None to object (not pointer)
|
||||
class NoneCastTester {
|
||||
public:
|
||||
int answer = -1;
|
||||
NoneCastTester() = default;
|
||||
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_<TestPropertiesOverride, TestProperties>(m, "TestPropertiesOverride")
|
||||
.def(py::init<>())
|
||||
.def_readonly("def_readonly", &TestPropertiesOverride::value)
|
||||
.def_readonly_static("def_readonly_static", &TestPropertiesOverride::static_value);
|
||||
|
||||
auto static_get1 = [](py::object) -> const UserType & { return TestPropRVP::sv1; };
|
||||
auto static_get2 = [](py::object) -> const UserType & { return TestPropRVP::sv2; };
|
||||
auto static_set1 = [](py::object, int v) { TestPropRVP::sv1.set(v); };
|
||||
auto static_set2 = [](py::object, int v) { TestPropRVP::sv2.set(v); };
|
||||
auto static_get1 = [](const py::object &) -> const UserType & { return TestPropRVP::sv1; };
|
||||
auto static_get2 = [](const py::object &) -> const UserType & { return TestPropRVP::sv2; };
|
||||
auto static_set1 = [](const py::object &, int v) { TestPropRVP::sv1.set(v); };
|
||||
auto static_set2 = [](const py::object &, int v) { TestPropRVP::sv2.set(v); };
|
||||
auto rvp_copy = py::return_value_policy::copy;
|
||||
|
||||
// test_property_return_value_policies
|
||||
|
@ -268,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_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type))
|
||||
.def_property_readonly_static("readonly", [](py::object) { return 1; });
|
||||
.def_property_readonly_static("readonly", [](const py::object &) { return 1; });
|
||||
|
||||
// test_overload_ordering
|
||||
m.def("overload_order", [](std::string) { return 1; });
|
||||
m.def("overload_order", [](std::string) { return 2; });
|
||||
m.def("overload_order", [](const std::string &) { return 1; });
|
||||
m.def("overload_order", [](const std::string &) { return 2; });
|
||||
m.def("overload_order", [](int) { return 3; });
|
||||
m.def("overload_order", [](int) { return 4; }, py::prepend{});
|
||||
|
||||
|
@ -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_<NoneCastTester>(m, "NoneCastTester")
|
||||
.def(py::init<>())
|
||||
.def(py::init<int>())
|
||||
.def(py::init([](py::none const&) { return NoneCastTester{}; }));
|
||||
py::implicitly_convertible<py::none, NoneCastTester>();
|
||||
m.def("ok_obj_or_none", [](NoneCastTester const& foo) { return foo.answer; });
|
||||
|
||||
|
||||
// test_str_issue
|
||||
// Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
|
||||
py::class_<StrIssue>(m, "StrIssue")
|
||||
|
@ -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>(&RegisteredDerived::do_nothing));
|
||||
static_assert(std::is_same<Adapted, void (RegisteredDerived::*)() const>::value, "");
|
||||
|
|
|
@ -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"""
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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 <int N> 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_<Base1> 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_<Base2> 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_<Base1a, std::shared_ptr<Base1a>>(m, "Base1a")
|
||||
.def(py::init<int>())
|
||||
.def("foo", &Base1a::foo);
|
||||
|
||||
struct Base2a {
|
||||
Base2a(int i) : i(i) { }
|
||||
int bar() { return i; }
|
||||
int i;
|
||||
};
|
||||
py::class_<Base2a, std::shared_ptr<Base2a>>(m, "Base2a")
|
||||
.def(py::init<int>())
|
||||
.def("bar", &Base2a::bar);
|
||||
|
||||
struct Base12a : Base1a, Base2a {
|
||||
Base12a(int i, int j) : Base1a(i), Base2a(j) { }
|
||||
};
|
||||
py::class_<Base12a, /* Base1 missing */ Base2a,
|
||||
std::shared_ptr<Base12a>>(m, "Base12a", py::multiple_inheritance())
|
||||
.def(py::init<int, int>());
|
||||
|
||||
m.def("bar_base2a", [](Base2a *b) { return b->bar(); });
|
||||
m.def("bar_base2a_sharedptr", [](std::shared_ptr<Base2a> b) { return b->bar(); });
|
||||
m.def("bar_base2a_sharedptr", [](const std::shared_ptr<Base2a> &b) { return b->bar(); });
|
||||
|
||||
// test_mi_unaligned_base
|
||||
// test_mi_base_return
|
||||
// Issue #801: invalid casting to derived type with MI bases
|
||||
struct I801B1 { int a = 1; I801B1() = default; I801B1(const I801B1 &) = default; virtual ~I801B1() = default; };
|
||||
struct I801B2 { int b = 2; I801B2() = default; I801B2(const I801B2 &) = default; virtual ~I801B2() = default; };
|
||||
struct I801C : I801B1, I801B2 {};
|
||||
struct I801D : I801C {}; // Indirect MI
|
||||
// Unregistered classes:
|
||||
struct I801B3 { int c = 3; virtual ~I801B3() = default; };
|
||||
struct I801E : I801B3, I801D {};
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <pybind11/stl.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
// 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<py::array>(yes) && !py::isinstance<py::array>(no);
|
||||
return py::isinstance<py::array>(std::move(yes))
|
||||
&& !py::isinstance<py::array>(std::move(no));
|
||||
});
|
||||
sm.def("isinstance_typed", [](py::object o) {
|
||||
sm.def("isinstance_typed", [](const py::object &o) {
|
||||
return py::isinstance<py::array_t<double>>(o) && !py::isinstance<py::array_t<int>>(o);
|
||||
});
|
||||
|
||||
|
@ -236,7 +238,7 @@ TEST_SUBMODULE(numpy_array, sm) {
|
|||
"array_t<double>"_a=py::array_t<double>()
|
||||
);
|
||||
});
|
||||
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<int32>"_a=py::array_t<std::int32_t>(o),
|
||||
|
@ -245,40 +247,47 @@ TEST_SUBMODULE(numpy_array, sm) {
|
|||
});
|
||||
|
||||
// test_overload_resolution
|
||||
sm.def("overloaded", [](py::array_t<double>) { return "double"; });
|
||||
sm.def("overloaded", [](py::array_t<float>) { return "float"; });
|
||||
sm.def("overloaded", [](py::array_t<int>) { return "int"; });
|
||||
sm.def("overloaded", [](py::array_t<unsigned short>) { return "unsigned short"; });
|
||||
sm.def("overloaded", [](py::array_t<long long>) { return "long long"; });
|
||||
sm.def("overloaded", [](py::array_t<std::complex<double>>) { return "double complex"; });
|
||||
sm.def("overloaded", [](py::array_t<std::complex<float>>) { return "float complex"; });
|
||||
sm.def("overloaded", [](const py::array_t<double> &) { return "double"; });
|
||||
sm.def("overloaded", [](const py::array_t<float> &) { return "float"; });
|
||||
sm.def("overloaded", [](const py::array_t<int> &) { return "int"; });
|
||||
sm.def("overloaded", [](const py::array_t<unsigned short> &) { return "unsigned short"; });
|
||||
sm.def("overloaded", [](const py::array_t<long long> &) { return "long long"; });
|
||||
sm.def("overloaded",
|
||||
[](const py::array_t<std::complex<double>> &) { return "double complex"; });
|
||||
sm.def("overloaded", [](const py::array_t<std::complex<float>> &) { return "float complex"; });
|
||||
|
||||
sm.def("overloaded2", [](py::array_t<std::complex<double>>) { return "double complex"; });
|
||||
sm.def("overloaded2", [](py::array_t<double>) { return "double"; });
|
||||
sm.def("overloaded2", [](py::array_t<std::complex<float>>) { return "float complex"; });
|
||||
sm.def("overloaded2", [](py::array_t<float>) { return "float"; });
|
||||
sm.def("overloaded2",
|
||||
[](const py::array_t<std::complex<double>> &) { return "double complex"; });
|
||||
sm.def("overloaded2", [](const py::array_t<double> &) { return "double"; });
|
||||
sm.def("overloaded2",
|
||||
[](const py::array_t<std::complex<float>> &) { return "float complex"; });
|
||||
sm.def("overloaded2", [](const py::array_t<float> &) { return "float"; });
|
||||
|
||||
// [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works.
|
||||
|
||||
// Only accept the exact types:
|
||||
sm.def("overloaded3", [](py::array_t<int>) { return "int"; }, py::arg{}.noconvert());
|
||||
sm.def("overloaded3", [](py::array_t<double>) { return "double"; }, py::arg{}.noconvert());
|
||||
sm.def(
|
||||
"overloaded3", [](const py::array_t<int> &) { return "int"; }, py::arg{}.noconvert());
|
||||
sm.def(
|
||||
"overloaded3",
|
||||
[](const py::array_t<double> &) { return "double"; },
|
||||
py::arg{}.noconvert());
|
||||
|
||||
// Make sure we don't do unsafe coercion (e.g. float to int) when not using forcecast, but
|
||||
// rather that float gets converted via the safe (conversion to double) overload:
|
||||
sm.def("overloaded4", [](py::array_t<long long, 0>) { return "long long"; });
|
||||
sm.def("overloaded4", [](py::array_t<double, 0>) { return "double"; });
|
||||
sm.def("overloaded4", [](const py::array_t<long long, 0> &) { return "long long"; });
|
||||
sm.def("overloaded4", [](const py::array_t<double, 0> &) { return "double"; });
|
||||
|
||||
// But we do allow conversion to int if forcecast is enabled (but only if no overload matches
|
||||
// without conversion)
|
||||
sm.def("overloaded5", [](py::array_t<unsigned int>) { return "unsigned int"; });
|
||||
sm.def("overloaded5", [](py::array_t<double>) { return "double"; });
|
||||
sm.def("overloaded5", [](const py::array_t<unsigned int> &) { return "unsigned int"; });
|
||||
sm.def("overloaded5", [](const py::array_t<double> &) { return "double"; });
|
||||
|
||||
// test_greedy_string_overload
|
||||
// Issue 685: ndarray shouldn't go to std::string overload
|
||||
sm.def("issue685", [](std::string) { return "string"; });
|
||||
sm.def("issue685", [](py::array) { return "array"; });
|
||||
sm.def("issue685", [](py::object) { return "other"; });
|
||||
sm.def("issue685", [](const std::string &) { return "string"; });
|
||||
sm.def("issue685", [](const py::array &) { return "array"; });
|
||||
sm.def("issue685", [](const py::object &) { return "other"; });
|
||||
|
||||
// test_array_unchecked_fixed_dims
|
||||
sm.def("proxy_add2", [](py::array_t<double> a, double v) {
|
||||
|
@ -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<double> a) {
|
||||
sm.def("proxy_squared_L2_norm", [](const py::array_t<double> &a) {
|
||||
auto r = a.unchecked<1>();
|
||||
double sumsq = 0;
|
||||
for (py::ssize_t i = 0; i < r.shape(0); i++)
|
||||
|
@ -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<double, 0>) {},
|
||||
py::arg("a"));
|
||||
sm.def("accept_double_forcecast",
|
||||
[](py::array_t<double, py::array::forcecast>) {},
|
||||
py::arg("a"));
|
||||
sm.def("accept_double_c_style",
|
||||
[](py::array_t<double, py::array::c_style>) {},
|
||||
py::arg("a"));
|
||||
sm.def("accept_double_c_style_forcecast",
|
||||
[](py::array_t<double, py::array::forcecast | py::array::c_style>) {},
|
||||
py::arg("a"));
|
||||
sm.def("accept_double_f_style",
|
||||
[](py::array_t<double, py::array::f_style>) {},
|
||||
py::arg("a"));
|
||||
sm.def("accept_double_f_style_forcecast",
|
||||
[](py::array_t<double, py::array::forcecast | py::array::f_style>) {},
|
||||
py::arg("a"));
|
||||
sm.def("accept_double_noconvert",
|
||||
[](py::array_t<double, 0>) {},
|
||||
"a"_a.noconvert());
|
||||
sm.def("accept_double_forcecast_noconvert",
|
||||
[](py::array_t<double, py::array::forcecast>) {},
|
||||
"a"_a.noconvert());
|
||||
sm.def("accept_double_c_style_noconvert",
|
||||
[](py::array_t<double, py::array::c_style>) {},
|
||||
"a"_a.noconvert());
|
||||
sm.def("accept_double_c_style_forcecast_noconvert",
|
||||
[](py::array_t<double, py::array::forcecast | py::array::c_style>) {},
|
||||
"a"_a.noconvert());
|
||||
sm.def("accept_double_f_style_noconvert",
|
||||
[](py::array_t<double, py::array::f_style>) {},
|
||||
"a"_a.noconvert());
|
||||
sm.def("accept_double_f_style_forcecast_noconvert",
|
||||
[](py::array_t<double, py::array::forcecast | py::array::f_style>) {},
|
||||
"a"_a.noconvert());
|
||||
sm.def(
|
||||
"accept_double", [](const py::array_t<double, 0> &) {}, py::arg("a"));
|
||||
sm.def(
|
||||
"accept_double_forcecast",
|
||||
[](const py::array_t<double, py::array::forcecast> &) {},
|
||||
py::arg("a"));
|
||||
sm.def(
|
||||
"accept_double_c_style",
|
||||
[](const py::array_t<double, py::array::c_style> &) {},
|
||||
py::arg("a"));
|
||||
sm.def(
|
||||
"accept_double_c_style_forcecast",
|
||||
[](const py::array_t<double, py::array::forcecast | py::array::c_style> &) {},
|
||||
py::arg("a"));
|
||||
sm.def(
|
||||
"accept_double_f_style",
|
||||
[](const py::array_t<double, py::array::f_style> &) {},
|
||||
py::arg("a"));
|
||||
sm.def(
|
||||
"accept_double_f_style_forcecast",
|
||||
[](const py::array_t<double, py::array::forcecast | py::array::f_style> &) {},
|
||||
py::arg("a"));
|
||||
sm.def(
|
||||
"accept_double_noconvert", [](const py::array_t<double, 0> &) {}, "a"_a.noconvert());
|
||||
sm.def(
|
||||
"accept_double_forcecast_noconvert",
|
||||
[](const py::array_t<double, py::array::forcecast> &) {},
|
||||
"a"_a.noconvert());
|
||||
sm.def(
|
||||
"accept_double_c_style_noconvert",
|
||||
[](const py::array_t<double, py::array::c_style> &) {},
|
||||
"a"_a.noconvert());
|
||||
sm.def(
|
||||
"accept_double_c_style_forcecast_noconvert",
|
||||
[](const py::array_t<double, py::array::forcecast | py::array::c_style> &) {},
|
||||
"a"_a.noconvert());
|
||||
sm.def(
|
||||
"accept_double_f_style_noconvert",
|
||||
[](const py::array_t<double, py::array::f_style> &) {},
|
||||
"a"_a.noconvert());
|
||||
sm.def(
|
||||
"accept_double_f_style_forcecast_noconvert",
|
||||
[](const py::array_t<double, py::array::forcecast | py::array::f_style> &) {},
|
||||
"a"_a.noconvert());
|
||||
|
||||
// Check that types returns correct npy format descriptor
|
||||
sm.def("test_fmt_desc_float", [](const py::array_t<float> &) {});
|
||||
sm.def("test_fmt_desc_double", [](const py::array_t<double> &) {});
|
||||
sm.def("test_fmt_desc_const_float", [](const py::array_t<const float> &) {});
|
||||
sm.def("test_fmt_desc_const_double", [](const py::array_t<const double> &) {});
|
||||
}
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "pybind11_tests.h"
|
||||
#include <pybind11/numpy.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
double my_func(int x, float y, double z) {
|
||||
py::print("my_func(x:int={}, y:float={:.0f}, z:float={:.0f})"_s.format(x, y, z));
|
||||
return (float) x*y*z;
|
||||
|
@ -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<int> x, py::array_t<float> y, float z) {
|
||||
return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(x, y);
|
||||
}
|
||||
);
|
||||
m.def("vectorized_func2", [](py::array_t<int> x, py::array_t<float> y, float z) {
|
||||
return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(std::move(x),
|
||||
std::move(y));
|
||||
});
|
||||
|
||||
// Vectorize a complex-valued function
|
||||
m.def("vectorized_func3", py::vectorize(
|
||||
|
@ -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<int, py::array::c_style>) { return "Int branch taken."; });
|
||||
m.def("selective_func", [](py::array_t<float, py::array::c_style>) { return "Float branch taken."; });
|
||||
m.def("selective_func", [](py::array_t<std::complex<float>, py::array::c_style>) { return "Complex float branch taken."; });
|
||||
|
||||
// A lot of these no lints could be replaced with const refs, and probably should at some point.
|
||||
m.def("selective_func",
|
||||
[](const py::array_t<int, py::array::c_style> &) { return "Int branch taken."; });
|
||||
m.def("selective_func",
|
||||
[](const py::array_t<float, py::array::c_style> &) { return "Float branch taken."; });
|
||||
m.def("selective_func", [](const py::array_t<std::complex<float>, py::array::c_style> &) {
|
||||
return "Complex float branch taken.";
|
||||
});
|
||||
|
||||
// test_passthrough_arguments
|
||||
// Passthrough test: references and non-pod types should be automatically passed through (in the
|
||||
|
@ -53,16 +58,21 @@ TEST_SUBMODULE(numpy_vectorize, m) {
|
|||
py::class_<NonPODClass>(m, "NonPODClass")
|
||||
.def(py::init<int>())
|
||||
.def_readwrite("value", &NonPODClass::value);
|
||||
m.def("vec_passthrough", py::vectorize(
|
||||
[](double *a, double b, py::array_t<double> c, const int &d, int &e, NonPODClass f, const double g) {
|
||||
return *a + b + c.at(0) + d + e + f.value + g;
|
||||
}
|
||||
));
|
||||
m.def("vec_passthrough",
|
||||
py::vectorize([](const double *a,
|
||||
double b,
|
||||
// Changing this broke things
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
py::array_t<double> c,
|
||||
const int &d,
|
||||
int &e,
|
||||
NonPODClass f,
|
||||
const double g) { return *a + b + c.at(0) + d + e + f.value + g; }));
|
||||
|
||||
// test_method_vectorization
|
||||
struct VectorizeTestClass {
|
||||
VectorizeTestClass(int v) : value{v} {};
|
||||
float method(int x, float y) { return y + (float) (x + value); }
|
||||
float method(int x, float y) const { return y + (float) (x + value); }
|
||||
int value = 0;
|
||||
};
|
||||
py::class_<VectorizeTestClass> 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<int, py::array::forcecast> arg1,
|
||||
py::array_t<float, py::array::forcecast> arg2,
|
||||
py::array_t<double, py::array::forcecast> arg3
|
||||
) {
|
||||
py::ssize_t ndim;
|
||||
std::vector<py::ssize_t> shape;
|
||||
std::array<py::buffer_info, 3> buffers {{ arg1.request(), arg2.request(), arg3.request() }};
|
||||
return py::detail::broadcast(buffers, ndim, shape);
|
||||
});
|
||||
m.def("vectorized_is_trivial",
|
||||
[](const py::array_t<int, py::array::forcecast> &arg1,
|
||||
const py::array_t<float, py::array::forcecast> &arg2,
|
||||
const py::array_t<double, py::array::forcecast> &arg3) {
|
||||
py::ssize_t ndim = 0;
|
||||
std::vector<py::ssize_t> shape;
|
||||
std::array<py::buffer_info, 3> buffers{
|
||||
{arg1.request(), arg2.request(), arg3.request()}};
|
||||
return py::detail::broadcast(buffers, ndim, shape);
|
||||
});
|
||||
|
||||
m.def("add_to", py::vectorize([](NonPODClass& x, int a) { x.value += a; }));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// clang-format off
|
||||
/*
|
||||
tests/test_pickling.cpp -- pickle support
|
||||
|
||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
Copyright (c) 2021 The Pybind Development Team.
|
||||
|
||||
All rights reserved. Use of this source code is governed by a
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
|
@ -9,6 +11,58 @@
|
|||
|
||||
#include "pybind11_tests.h"
|
||||
|
||||
// clang-format on
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace exercise_trampoline {
|
||||
|
||||
struct SimpleBase {
|
||||
int num = 0;
|
||||
virtual ~SimpleBase() = default;
|
||||
|
||||
// For compatibility with old clang versions:
|
||||
SimpleBase() = default;
|
||||
SimpleBase(const SimpleBase &) = default;
|
||||
};
|
||||
|
||||
struct SimpleBaseTrampoline : SimpleBase {};
|
||||
|
||||
struct SimpleCppDerived : SimpleBase {};
|
||||
|
||||
void wrap(py::module m) {
|
||||
py::class_<SimpleBase, SimpleBaseTrampoline>(m, "SimpleBase")
|
||||
.def(py::init<>())
|
||||
.def_readwrite("num", &SimpleBase::num)
|
||||
.def(py::pickle(
|
||||
[](const py::object &self) {
|
||||
py::dict d;
|
||||
if (py::hasattr(self, "__dict__"))
|
||||
d = self.attr("__dict__");
|
||||
return py::make_tuple(self.attr("num"), d);
|
||||
},
|
||||
[](const py::tuple &t) {
|
||||
if (t.size() != 2)
|
||||
throw std::runtime_error("Invalid state!");
|
||||
auto cpp_state = std::unique_ptr<SimpleBase>(new SimpleBaseTrampoline);
|
||||
cpp_state->num = t[0].cast<int>();
|
||||
auto py_state = t[1].cast<py::dict>();
|
||||
return std::make_pair(std::move(cpp_state), py_state);
|
||||
}));
|
||||
|
||||
m.def("make_SimpleCppDerivedAsBase",
|
||||
[]() { return std::unique_ptr<SimpleBase>(new SimpleCppDerived); });
|
||||
m.def("check_dynamic_cast_SimpleCppDerived", [](const SimpleBase *base_ptr) {
|
||||
return dynamic_cast<const SimpleCppDerived *>(base_ptr) != nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace exercise_trampoline
|
||||
|
||||
// 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<std::string>());
|
||||
pyPickleable.def("__setstate__", [](Pickleable &p, const py::tuple &t) {
|
||||
if (t.size() != 3)
|
||||
throw std::runtime_error("Invalid state!");
|
||||
/* Invoke the constructor (need to use in-place version) */
|
||||
new (&p) Pickleable(t[0].cast<std::string>());
|
||||
|
||||
/* Assign any additional state */
|
||||
p.setExtra1(t[1].cast<int>());
|
||||
p.setExtra2(t[2].cast<int>());
|
||||
});
|
||||
/* Assign any additional state */
|
||||
p.setExtra1(t[1].cast<int>());
|
||||
p.setExtra2(t[2].cast<int>());
|
||||
});
|
||||
});
|
||||
|
||||
py::class_<PickleableNew, Pickleable>(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<std::string>());
|
||||
|
@ -73,8 +126,7 @@ TEST_SUBMODULE(pickling, m) {
|
|||
p.setExtra1(t[1].cast<int>());
|
||||
p.setExtra2(t[2].cast<int>());
|
||||
return p;
|
||||
}
|
||||
));
|
||||
}));
|
||||
|
||||
#if !defined(PYPY_VERSION)
|
||||
// test_roundtrip_with_dict
|
||||
|
@ -92,35 +144,33 @@ TEST_SUBMODULE(pickling, m) {
|
|||
};
|
||||
|
||||
py::class_<PickleableWithDict> pyPickleableWithDict(m, "PickleableWithDict", py::dynamic_attr());
|
||||
pyPickleableWithDict
|
||||
.def(py::init<std::string>())
|
||||
pyPickleableWithDict.def(py::init<std::string>())
|
||||
.def_readwrite("value", &PickleableWithDict::value)
|
||||
.def_readwrite("extra", &PickleableWithDict::extra)
|
||||
.def("__getstate__", [](py::object self) {
|
||||
.def("__getstate__", [](const py::object &self) {
|
||||
/* Also include __dict__ in state */
|
||||
return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__"));
|
||||
});
|
||||
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<PickleableWithDict&>();
|
||||
new (&p) PickleableWithDict(t[0].cast<std::string>());
|
||||
pyPickleableWithDict.def("__setstate__", [](const py::object &self, const py::tuple &t) {
|
||||
if (t.size() != 3)
|
||||
throw std::runtime_error("Invalid state!");
|
||||
/* Cast and construct */
|
||||
auto &p = self.cast<PickleableWithDict &>();
|
||||
new (&p) PickleableWithDict(t[0].cast<std::string>());
|
||||
|
||||
/* Assign C++ state */
|
||||
p.extra = t[1].cast<int>();
|
||||
/* Assign C++ state */
|
||||
p.extra = t[1].cast<int>();
|
||||
|
||||
/* Assign Python state */
|
||||
self.attr("__dict__") = t[2];
|
||||
});
|
||||
/* Assign Python state */
|
||||
self.attr("__dict__") = t[2];
|
||||
});
|
||||
});
|
||||
|
||||
py::class_<PickleableWithDictNew, PickleableWithDict>(m, "PickleableWithDictNew")
|
||||
.def(py::init<std::string>())
|
||||
.def(py::pickle(
|
||||
[](py::object self) {
|
||||
[](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<py::dict>();
|
||||
return std::make_pair(cpp_state, py_state);
|
||||
}
|
||||
));
|
||||
}));
|
||||
#endif
|
||||
|
||||
exercise_trampoline::wrap(m);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <utility>
|
||||
|
||||
#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<std::string>(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<T>() should be the same as T(obj)
|
||||
return py::dict(
|
||||
"bytes"_a=d["bytes"].cast<py::bytes>(),
|
||||
|
@ -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<py::bytes>(o); });
|
||||
m.def("isinstance_pybind11_str", [](py::object o) { return py::isinstance<py::str>(o); });
|
||||
m.def("isinstance_pybind11_bytes",
|
||||
[](py::object o) { return py::isinstance<py::bytes>(std::move(o)); });
|
||||
m.def("isinstance_pybind11_str",
|
||||
[](py::object o) { return py::isinstance<py::str>(std::move(o)); });
|
||||
|
||||
m.def("pass_to_pybind11_bytes", [](py::bytes b) { return py::len(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)); });
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <pybind11/stl.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
template<typename T>
|
||||
class NonZeroIterator {
|
||||
|
@ -80,18 +81,17 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
|
|||
int start,stop,step;
|
||||
int size;
|
||||
};
|
||||
py::class_<Sliceable>(m,"Sliceable")
|
||||
py::class_<Sliceable>(m, "Sliceable")
|
||||
.def(py::init<int>())
|
||||
.def("__getitem__",[](const Sliceable &s, py::slice slice) {
|
||||
py::ssize_t start, stop, step, slicelength;
|
||||
if (!slice.compute(s.size, &start, &stop, &step, &slicelength))
|
||||
throw py::error_already_set();
|
||||
int istart = static_cast<int>(start);
|
||||
int istop = static_cast<int>(stop);
|
||||
int istep = static_cast<int>(step);
|
||||
return std::make_tuple(istart,istop,istep);
|
||||
})
|
||||
;
|
||||
.def("__getitem__", [](const Sliceable &s, const py::slice &slice) {
|
||||
py::ssize_t start = 0, stop = 0, step = 0, slicelength = 0;
|
||||
if (!slice.compute(s.size, &start, &stop, &step, &slicelength))
|
||||
throw py::error_already_set();
|
||||
int istart = static_cast<int>(start);
|
||||
int istop = static_cast<int>(stop);
|
||||
int istep = static_cast<int>(step);
|
||||
return std::make_tuple(istart, istop, istep);
|
||||
});
|
||||
|
||||
// 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_<Sequence>(m, "Sequence")
|
||||
.def(py::init<size_t>())
|
||||
.def(py::init<const std::vector<float>&>())
|
||||
.def(py::init<const std::vector<float> &>())
|
||||
/// Bare bones interface
|
||||
.def("__getitem__", [](const Sequence &s, size_t i) {
|
||||
if (i >= s.size()) throw py::index_error();
|
||||
return s[i];
|
||||
})
|
||||
.def("__setitem__", [](Sequence &s, size_t i, float v) {
|
||||
if (i >= s.size()) throw py::index_error();
|
||||
s[i] = v;
|
||||
})
|
||||
.def("__getitem__",
|
||||
[](const Sequence &s, size_t i) {
|
||||
if (i >= s.size())
|
||||
throw py::index_error();
|
||||
return s[i];
|
||||
})
|
||||
.def("__setitem__",
|
||||
[](Sequence &s, size_t i, float v) {
|
||||
if (i >= s.size())
|
||||
throw py::index_error();
|
||||
s[i] = v;
|
||||
})
|
||||
.def("__len__", &Sequence::size)
|
||||
/// Optional sequence protocol operations
|
||||
.def("__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); },
|
||||
py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */)
|
||||
.def(
|
||||
"__iter__",
|
||||
[](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); },
|
||||
py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */)
|
||||
.def("__contains__", [](const Sequence &s, float v) { return s.contains(v); })
|
||||
.def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); })
|
||||
/// Slicing protocol (optional)
|
||||
.def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* {
|
||||
size_t start, stop, step, slicelength;
|
||||
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
|
||||
throw py::error_already_set();
|
||||
auto *seq = new Sequence(slicelength);
|
||||
for (size_t i = 0; i < slicelength; ++i) {
|
||||
(*seq)[i] = s[start]; start += step;
|
||||
}
|
||||
return seq;
|
||||
})
|
||||
.def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) {
|
||||
size_t start, stop, step, slicelength;
|
||||
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
|
||||
throw py::error_already_set();
|
||||
if (slicelength != value.size())
|
||||
throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
|
||||
for (size_t i = 0; i < slicelength; ++i) {
|
||||
s[start] = value[i]; start += step;
|
||||
}
|
||||
})
|
||||
.def("__getitem__",
|
||||
[](const Sequence &s, const py::slice &slice) -> Sequence * {
|
||||
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
||||
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
|
||||
throw py::error_already_set();
|
||||
auto *seq = new Sequence(slicelength);
|
||||
for (size_t i = 0; i < slicelength; ++i) {
|
||||
(*seq)[i] = s[start];
|
||||
start += step;
|
||||
}
|
||||
return seq;
|
||||
})
|
||||
.def("__setitem__",
|
||||
[](Sequence &s, const py::slice &slice, const Sequence &value) {
|
||||
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
||||
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
|
||||
throw py::error_already_set();
|
||||
if (slicelength != value.size())
|
||||
throw std::runtime_error(
|
||||
"Left and right hand size of slice assignment have different sizes!");
|
||||
for (size_t i = 0; i < slicelength; ++i) {
|
||||
s[start] = value[i];
|
||||
start += step;
|
||||
}
|
||||
})
|
||||
/// Comparisons
|
||||
.def(py::self == py::self)
|
||||
.def(py::self != py::self)
|
||||
|
@ -231,8 +242,8 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
|
|||
StringMap(std::unordered_map<std::string, std::string> init)
|
||||
: map(std::move(init)) {}
|
||||
|
||||
void set(std::string key, std::string val) { map[key] = val; }
|
||||
std::string get(std::string key) const { return map.at(key); }
|
||||
void set(const std::string &key, std::string val) { map[key] = std::move(val); }
|
||||
std::string get(const std::string &key) const { return map.at(key); }
|
||||
size_t size() const { return map.size(); }
|
||||
private:
|
||||
std::unordered_map<std::string, std::string> map;
|
||||
|
@ -243,19 +254,24 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
|
|||
py::class_<StringMap>(m, "StringMap")
|
||||
.def(py::init<>())
|
||||
.def(py::init<std::unordered_map<std::string, std::string>>())
|
||||
.def("__getitem__", [](const StringMap &map, std::string key) {
|
||||
try { return map.get(key); }
|
||||
catch (const std::out_of_range&) {
|
||||
throw py::key_error("key '" + key + "' does not exist");
|
||||
}
|
||||
})
|
||||
.def("__getitem__",
|
||||
[](const StringMap &map, const std::string &key) {
|
||||
try {
|
||||
return map.get(key);
|
||||
} catch (const std::out_of_range &) {
|
||||
throw py::key_error("key '" + key + "' does not exist");
|
||||
}
|
||||
})
|
||||
.def("__setitem__", &StringMap::set)
|
||||
.def("__len__", &StringMap::size)
|
||||
.def("__iter__", [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); },
|
||||
py::keep_alive<0, 1>())
|
||||
.def("items", [](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); },
|
||||
py::keep_alive<0, 1>())
|
||||
;
|
||||
.def(
|
||||
"__iter__",
|
||||
[](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); },
|
||||
py::keep_alive<0, 1>())
|
||||
.def(
|
||||
"items",
|
||||
[](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); },
|
||||
py::keep_alive<0, 1>());
|
||||
|
||||
// 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<py::handle, py::handle> p) {
|
||||
return p.second.cast<int>() != 0;
|
||||
});
|
||||
m.def("count_nonzeros", [](const py::dict &d) {
|
||||
return std::count_if(d.begin(), d.end(), [](std::pair<py::handle, py::handle> p) {
|
||||
return p.second.cast<int>() != 0;
|
||||
});
|
||||
});
|
||||
|
||||
m.def("tuple_iterator", &test_random_access_iterator<py::tuple>);
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -24,7 +24,7 @@ template <typename T> class huge_unique_ptr {
|
|||
std::unique_ptr<T> 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 *> myobject4_instances;
|
||||
std::unordered_set<MyObject4 *> myobject4_instances;
|
||||
class MyObject4 {
|
||||
public:
|
||||
MyObject4(int value) : value{value} {
|
||||
|
@ -127,7 +127,7 @@ private:
|
|||
// Object with std::unique_ptr<T, D> where D is not matching the base class
|
||||
// Object with a protected destructor
|
||||
class MyObject4a;
|
||||
static std::unordered_set<MyObject4a *> myobject4a_instances;
|
||||
std::unordered_set<MyObject4a *> 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> {
|
||||
B() { print_created(this); }
|
||||
B(const B &) : std::enable_shared_from_this<B>() { print_copy_created(this); }
|
||||
B(B &&) : std::enable_shared_from_this<B>() { print_move_created(this); }
|
||||
B(B &&) noexcept : std::enable_shared_from_this<B>() { 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<ElementBase> e) { l.push_back(e); }
|
||||
void add(const std::shared_ptr<ElementBase> &e) { l.push_back(e); }
|
||||
std::vector<std::shared_ptr<ElementBase>> 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<MyObject2>(7); });
|
||||
m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); });
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
m.def("print_myobject2_2", [](std::shared_ptr<MyObject2> obj) { py::print(obj->toString()); });
|
||||
m.def("print_myobject2_3", [](const std::shared_ptr<MyObject2> &obj) { py::print(obj->toString()); });
|
||||
m.def("print_myobject2_4", [](const std::shared_ptr<MyObject2> *obj) { py::print((*obj)->toString()); });
|
||||
|
@ -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<MyObject3>(9); });
|
||||
m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); });
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
m.def("print_myobject3_2", [](std::shared_ptr<MyObject3> obj) { py::print(obj->toString()); });
|
||||
m.def("print_myobject3_3", [](const std::shared_ptr<MyObject3> &obj) { py::print(obj->toString()); });
|
||||
m.def("print_myobject3_4", [](const std::shared_ptr<MyObject3> *obj) { py::print((*obj)->toString()); });
|
||||
|
@ -358,12 +362,15 @@ TEST_SUBMODULE(smart_ptr, m) {
|
|||
py::class_<SharedPtrRef, std::unique_ptr<SharedPtrRef>>(m, "SharedPtrRef")
|
||||
.def(py::init<>())
|
||||
.def_readonly("ref", &SharedPtrRef::value)
|
||||
.def_property_readonly("copy", [](const SharedPtrRef &s) { return s.value; },
|
||||
py::return_value_policy::copy)
|
||||
.def_property_readonly(
|
||||
"copy", [](const SharedPtrRef &s) { return s.value; }, py::return_value_policy::copy)
|
||||
.def_readonly("holder_ref", &SharedPtrRef::shared)
|
||||
.def_property_readonly("holder_copy", [](const SharedPtrRef &s) { return s.shared; },
|
||||
py::return_value_policy::copy)
|
||||
.def_property_readonly(
|
||||
"holder_copy",
|
||||
[](const SharedPtrRef &s) { return s.shared; },
|
||||
py::return_value_policy::copy)
|
||||
.def("set_ref", [](SharedPtrRef &, const A &) { return true; })
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
.def("set_holder", [](SharedPtrRef &, std::shared_ptr<A>) { return true; });
|
||||
|
||||
// test_shared_ptr_from_this_and_references
|
||||
|
@ -372,13 +379,19 @@ TEST_SUBMODULE(smart_ptr, m) {
|
|||
py::class_<SharedFromThisRef, std::unique_ptr<SharedFromThisRef>>(m, "SharedFromThisRef")
|
||||
.def(py::init<>())
|
||||
.def_readonly("bad_wp", &SharedFromThisRef::value)
|
||||
.def_property_readonly("ref", [](const SharedFromThisRef &s) -> const B & { return *s.shared; })
|
||||
.def_property_readonly("copy", [](const SharedFromThisRef &s) { return s.value; },
|
||||
py::return_value_policy::copy)
|
||||
.def_property_readonly("ref",
|
||||
[](const SharedFromThisRef &s) -> const B & { return *s.shared; })
|
||||
.def_property_readonly(
|
||||
"copy",
|
||||
[](const SharedFromThisRef &s) { return s.value; },
|
||||
py::return_value_policy::copy)
|
||||
.def_readonly("holder_ref", &SharedFromThisRef::shared)
|
||||
.def_property_readonly("holder_copy", [](const SharedFromThisRef &s) { return s.shared; },
|
||||
py::return_value_policy::copy)
|
||||
.def_property_readonly(
|
||||
"holder_copy",
|
||||
[](const SharedFromThisRef &s) { return s.shared; },
|
||||
py::return_value_policy::copy)
|
||||
.def("set_ref", [](SharedFromThisRef &, const B &) { return true; })
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
.def("set_holder", [](SharedFromThisRef &, std::shared_ptr<B>) { return true; });
|
||||
|
||||
// Issue #865: shared_from_this doesn't work with virtual inheritance
|
||||
|
@ -396,10 +409,14 @@ TEST_SUBMODULE(smart_ptr, m) {
|
|||
py::class_<TypeForHolderWithAddressOf, HolderWithAddressOf>(m, "TypeForHolderWithAddressOf")
|
||||
.def_static("make", []() { return HolderWithAddressOf(new TypeForHolderWithAddressOf); })
|
||||
.def("get", [](const HolderWithAddressOf &self) { return self.get(); })
|
||||
.def("print_object_1", [](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); })
|
||||
.def("print_object_1",
|
||||
[](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); })
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
.def("print_object_2", [](HolderWithAddressOf obj) { py::print(obj.get()->toString()); })
|
||||
.def("print_object_3", [](const HolderWithAddressOf &obj) { py::print(obj.get()->toString()); })
|
||||
.def("print_object_4", [](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); });
|
||||
.def("print_object_3",
|
||||
[](const HolderWithAddressOf &obj) { py::print(obj.get()->toString()); })
|
||||
.def("print_object_4",
|
||||
[](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); });
|
||||
|
||||
// test_move_only_holder_with_addressof_operator
|
||||
using MoveOnlyHolderWithAddressOf = unique_ptr_with_addressof_operator<TypeForMoveOnlyHolderWithAddressOf>;
|
||||
|
@ -411,6 +428,7 @@ TEST_SUBMODULE(smart_ptr, m) {
|
|||
// test_smart_ptr_from_default
|
||||
py::class_<HeldByDefaultHolder, std::unique_ptr<HeldByDefaultHolder>>(m, "HeldByDefaultHolder")
|
||||
.def(py::init<>())
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
.def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {});
|
||||
|
||||
// test_shared_ptr_gc
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
#include "constructor_stats.h"
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
#ifndef PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL
|
||||
#define PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL
|
||||
#endif
|
||||
#include <pybind11/stl/filesystem.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
@ -97,7 +102,7 @@ TEST_SUBMODULE(stl, m) {
|
|||
// test_set
|
||||
m.def("cast_set", []() { return std::set<std::string>{"key1", "key2"}; });
|
||||
m.def("load_set", [](const std::set<std::string> &set) {
|
||||
return set.count("key1") && set.count("key2") && set.count("key3");
|
||||
return (set.count("key1") != 0u) && (set.count("key2") != 0u) && (set.count("key3") != 0u);
|
||||
});
|
||||
|
||||
// test_recursive_casting
|
||||
|
@ -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<int>) { return true; });
|
||||
m.def("nodefer_none_optional", [](py::none) { return false; });
|
||||
m.def("nodefer_none_optional", [](const py::none &) { return false; });
|
||||
|
||||
using opt_holder = OptionalHolder<std::optional, MoveOutDetector>;
|
||||
py::class_<opt_holder>(m, "OptionalHolder", "Class with optional member")
|
||||
|
@ -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<py::detail::variant_caster_visitor::result_type, py::handle>::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<int, std::string, double, std::nullptr_t> v) {
|
||||
m.def("load_variant", [](const variant<int, std::string, double, std::nullptr_t> &v) {
|
||||
return py::detail::visit_helper<variant>::call(visitor(), v);
|
||||
});
|
||||
m.def("load_variant_2pass", [](variant<double, int> v) {
|
||||
|
@ -287,9 +296,11 @@ TEST_SUBMODULE(stl, m) {
|
|||
m.def("stl_pass_by_pointer", [](std::vector<int>* v) { return *v; }, "v"_a=nullptr);
|
||||
|
||||
// #1258: pybind11/stl.h converts string to vector<string>
|
||||
m.def("func_with_string_or_vector_string_arg_overload", [](std::vector<std::string>) { return 1; });
|
||||
m.def("func_with_string_or_vector_string_arg_overload", [](std::list<std::string>) { return 2; });
|
||||
m.def("func_with_string_or_vector_string_arg_overload", [](std::string) { return 3; });
|
||||
m.def("func_with_string_or_vector_string_arg_overload",
|
||||
[](const std::vector<std::string> &) { return 1; });
|
||||
m.def("func_with_string_or_vector_string_arg_overload",
|
||||
[](const std::list<std::string> &) { return 2; });
|
||||
m.def("func_with_string_or_vector_string_arg_overload", [](const std::string &) { return 3; });
|
||||
|
||||
class Placeholder {
|
||||
public:
|
||||
|
@ -321,4 +332,10 @@ TEST_SUBMODULE(stl, m) {
|
|||
py::class_<Issue1561Outer>(m, "Issue1561Outer")
|
||||
.def(py::init<>())
|
||||
.def_readwrite("list", &Issue1561Outer::list);
|
||||
|
||||
m.def(
|
||||
"return_vector_bool_raw_ptr",
|
||||
[]() { return new std::vector<bool>(4513); },
|
||||
// Without explicitly specifying `take_ownership`, this function leaks.
|
||||
py::return_value_policy::take_ownership);
|
||||
}
|
||||
|
|
|
@ -162,6 +162,25 @@ def test_exp_optional():
|
|||
assert holder.member_initialized()
|
||||
|
||||
|
||||
@pytest.mark.skipif(not hasattr(m, "has_filesystem"), reason="no <filesystem>")
|
||||
def test_fs_path():
|
||||
from pathlib import Path
|
||||
|
||||
class PseudoStrPath:
|
||||
def __fspath__(self):
|
||||
return "foo/bar"
|
||||
|
||||
class PseudoBytesPath:
|
||||
def __fspath__(self):
|
||||
return b"foo/bar"
|
||||
|
||||
assert m.parent_path(Path("foo/bar")) == Path("foo")
|
||||
assert m.parent_path("foo/bar") == Path("foo")
|
||||
assert m.parent_path(b"foo/bar") == Path("foo")
|
||||
assert m.parent_path(PseudoStrPath()) == Path("foo")
|
||||
assert m.parent_path(PseudoBytesPath()) == Path("foo")
|
||||
|
||||
|
||||
@pytest.mark.skipif(not hasattr(m, "load_variant"), reason="no <variant>")
|
||||
def test_variant(doc):
|
||||
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
|
||||
|
|
|
@ -125,5 +125,7 @@ TEST_SUBMODULE(stl_binders, m) {
|
|||
PYBIND11_NUMPY_DTYPE(VStruct, w, x, y, z);
|
||||
py::class_<VStruct>(m, "VStruct").def_readwrite("x", &VStruct::x);
|
||||
py::bind_vector<std::vector<VStruct>>(m, "VectorStruct", py::buffer_protocol());
|
||||
m.def("get_vectorstruct", [] {return std::vector<VStruct> {{0, 5, 3.0, 1}, {1, 30, -1e4, 0}};});
|
||||
m.def("get_vectorstruct", [] {
|
||||
return std::vector<VStruct>{{false, 5, 3.0, true}, {true, 30, -1e4, false}};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}")
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 ";$<$<CONFIG:MinSizeRel>:-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()
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ This module defines the following commands to assist with creating Python module
|
|||
|
||||
pybind11_add_module(<target>
|
||||
[STATIC|SHARED|MODULE]
|
||||
[THIN_LTO] [OPT_SIZE] [NO_EXTRAS] [WITHOUT_SOBAI]
|
||||
[THIN_LTO] [OPT_SIZE] [NO_EXTRAS] [WITHOUT_SOABI]
|
||||
<files>...
|
||||
)
|
||||
|
||||
|
@ -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)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue