Merge branch 'master' into sh_merge_master

This commit is contained in:
Ralf W. Grosse-Kunstleve 2024-03-27 17:06:50 -07:00
commit 826f615365
34 changed files with 668 additions and 71 deletions

View File

@ -109,12 +109,15 @@ jobs:
run: python -m pip install pytest-github-actions-annotate-failures run: python -m pip install pytest-github-actions-annotate-failures
# First build - C++11 mode and inplace # First build - C++11 mode and inplace
# More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON here. # More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON here
# (same for PYBIND11_NUMPY_1_ONLY, but requires a NumPy 1.x at runtime).
- name: Configure C++11 ${{ matrix.args }} - name: Configure C++11 ${{ matrix.args }}
run: > run: >
cmake -S . -B . cmake -S . -B .
-DPYBIND11_WERROR=ON -DPYBIND11_WERROR=ON
-DPYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION=ON
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON
-DPYBIND11_NUMPY_1_ONLY=ON
-DDOWNLOAD_CATCH=ON -DDOWNLOAD_CATCH=ON
-DDOWNLOAD_EIGEN=ON -DDOWNLOAD_EIGEN=ON
-DCMAKE_CXX_STANDARD=11 -DCMAKE_CXX_STANDARD=11
@ -139,11 +142,13 @@ jobs:
# Second build - C++17 mode and in a build directory # Second build - C++17 mode and in a build directory
# More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF here. # More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF here.
# (same for PYBIND11_NUMPY_1_ONLY, but requires a NumPy 1.x at runtime).
- name: Configure C++17 - name: Configure C++17
run: > run: >
cmake -S . -B build2 cmake -S . -B build2
-DPYBIND11_WERROR=ON -DPYBIND11_WERROR=ON
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF
-DPYBIND11_NUMPY_1_ONLY=ON
-DDOWNLOAD_CATCH=ON -DDOWNLOAD_CATCH=ON
-DDOWNLOAD_EIGEN=ON -DDOWNLOAD_EIGEN=ON
-DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD=17
@ -661,6 +666,11 @@ jobs:
run: | run: |
python3 -m pip install cmake -r tests/requirements.txt python3 -m pip install cmake -r tests/requirements.txt
- name: Ensure NumPy 2 is used (required Python >= 3.9)
if: matrix.container == 'almalinux:9'
run: |
python3 -m pip install 'numpy>=2.0.0b1' 'scipy>=1.13.0rc1'
- name: Configure - name: Configure
shell: bash shell: bash
run: > run: >
@ -896,8 +906,10 @@ jobs:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
- name: Prepare env - name: Prepare env
# Ensure use of NumPy 2 (via NumPy nightlies but can be changed soon)
run: | run: |
python3 -m pip install -r tests/requirements.txt python3 -m pip install -r tests/requirements.txt
python3 -m pip install 'numpy>=2.0.0b1' 'scipy>=1.13.0rc1'
- name: Update CMake - name: Update CMake
uses: jwlawson/actions-setup-cmake@v2.0 uses: jwlawson/actions-setup-cmake@v2.0

View File

@ -14,7 +14,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/labeler@main - uses: actions/labeler@v4
if: > if: >
github.event.pull_request.merged == true && github.event.pull_request.merged == true &&
!startsWith(github.event.pull_request.title, 'chore(deps):') && !startsWith(github.event.pull_request.title, 'chore(deps):') &&

View File

@ -107,15 +107,25 @@ endif()
option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT}) option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT})
option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT}) option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT})
option(PYBIND11_NOPYTHON "Disable search for Python" OFF) option(PYBIND11_NOPYTHON "Disable search for Python" OFF)
option(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION
"To enforce that a handle_type_name<> specialization exists" OFF)
option(PYBIND11_SIMPLE_GIL_MANAGEMENT option(PYBIND11_SIMPLE_GIL_MANAGEMENT
"Use simpler GIL management logic that does not support disassociation" OFF) "Use simpler GIL management logic that does not support disassociation" OFF)
option(PYBIND11_NUMPY_1_ONLY
"Disable NumPy 2 support to avoid changes to previous pybind11 versions." OFF)
set(PYBIND11_INTERNALS_VERSION set(PYBIND11_INTERNALS_VERSION
"" ""
CACHE STRING "Override the ABI version, may be used to enable the unstable ABI.") CACHE STRING "Override the ABI version, may be used to enable the unstable ABI.")
if(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION)
add_compile_definitions(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION)
endif()
if(PYBIND11_SIMPLE_GIL_MANAGEMENT) if(PYBIND11_SIMPLE_GIL_MANAGEMENT)
add_compile_definitions(PYBIND11_SIMPLE_GIL_MANAGEMENT) add_compile_definitions(PYBIND11_SIMPLE_GIL_MANAGEMENT)
endif() endif()
if(PYBIND11_NUMPY_1_ONLY)
add_compile_definitions(PYBIND11_NUMPY_1_ONLY)
endif()
cmake_dependent_option( cmake_dependent_option(
USE_PYTHON_INCLUDE_DIR USE_PYTHON_INCLUDE_DIR

View File

@ -40,10 +40,10 @@ with everything stripped away that isn't relevant for binding
generation. Without comments, the core header files only require ~4K generation. Without comments, the core header files only require ~4K
lines of code and depend on Python (3.6+, or PyPy) and the C++ lines of code and depend on Python (3.6+, or PyPy) and the C++
standard library. This compact implementation was possible thanks to standard library. This compact implementation was possible thanks to
some of the new C++11 language features (specifically: tuples, lambda some C++11 language features (specifically: tuples, lambda functions and
functions and variadic templates). Since its creation, this library has variadic templates). Since its creation, this library has grown beyond
grown beyond Boost.Python in many ways, leading to dramatically simpler Boost.Python in many ways, leading to dramatically simpler binding code in many
binding code in many common situations. common situations.
Tutorial and reference documentation is provided at Tutorial and reference documentation is provided at
`pybind11.readthedocs.io <https://pybind11.readthedocs.io/en/latest>`_. `pybind11.readthedocs.io <https://pybind11.readthedocs.io/en/latest>`_.
@ -75,6 +75,7 @@ pybind11 can map the following core C++ features to Python:
- Internal references with correct reference counting - Internal references with correct reference counting
- C++ classes with virtual (and pure virtual) methods can be extended - C++ classes with virtual (and pure virtual) methods can be extended
in Python in Python
- Integrated NumPy support (NumPy 2 requires pybind11 2.12+)
Goodies Goodies
------- -------

View File

@ -15,9 +15,183 @@ IN DEVELOPMENT
Changes will be summarized here periodically. Changes will be summarized here periodically.
Version 2.12.0 (March 27, 2025)
-------------------------------
New Features:
* ``pybind11`` now supports compiling for
`NumPy 2 <https://numpy.org/devdocs/numpy_2_0_migration_guide.html>`_. Most
code shouldn't change (see :ref:`upgrade-guide-2.12` for details). However,
if you experience issues you can define ``PYBIND11_NUMPY_1_ONLY`` to disable
the new support for now, but this will be removed in the future.
`#5050 <https://github.com/pybind/pybind11/pull/5050>`_
* ``pybind11/gil_safe_call_once.h`` was added (it needs to be included
explicitly). The primary use case is GIL-safe initialization of C++
``static`` variables.
`#4877 <https://github.com/pybind/pybind11/pull/4877>`_
* Support move-only iterators in ``py::make_iterator``,
``py::make_key_iterator``, ``py::make_value_iterator``.
`#4834 <https://github.com/pybind/pybind11/pull/4834>`_
* Two simple ``py::set_error()`` functions were added and the documentation was
updated accordingly. In particular, ``py::exception<>::operator()`` was
deprecated (use one of the new functions instead). The documentation for
``py::exception<>`` was further updated to not suggest code that may result
in undefined behavior.
`#4772 <https://github.com/pybind/pybind11/pull/4772>`_
Bug fixes:
* Removes potential for Undefined Behavior during process teardown.
`#4897 <https://github.com/pybind/pybind11/pull/4897>`_
* Improve compatibility with the nvcc compiler (especially CUDA 12.1/12.2).
`#4893 <https://github.com/pybind/pybind11/pull/4893>`_
* ``pybind11/numpy.h`` now imports NumPy's ``multiarray`` and ``_internal``
submodules with paths depending on the installed version of NumPy (for
compatibility with NumPy 2).
`#4857 <https://github.com/pybind/pybind11/pull/4857>`_
* Builtins collections names in docstrings are now consistently rendered in
lowercase (list, set, dict, tuple), in accordance with PEP 585.
`#4833 <https://github.com/pybind/pybind11/pull/4833>`_
* Added ``py::typing::Iterator<T>``, ``py::typing::Iterable<T>``.
`#4832 <https://github.com/pybind/pybind11/pull/4832>`_
* Render ``py::function`` as ``Callable`` in docstring.
`#4829 <https://github.com/pybind/pybind11/pull/4829>`_
* Also bump ``PYBIND11_INTERNALS_VERSION`` for MSVC, which unlocks two new
features without creating additional incompatibilities.
`#4819 <https://github.com/pybind/pybind11/pull/4819>`_
* Guard against crashes/corruptions caused by modules built with different MSVC
versions.
`#4779 <https://github.com/pybind/pybind11/pull/4779>`_
* A long-standing bug in the handling of Python multiple inheritance was fixed.
See PR #4762 for the rather complex details.
`#4762 <https://github.com/pybind/pybind11/pull/4762>`_
* Fix ``bind_map`` with ``using`` declarations.
`#4952 <https://github.com/pybind/pybind11/pull/4952>`_
* Qualify ``py::detail::concat`` usage to avoid ADL selecting one from
somewhere else, such as modernjson's concat.
`#4955 <https://github.com/pybind/pybind11/pull/4955>`_
* Use new PyCode API on Python 3.12+.
`#4916 <https://github.com/pybind/pybind11/pull/4916>`_
* Minor cleanup from warnings reported by Clazy.
`#4988 <https://github.com/pybind/pybind11/pull/4988>`_
* Remove typing and duplicate ``class_`` for ``KeysView``/``ValuesView``/``ItemsView``.
`#4985 <https://github.com/pybind/pybind11/pull/4985>`_
* Use ``PyObject_VisitManagedDict()`` and ``PyObject_ClearManagedDict()`` on Python 3.13 and newer.
`#4973 <https://github.com/pybind/pybind11/pull/4973>`_
* Update ``make_static_property_type()`` to make it compatible with Python 3.13.
`#4971 <https://github.com/pybind/pybind11/pull/4971>`_
.. fix(types)
* Render typed iterators for ``make_iterator``, ``make_key_iterator``,
``make_value_iterator``.
`#4876 <https://github.com/pybind/pybind11/pull/4876>`_
* Add several missing type name specializations.
`#5073 <https://github.com/pybind/pybind11/pull/5073>`_
* Change docstring render for ``py::buffer``, ``py::sequence`` and
``py::handle`` (to ``Buffer``, ``Sequence``, ``Any``).
`#4831 <https://github.com/pybind/pybind11/pull/4831>`_
* Fixed ``base_enum.__str__`` docstring.
`#4827 <https://github.com/pybind/pybind11/pull/4827>`_
* Enforce single line docstring signatures.
`#4735 <https://github.com/pybind/pybind11/pull/4735>`_
* Special 'typed' wrappers now available in ``typing.h`` to annotate tuple, dict,
list, set, and function.
`#4259 <https://github.com/pybind/pybind11/pull/4259>`_
* Create ``handle_type_name`` specialization to type-hint variable length tuples.
`#5051 <https://github.com/pybind/pybind11/pull/5051>`_
.. fix(build)
* Setting ``PYBIND11_FINDPYTHON`` to OFF will force the old FindPythonLibs mechanism to be used.
`#5042 <https://github.com/pybind/pybind11/pull/5042>`_
* Skip empty ``PYBIND11_PYTHON_EXECUTABLE_LAST`` for the first cmake run.
`#4856 <https://github.com/pybind/pybind11/pull/4856>`_
* Fix FindPython mode exports & avoid ``pkg_resources`` if
``importlib.metadata`` available.
`#4941 <https://github.com/pybind/pybind11/pull/4941>`_
* ``Python_ADDITIONAL_VERSIONS`` (classic search) now includes 3.12.
`#4909 <https://github.com/pybind/pybind11/pull/4909>`_
* ``pybind11.pc`` is now relocatable by default as long as install destinations
are not absolute paths.
`#4830 <https://github.com/pybind/pybind11/pull/4830>`_
* Correctly detect CMake FindPython removal when used as a subdirectory.
`#4806 <https://github.com/pybind/pybind11/pull/4806>`_
* Don't require the libs component on CMake 3.18+ when using
PYBIND11_FINDPYTHON (fixes manylinux builds).
`#4805 <https://github.com/pybind/pybind11/pull/4805>`_
* ``pybind11_strip`` is no longer automatically applied when
``CMAKE_BUILD_TYPE`` is unset.
`#4780 <https://github.com/pybind/pybind11/pull/4780>`_
* Support ``DEBUG_POSFIX`` correctly for debug builds.
`#4761 <https://github.com/pybind/pybind11/pull/4761>`_
* Hardcode lto/thin lto for Emscripten cross-compiles.
`#4642 <https://github.com/pybind/pybind11/pull/4642>`_
* Upgrade maximum supported CMake version to 3.27 to fix CMP0148 warnings.
`#4786 <https://github.com/pybind/pybind11/pull/4786>`_
Documentation:
* Small fix to grammar in ``functions.rst``.
`#4791 <https://github.com/pybind/pybind11/pull/4791>`_
* Remove upper bound in example pyproject.toml for setuptools.
`#4774 <https://github.com/pybind/pybind11/pull/4774>`_
CI:
* CI: Update NVHPC to 23.5 and Ubuntu 20.04.
`#4764 <https://github.com/pybind/pybind11/pull/4764>`_
* Test on PyPy 3.10.
`#4714 <https://github.com/pybind/pybind11/pull/4714>`_
Other:
* Use Ruff formatter instead of Black.
`#4912 <https://github.com/pybind/pybind11/pull/4912>`_
* An ``assert()`` was added to help Coverty avoid generating a false positive.
`#4817 <https://github.com/pybind/pybind11/pull/4817>`_
Version 2.11.1 (July 17, 2023) Version 2.11.1 (July 17, 2023)
----------------------------- ------------------------------
Changes: Changes:
@ -32,7 +206,7 @@ Changes:
Version 2.11.0 (July 14, 2023) Version 2.11.0 (July 14, 2023)
----------------------------- ------------------------------
New features: New features:

View File

@ -36,19 +36,19 @@ If you don't have nox, you should either use ``pipx run nox`` instead, or use
- Run ``nox -s tests_packaging`` to ensure this was done correctly. - Run ``nox -s tests_packaging`` to ensure this was done correctly.
- Ensure that all the information in ``setup.cfg`` is up-to-date, like - Ensure that all the information in ``setup.cfg`` is up-to-date, like
supported Python versions. supported Python versions.
- Add release date in ``docs/changelog.rst`` and integrate the output of - Add release date in ``docs/changelog.rst`` and integrate the output of
``nox -s make_changelog``. ``nox -s make_changelog``.
- Note that the ``make_changelog`` command inspects - Note that the ``nox -s make_changelog`` command inspects
`needs changelog <https://github.com/pybind/pybind11/pulls?q=is%3Apr+is%3Aclosed+label%3A%22needs+changelog%22>`_. `needs changelog <https://github.com/pybind/pybind11/pulls?q=is%3Apr+is%3Aclosed+label%3A%22needs+changelog%22>`_.
- Manually clear the ``needs changelog`` labels using the GitHub web - Manually clear the ``needs changelog`` labels using the GitHub web
interface (very easy: start by clicking the link above). interface (very easy: start by clicking the link above).
- ``git add`` and ``git commit``, ``git push``. **Ensure CI passes**. (If it - ``git add`` and ``git commit``, ``git push``. **Ensure CI passes**. (If it
fails due to a known flake issue, either ignore or restart CI.) 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 - Add a release branch if this is a new MINOR version, or update the existing

View File

@ -8,6 +8,34 @@ to a new version. But it goes into more detail. This includes things like
deprecated APIs and their replacements, build system changes, general code deprecated APIs and their replacements, build system changes, general code
modernization and other useful information. modernization and other useful information.
.. _upgrade-guide-2.12:
v2.12
=====
NumPy support has been upgraded to support the 2.x series too. The two relevant
changes are that:
* ``dtype.flags()`` is now a ``uint64`` and ``dtype.alignment()`` an
``ssize_t`` (and NumPy may return an larger than integer value for
``itemsize()`` in NumPy 2.x).
* The long deprecated NumPy function ``PyArray_GetArrayParamsFromObject``
function is not available anymore.
Due to NumPy changes, you may experience difficulties updating to NumPy 2.
Please see the [NumPy 2 migration guide](https://numpy.org/devdocs/numpy_2_0_migration_guide.html) for details.
For example, a more direct change could be that the default integer ``"int_"``
(and ``"uint"``) is now ``ssize_t`` and not ``long`` (affects 64bit windows).
If you want to only support NumPy 1.x for now and are having problems due to
the two internal changes listed above, you can define
``PYBIND11_NUMPY_1_ONLY`` to disable the new support for now. Make sure you
define this on all pybind11 compile units, since it could be a source of ODR
violations if used inconsistently. This option will be removed in the future,
so adapting your code is highly recommended.
.. _upgrade-guide-2.11: .. _upgrade-guide-2.11:
v2.11 v2.11

View File

@ -357,8 +357,9 @@ public:
value = false; value = false;
return true; return true;
} }
if (convert || (std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name) == 0)) { if (convert || is_numpy_bool(src)) {
// (allow non-implicit conversion for numpy booleans) // (allow non-implicit conversion for numpy booleans), use strncmp
// since NumPy 1.x had an additional trailing underscore.
Py_ssize_t res = -1; Py_ssize_t res = -1;
if (src.is_none()) { if (src.is_none()) {
@ -390,6 +391,15 @@ public:
return handle(src ? Py_True : Py_False).inc_ref(); return handle(src ? Py_True : Py_False).inc_ref();
} }
PYBIND11_TYPE_CASTER(bool, const_name("bool")); PYBIND11_TYPE_CASTER(bool, const_name("bool"));
private:
// Test if an object is a NumPy boolean (without fetching the type).
static inline bool is_numpy_bool(handle object) {
const char *type_name = Py_TYPE(object.ptr())->tp_name;
// Name changed to `numpy.bool` in NumPy 2, `numpy.bool_` is needed for 1.x support
return std::strcmp("numpy.bool", type_name) == 0
|| std::strcmp("numpy.bool_", type_name) == 0;
}
}; };
// Helper class for UTF-{8,16,32} C++ stl strings: // Helper class for UTF-{8,16,32} C++ stl strings:
@ -696,8 +706,9 @@ public:
return cast(*src, policy, parent); return cast(*src, policy, parent);
} }
static constexpr auto name static constexpr auto name = const_name("tuple[")
= const_name("tuple[") + concat(make_caster<Ts>::name...) + const_name("]"); + ::pybind11::detail::concat(make_caster<Ts>::name...)
+ const_name("]");
template <typename T> template <typename T>
using cast_op_type = type; using cast_op_type = type;
@ -909,10 +920,53 @@ struct is_holder_type
template <typename base, typename deleter> template <typename base, typename deleter>
struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {}; struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {};
#ifdef PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION // See PR #4888
// This leads to compilation errors if a specialization is missing.
template <typename T>
struct handle_type_name;
#else
template <typename T> template <typename T>
struct handle_type_name { struct handle_type_name {
static constexpr auto name = const_name<T>(); static constexpr auto name = const_name<T>();
}; };
#endif
template <>
struct handle_type_name<object> {
static constexpr auto name = const_name("object");
};
template <>
struct handle_type_name<list> {
static constexpr auto name = const_name("list");
};
template <>
struct handle_type_name<dict> {
static constexpr auto name = const_name("dict");
};
template <>
struct handle_type_name<anyset> {
static constexpr auto name = const_name("Union[set, frozenset]");
};
template <>
struct handle_type_name<set> {
static constexpr auto name = const_name("set");
};
template <>
struct handle_type_name<frozenset> {
static constexpr auto name = const_name("frozenset");
};
template <>
struct handle_type_name<str> {
static constexpr auto name = const_name("str");
};
template <>
struct handle_type_name<tuple> {
static constexpr auto name = const_name("tuple");
};
template <> template <>
struct handle_type_name<bool_> { struct handle_type_name<bool_> {
static constexpr auto name = const_name("bool"); static constexpr auto name = const_name("bool");
@ -958,6 +1012,34 @@ struct handle_type_name<sequence> {
static constexpr auto name = const_name("Sequence"); static constexpr auto name = const_name("Sequence");
}; };
template <> template <>
struct handle_type_name<bytearray> {
static constexpr auto name = const_name("bytearray");
};
template <>
struct handle_type_name<memoryview> {
static constexpr auto name = const_name("memoryview");
};
template <>
struct handle_type_name<slice> {
static constexpr auto name = const_name("slice");
};
template <>
struct handle_type_name<type> {
static constexpr auto name = const_name("type");
};
template <>
struct handle_type_name<capsule> {
static constexpr auto name = const_name("capsule");
};
template <>
struct handle_type_name<ellipsis> {
static constexpr auto name = const_name("ellipsis");
};
template <>
struct handle_type_name<weakref> {
static constexpr auto name = const_name("weakref");
};
template <>
struct handle_type_name<args> { struct handle_type_name<args> {
static constexpr auto name = const_name("*args"); static constexpr auto name = const_name("*args");
}; };
@ -965,6 +1047,30 @@ template <>
struct handle_type_name<kwargs> { struct handle_type_name<kwargs> {
static constexpr auto name = const_name("**kwargs"); static constexpr auto name = const_name("**kwargs");
}; };
template <>
struct handle_type_name<obj_attr_accessor> {
static constexpr auto name = const_name<obj_attr_accessor>();
};
template <>
struct handle_type_name<str_attr_accessor> {
static constexpr auto name = const_name<str_attr_accessor>();
};
template <>
struct handle_type_name<item_accessor> {
static constexpr auto name = const_name<item_accessor>();
};
template <>
struct handle_type_name<sequence_accessor> {
static constexpr auto name = const_name<sequence_accessor>();
};
template <>
struct handle_type_name<list_accessor> {
static constexpr auto name = const_name<list_accessor>();
};
template <>
struct handle_type_name<tuple_accessor> {
static constexpr auto name = const_name<tuple_accessor>();
};
template <typename type> template <typename type>
struct pyobject_caster { struct pyobject_caster {
@ -1506,7 +1612,8 @@ public:
static_assert(args_pos == -1 || args_pos == constexpr_first<argument_is_args, Args...>(), static_assert(args_pos == -1 || args_pos == constexpr_first<argument_is_args, Args...>(),
"py::args cannot be specified more than once"); "py::args cannot be specified more than once");
static constexpr auto arg_names = concat(type_descr(make_caster<Args>::name)...); static constexpr auto arg_names
= ::pybind11::detail::concat(type_descr(make_caster<Args>::name)...);
bool load_args(function_call &call) { return load_impl_sequence(call, indices{}); } bool load_args(function_call &call) { return load_impl_sequence(call, indices{}); }

View File

@ -10,12 +10,12 @@
#pragma once #pragma once
#define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MAJOR 2
#define PYBIND11_VERSION_MINOR 12 #define PYBIND11_VERSION_MINOR 13
#define PYBIND11_VERSION_PATCH 0.dev1 #define PYBIND11_VERSION_PATCH 0.dev1
// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html // Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html
// Additional convention: 0xD = dev // Additional convention: 0xD = dev
#define PYBIND11_VERSION_HEX 0x020C00D1 #define PYBIND11_VERSION_HEX 0x020D00D1
// Define some generic pybind11 helper macros for warning management. // Define some generic pybind11 helper macros for warning management.
// //
@ -296,6 +296,10 @@ PYBIND11_WARNING_DISABLE_MSVC(4505)
# undef copysign # undef copysign
#endif #endif
#if defined(PYBIND11_NUMPY_1_ONLY)
# define PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED
#endif
#if defined(PYPY_VERSION) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) #if defined(PYPY_VERSION) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
# define PYBIND11_SIMPLE_GIL_MANAGEMENT # define PYBIND11_SIMPLE_GIL_MANAGEMENT
#endif #endif

View File

@ -68,9 +68,14 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
// `Py_LIMITED_API` anyway. // `Py_LIMITED_API` anyway.
# if PYBIND11_INTERNALS_VERSION > 4 # if PYBIND11_INTERNALS_VERSION > 4
# define PYBIND11_TLS_KEY_REF Py_tss_t & # define PYBIND11_TLS_KEY_REF Py_tss_t &
# if defined(__GNUC__) && !defined(__INTEL_COMPILER) # if defined(__clang__)
// Clang on macOS warns due to `Py_tss_NEEDS_INIT` not specifying an initializer # define PYBIND11_TLS_KEY_INIT(var) \
// for every field. _Pragma("clang diagnostic push") /**/ \
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
Py_tss_t var \
= Py_tss_NEEDS_INIT; \
_Pragma("clang diagnostic pop")
# elif defined(__GNUC__) && !defined(__INTEL_COMPILER)
# define PYBIND11_TLS_KEY_INIT(var) \ # define PYBIND11_TLS_KEY_INIT(var) \
_Pragma("GCC diagnostic push") /**/ \ _Pragma("GCC diagnostic push") /**/ \
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \ _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \

View File

@ -1205,13 +1205,17 @@ protected:
static Constructor make_move_constructor(...) { return nullptr; } static Constructor make_move_constructor(...) { return nullptr; }
}; };
inline std::string quote_cpp_type_name(const std::string &cpp_type_name) {
return cpp_type_name; // No-op for now. See PR #4888
}
PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) { PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) {
if (auto *type_data = get_type_info(ti)) { if (auto *type_data = get_type_info(ti)) {
handle th((PyObject *) type_data->type); handle th((PyObject *) type_data->type);
return th.attr("__module__").cast<std::string>() + '.' return th.attr("__module__").cast<std::string>() + '.'
+ th.attr("__qualname__").cast<std::string>(); + th.attr("__qualname__").cast<std::string>();
} }
return clean_type_id(ti.name()); return quote_cpp_type_name(clean_type_id(ti.name()));
} }
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)

View File

@ -70,7 +70,7 @@ struct eigen_tensor_helper<Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexTy
template <size_t... Is> template <size_t... Is>
struct helper<index_sequence<Is...>> { struct helper<index_sequence<Is...>> {
static constexpr auto value = concat(const_name(((void) Is, "?"))...); static constexpr auto value = ::pybind11::detail::concat(const_name(((void) Is, "?"))...);
}; };
static constexpr auto dimensions_descriptor static constexpr auto dimensions_descriptor
@ -104,7 +104,8 @@ struct eigen_tensor_helper<
return get_shape() == shape; return get_shape() == shape;
} }
static constexpr auto dimensions_descriptor = concat(const_name<Indices>()...); static constexpr auto dimensions_descriptor
= ::pybind11::detail::concat(const_name<Indices>()...);
template <typename... Args> template <typename... Args>
static Type *alloc(Args &&...args) { static Type *alloc(Args &&...args) {

View File

@ -128,7 +128,8 @@ public:
} }
PYBIND11_TYPE_CASTER(type, PYBIND11_TYPE_CASTER(type,
const_name("Callable[[") + concat(make_caster<Args>::name...) const_name("Callable[[")
+ ::pybind11::detail::concat(make_caster<Args>::name...)
+ const_name("], ") + make_caster<retval_type>::name + const_name("], ") + make_caster<retval_type>::name
+ const_name("]")); + const_name("]"));
}; };

View File

@ -29,10 +29,15 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#if defined(PYBIND11_NUMPY_1_ONLY) && !defined(PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED)
# error PYBIND11_NUMPY_1_ONLY must be defined before any pybind11 header is included.
#endif
/* This will be true on all flat address space platforms and allows us to reduce the /* This will be true on all flat address space platforms and allows us to reduce the
whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size
and dimension types (e.g. shape, strides, indexing), instead of inflicting this and dimension types (e.g. shape, strides, indexing), instead of inflicting this
upon the library user. */ upon the library user.
Note that NumPy 2 now uses ssize_t for `npy_intp` to simplify this. */
static_assert(sizeof(::pybind11::ssize_t) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t"); static_assert(sizeof(::pybind11::ssize_t) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t");
static_assert(std::is_signed<Py_intptr_t>::value, "Py_intptr_t must be signed"); static_assert(std::is_signed<Py_intptr_t>::value, "Py_intptr_t must be signed");
// We now can reinterpret_cast between py::ssize_t and Py_intptr_t (MSVC + PyPy cares) // We now can reinterpret_cast between py::ssize_t and Py_intptr_t (MSVC + PyPy cares)
@ -41,10 +46,16 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_WARNING_DISABLE_MSVC(4127) PYBIND11_WARNING_DISABLE_MSVC(4127)
class dtype; // Forward declaration
class array; // Forward declaration class array; // Forward declaration
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
template <>
struct handle_type_name<dtype> {
static constexpr auto name = const_name("numpy.dtype");
};
template <> template <>
struct handle_type_name<array> { struct handle_type_name<array> {
static constexpr auto name = const_name("numpy.ndarray"); static constexpr auto name = const_name("numpy.ndarray");
@ -53,7 +64,8 @@ struct handle_type_name<array> {
template <typename type, typename SFINAE = void> template <typename type, typename SFINAE = void>
struct npy_format_descriptor; struct npy_format_descriptor;
struct PyArrayDescr_Proxy { /* NumPy 1 proxy (always includes legacy fields) */
struct PyArrayDescr1_Proxy {
PyObject_HEAD PyObject_HEAD
PyObject *typeobj; PyObject *typeobj;
char kind; char kind;
@ -68,6 +80,43 @@ struct PyArrayDescr_Proxy {
PyObject *names; PyObject *names;
}; };
#ifndef PYBIND11_NUMPY_1_ONLY
struct PyArrayDescr_Proxy {
PyObject_HEAD
PyObject *typeobj;
char kind;
char type;
char byteorder;
char _former_flags;
int type_num;
/* Additional fields are NumPy version specific. */
};
#else
/* NumPy 1.x only, we can expose all fields */
using PyArrayDescr_Proxy = PyArrayDescr1_Proxy;
#endif
/* NumPy 2 proxy, including legacy fields */
struct PyArrayDescr2_Proxy {
PyObject_HEAD
PyObject *typeobj;
char kind;
char type;
char byteorder;
char _former_flags;
int type_num;
std::uint64_t flags;
ssize_t elsize;
ssize_t alignment;
PyObject *metadata;
Py_hash_t hash;
void *reserved_null[2];
/* The following fields only exist if 0 <= type_num < 2056 */
char *subarray;
PyObject *fields;
PyObject *names;
};
struct PyArray_Proxy { struct PyArray_Proxy {
PyObject_HEAD PyObject_HEAD
char *data; char *data;
@ -131,6 +180,14 @@ PYBIND11_NOINLINE module_ import_numpy_core_submodule(const char *submodule_name
object numpy_version = numpy_lib.attr("NumpyVersion")(version_string); object numpy_version = numpy_lib.attr("NumpyVersion")(version_string);
int major_version = numpy_version.attr("major").cast<int>(); int major_version = numpy_version.attr("major").cast<int>();
#ifdef PYBIND11_NUMPY_1_ONLY
if (major_version >= 2) {
throw std::runtime_error(
"This extension was built with PYBIND11_NUMPY_1_ONLY defined, "
"but NumPy 2 is used in this process. For NumPy2 compatibility, "
"this extension needs to be rebuilt without the PYBIND11_NUMPY_1_ONLY define.");
}
#endif
/* `numpy.core` was renamed to `numpy._core` in NumPy 2.0 as it officially /* `numpy.core` was renamed to `numpy._core` in NumPy 2.0 as it officially
became a private module. */ became a private module. */
std::string numpy_core_path = major_version >= 2 ? "numpy._core" : "numpy.core"; std::string numpy_core_path = major_version >= 2 ? "numpy._core" : "numpy.core";
@ -203,6 +260,8 @@ struct npy_api {
NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_), NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_),
}; };
unsigned int PyArray_RUNTIME_VERSION_;
struct PyArray_Dims { struct PyArray_Dims {
Py_intptr_t *ptr; Py_intptr_t *ptr;
int len; int len;
@ -241,6 +300,7 @@ struct npy_api {
PyObject *(*PyArray_FromAny_)(PyObject *, PyObject *, int, int, int, PyObject *); PyObject *(*PyArray_FromAny_)(PyObject *, PyObject *, int, int, int, PyObject *);
int (*PyArray_DescrConverter_)(PyObject *, PyObject **); int (*PyArray_DescrConverter_)(PyObject *, PyObject **);
bool (*PyArray_EquivTypes_)(PyObject *, PyObject *); bool (*PyArray_EquivTypes_)(PyObject *, PyObject *);
#ifdef PYBIND11_NUMPY_1_ONLY
int (*PyArray_GetArrayParamsFromObject_)(PyObject *, int (*PyArray_GetArrayParamsFromObject_)(PyObject *,
PyObject *, PyObject *,
unsigned char, unsigned char,
@ -249,6 +309,7 @@ struct npy_api {
Py_intptr_t *, Py_intptr_t *,
PyObject **, PyObject **,
PyObject *); PyObject *);
#endif
PyObject *(*PyArray_Squeeze_)(PyObject *); PyObject *(*PyArray_Squeeze_)(PyObject *);
// Unused. Not removed because that affects ABI of the class. // Unused. Not removed because that affects ABI of the class.
int (*PyArray_SetBaseObject_)(PyObject *, PyObject *); int (*PyArray_SetBaseObject_)(PyObject *, PyObject *);
@ -266,7 +327,8 @@ private:
API_PyArray_DescrFromScalar = 57, API_PyArray_DescrFromScalar = 57,
API_PyArray_FromAny = 69, API_PyArray_FromAny = 69,
API_PyArray_Resize = 80, API_PyArray_Resize = 80,
API_PyArray_CopyInto = 82, // CopyInto was slot 82 and 50 was effectively an alias. NumPy 2 removed 82.
API_PyArray_CopyInto = 50,
API_PyArray_NewCopy = 85, API_PyArray_NewCopy = 85,
API_PyArray_NewFromDescr = 94, API_PyArray_NewFromDescr = 94,
API_PyArray_DescrNewFromType = 96, API_PyArray_DescrNewFromType = 96,
@ -275,7 +337,9 @@ private:
API_PyArray_View = 137, API_PyArray_View = 137,
API_PyArray_DescrConverter = 174, API_PyArray_DescrConverter = 174,
API_PyArray_EquivTypes = 182, API_PyArray_EquivTypes = 182,
#ifdef PYBIND11_NUMPY_1_ONLY
API_PyArray_GetArrayParamsFromObject = 278, API_PyArray_GetArrayParamsFromObject = 278,
#endif
API_PyArray_SetBaseObject = 282 API_PyArray_SetBaseObject = 282
}; };
@ -290,7 +354,8 @@ private:
npy_api api; npy_api api;
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func]; #define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion); DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);
if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7) { api.PyArray_RUNTIME_VERSION_ = api.PyArray_GetNDArrayCFeatureVersion_();
if (api.PyArray_RUNTIME_VERSION_ < 0x7) {
pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0"); pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0");
} }
DECL_NPY_API(PyArray_Type); DECL_NPY_API(PyArray_Type);
@ -309,7 +374,9 @@ private:
DECL_NPY_API(PyArray_View); DECL_NPY_API(PyArray_View);
DECL_NPY_API(PyArray_DescrConverter); DECL_NPY_API(PyArray_DescrConverter);
DECL_NPY_API(PyArray_EquivTypes); DECL_NPY_API(PyArray_EquivTypes);
#ifdef PYBIND11_NUMPY_1_ONLY
DECL_NPY_API(PyArray_GetArrayParamsFromObject); DECL_NPY_API(PyArray_GetArrayParamsFromObject);
#endif
DECL_NPY_API(PyArray_SetBaseObject); DECL_NPY_API(PyArray_SetBaseObject);
#undef DECL_NPY_API #undef DECL_NPY_API
@ -331,6 +398,14 @@ inline const PyArrayDescr_Proxy *array_descriptor_proxy(const PyObject *ptr) {
return reinterpret_cast<const PyArrayDescr_Proxy *>(ptr); return reinterpret_cast<const PyArrayDescr_Proxy *>(ptr);
} }
inline const PyArrayDescr1_Proxy *array_descriptor1_proxy(const PyObject *ptr) {
return reinterpret_cast<const PyArrayDescr1_Proxy *>(ptr);
}
inline const PyArrayDescr2_Proxy *array_descriptor2_proxy(const PyObject *ptr) {
return reinterpret_cast<const PyArrayDescr2_Proxy *>(ptr);
}
inline bool check_flags(const void *ptr, int flag) { inline bool check_flags(const void *ptr, int flag) {
return (flag == (array_proxy(ptr)->flags & flag)); return (flag == (array_proxy(ptr)->flags & flag));
} }
@ -371,7 +446,7 @@ struct array_info<std::array<T, N>> {
} }
static constexpr auto extents = const_name<array_info<T>::is_array>( static constexpr auto extents = const_name<array_info<T>::is_array>(
concat(const_name<N>(), array_info<T>::extents), const_name<N>()); ::pybind11::detail::concat(const_name<N>(), array_info<T>::extents), const_name<N>());
}; };
// For numpy we have special handling for arrays of characters, so we don't include // For numpy we have special handling for arrays of characters, so we don't include
// the size in the array extents. // the size in the array extents.
@ -610,10 +685,32 @@ public:
} }
/// Size of the data type in bytes. /// Size of the data type in bytes.
#ifdef PYBIND11_NUMPY_1_ONLY
ssize_t itemsize() const { return detail::array_descriptor_proxy(m_ptr)->elsize; } ssize_t itemsize() const { return detail::array_descriptor_proxy(m_ptr)->elsize; }
#else
ssize_t itemsize() const {
if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {
return detail::array_descriptor1_proxy(m_ptr)->elsize;
}
return detail::array_descriptor2_proxy(m_ptr)->elsize;
}
#endif
/// Returns true for structured data types. /// Returns true for structured data types.
#ifdef PYBIND11_NUMPY_1_ONLY
bool has_fields() const { return detail::array_descriptor_proxy(m_ptr)->names != nullptr; } bool has_fields() const { return detail::array_descriptor_proxy(m_ptr)->names != nullptr; }
#else
bool has_fields() const {
if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {
return detail::array_descriptor1_proxy(m_ptr)->names != nullptr;
}
const auto *proxy = detail::array_descriptor2_proxy(m_ptr);
if (proxy->type_num < 0 || proxy->type_num >= 2056) {
return false;
}
return proxy->names != nullptr;
}
#endif
/// Single-character code for dtype's kind. /// Single-character code for dtype's kind.
/// For example, floating point types are 'f' and integral types are 'i'. /// For example, floating point types are 'f' and integral types are 'i'.
@ -639,11 +736,29 @@ public:
/// Single character for byteorder /// Single character for byteorder
char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; } char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; }
/// Alignment of the data type /// Alignment of the data type
#ifdef PYBIND11_NUMPY_1_ONLY
int alignment() const { return detail::array_descriptor_proxy(m_ptr)->alignment; } int alignment() const { return detail::array_descriptor_proxy(m_ptr)->alignment; }
#else
ssize_t alignment() const {
if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {
return detail::array_descriptor1_proxy(m_ptr)->alignment;
}
return detail::array_descriptor2_proxy(m_ptr)->alignment;
}
#endif
/// Flags for the array descriptor /// Flags for the array descriptor
#ifdef PYBIND11_NUMPY_1_ONLY
char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; } char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; }
#else
std::uint64_t flags() const {
if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {
return (unsigned char) detail::array_descriptor1_proxy(m_ptr)->flags;
}
return detail::array_descriptor2_proxy(m_ptr)->flags;
}
#endif
private: private:
static object &_dtype_from_pep3118() { static object &_dtype_from_pep3118() {
@ -810,9 +925,7 @@ public:
} }
/// Byte size of a single element /// Byte size of a single element
ssize_t itemsize() const { ssize_t itemsize() const { return dtype().itemsize(); }
return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize;
}
/// Total number of bytes /// Total number of bytes
ssize_t nbytes() const { return size() * itemsize(); } ssize_t nbytes() const { return size() * itemsize(); }

View File

@ -493,9 +493,7 @@ protected:
signature += rec->scope.attr("__module__").cast<std::string>() + "." signature += rec->scope.attr("__module__").cast<std::string>() + "."
+ rec->scope.attr("__qualname__").cast<std::string>(); + rec->scope.attr("__qualname__").cast<std::string>();
} else { } else {
std::string tname(t->name()); signature += detail::quote_cpp_type_name(detail::clean_type_id(t->name()));
detail::clean_type_id(tname);
signature += tname;
} }
} else { } else {
signature += c; signature += c;
@ -1193,6 +1191,15 @@ protected:
} }
}; };
PYBIND11_NAMESPACE_BEGIN(detail)
template <>
struct handle_type_name<cpp_function> {
static constexpr auto name = const_name("Callable");
};
PYBIND11_NAMESPACE_END(detail)
/// Wrapper for Python extension modules /// Wrapper for Python extension modules
class module_ : public object { class module_ : public object {
public: public:
@ -1320,6 +1327,15 @@ public:
} }
}; };
PYBIND11_NAMESPACE_BEGIN(detail)
template <>
struct handle_type_name<module_> {
static constexpr auto name = const_name("module");
};
PYBIND11_NAMESPACE_END(detail)
// When inside a namespace (or anywhere as long as it's not the first item on a line), // When inside a namespace (or anywhere as long as it's not the first item on a line),
// C++20 allows "module" to be used. This is provided for backward compatibility, and for // C++20 allows "module" to be used. This is provided for backward compatibility, and for
// simplicity, if someone wants to use py::module for example, that is perfectly safe. // simplicity, if someone wants to use py::module for example, that is perfectly safe.
@ -2871,6 +2887,11 @@ public:
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
template <>
struct handle_type_name<exception<void>> {
static constexpr auto name = const_name("Exception");
};
// Helper function for register_exception and register_local_exception // Helper function for register_exception and register_local_exception
template <typename CppException> template <typename CppException>
exception<CppException> & exception<CppException> &

View File

@ -59,6 +59,7 @@ struct sequence_item;
struct list_item; struct list_item;
struct tuple_item; struct tuple_item;
} // namespace accessor_policies } // namespace accessor_policies
// PLEASE KEEP handle_type_name SPECIALIZATIONS IN SYNC.
using obj_attr_accessor = accessor<accessor_policies::obj_attr>; using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
using str_attr_accessor = accessor<accessor_policies::str_attr>; using str_attr_accessor = accessor<accessor_policies::str_attr>;
using item_accessor = accessor<accessor_policies::generic_item>; using item_accessor = accessor<accessor_policies::generic_item>;

View File

@ -424,7 +424,8 @@ struct variant_caster<V<Ts...>> {
using Type = V<Ts...>; using Type = V<Ts...>;
PYBIND11_TYPE_CASTER(Type, PYBIND11_TYPE_CASTER(Type,
const_name("Union[") + detail::concat(make_caster<Ts>::name...) const_name("Union[")
+ ::pybind11::detail::concat(make_caster<Ts>::name...)
+ const_name("]")); + const_name("]"));
}; };

View File

@ -69,8 +69,9 @@ PYBIND11_NAMESPACE_BEGIN(detail)
template <typename... Types> template <typename... Types>
struct handle_type_name<typing::Tuple<Types...>> { struct handle_type_name<typing::Tuple<Types...>> {
static constexpr auto name static constexpr auto name = const_name("tuple[")
= const_name("tuple[") + concat(make_caster<Types>::name...) + const_name("]"); + ::pybind11::detail::concat(make_caster<Types>::name...)
+ const_name("]");
}; };
template <> template <>
@ -79,6 +80,13 @@ struct handle_type_name<typing::Tuple<>> {
static constexpr auto name = const_name("tuple[()]"); static constexpr auto name = const_name("tuple[()]");
}; };
template <typename T>
struct handle_type_name<typing::Tuple<T, ellipsis>> {
// PEP 484 specifies this syntax for a variable-length tuple
static constexpr auto name
= const_name("tuple[") + make_caster<T>::name + const_name(", ...]");
};
template <typename K, typename V> template <typename K, typename V>
struct handle_type_name<typing::Dict<K, V>> { struct handle_type_name<typing::Dict<K, V>> {
static constexpr auto name = const_name("dict[") + make_caster<K>::name + const_name(", ") static constexpr auto name = const_name("dict[") + make_caster<K>::name + const_name(", ")
@ -108,9 +116,9 @@ struct handle_type_name<typing::Iterator<T>> {
template <typename Return, typename... Args> template <typename Return, typename... Args>
struct handle_type_name<typing::Callable<Return(Args...)>> { struct handle_type_name<typing::Callable<Return(Args...)>> {
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>; using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
static constexpr auto name = const_name("Callable[[") + concat(make_caster<Args>::name...) static constexpr auto name
+ const_name("], ") + make_caster<retval_type>::name = const_name("Callable[[") + ::pybind11::detail::concat(make_caster<Args>::name...)
+ const_name("]"); + const_name("], ") + make_caster<retval_type>::name + const_name("]");
}; };
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)

View File

@ -8,5 +8,5 @@ def _to_int(s: str) -> Union[int, str]:
return s return s
__version__ = "2.12.0.dev1" __version__ = "2.13.0.dev1"
version_info = tuple(_to_int(s) for s in __version__.split(".")) version_info = tuple(_to_int(s) for s in __version__.split("."))

View File

@ -557,11 +557,15 @@ set(PYBIND11_TEST_PREFIX_COMMAND
"" ""
CACHE STRING "Put this before pytest, use for checkers and such") CACHE STRING "Put this before pytest, use for checkers and such")
set(PYBIND11_PYTEST_ARGS
""
CACHE STRING "Extra arguments for pytest")
# A single command to compile and run the tests # A single command to compile and run the tests
add_custom_target( add_custom_target(
pytest pytest
COMMAND ${PYBIND11_TEST_PREFIX_COMMAND} ${PYTHON_EXECUTABLE} -m pytest COMMAND ${PYBIND11_TEST_PREFIX_COMMAND} ${PYTHON_EXECUTABLE} -m pytest
${PYBIND11_ABS_PYTEST_FILES} ${PYBIND11_ABS_PYTEST_FILES} ${PYBIND11_PYTEST_ARGS}
DEPENDS ${test_targets} DEPENDS ${test_targets}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
USES_TERMINAL) USES_TERMINAL)

View File

@ -218,4 +218,5 @@ def pytest_report_header(config):
f" {pybind11_tests.cpp_std}" f" {pybind11_tests.cpp_std}"
f" {pybind11_tests.PYBIND11_INTERNALS_ID}" f" {pybind11_tests.PYBIND11_INTERNALS_ID}"
f" PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}" f" PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}"
f" PYBIND11_NUMPY_1_ONLY={pybind11_tests.PYBIND11_NUMPY_1_ONLY}"
) )

View File

@ -80,10 +80,10 @@ PYBIND11_MODULE(pybind11_tests, m) {
// Intentionally kept minimal to not create a maintenance chore // Intentionally kept minimal to not create a maintenance chore
// ("just enough" to be conclusive). // ("just enough" to be conclusive).
#if defined(_MSC_FULL_VER) #if defined(__VERSION__)
m.attr("compiler_info") = "MSVC " PYBIND11_TOSTRING(_MSC_FULL_VER);
#elif defined(__VERSION__)
m.attr("compiler_info") = __VERSION__; m.attr("compiler_info") = __VERSION__;
#elif defined(_MSC_FULL_VER)
m.attr("compiler_info") = "MSVC " PYBIND11_TOSTRING(_MSC_FULL_VER);
#else #else
m.attr("compiler_info") = py::none(); m.attr("compiler_info") = py::none();
#endif #endif
@ -95,6 +95,12 @@ PYBIND11_MODULE(pybind11_tests, m) {
#else #else
false; false;
#endif #endif
m.attr("PYBIND11_NUMPY_1_ONLY") =
#if defined(PYBIND11_NUMPY_1_ONLY)
true;
#else
false;
#endif
bind_ConstructorStats(m); bind_ConstructorStats(m);

View File

@ -54,7 +54,11 @@ int f2(int x) noexcept(true) { return x + 2; }
int f3(int x) noexcept(false) { return x + 3; } int f3(int x) noexcept(false) { return x + 3; }
PYBIND11_WARNING_PUSH PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated") PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated")
#if defined(__clang_major__) && __clang_major__ >= 5
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated-dynamic-exception-spec")
#else
PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated") PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated")
#endif
// NOLINTNEXTLINE(modernize-use-noexcept) // NOLINTNEXTLINE(modernize-use-noexcept)
int f4(int x) throw() { return x + 4; } // Deprecated equivalent to noexcept(true) int f4(int x) throw() { return x + 4; } // Deprecated equivalent to noexcept(true)
PYBIND11_WARNING_POP PYBIND11_WARNING_POP

View File

@ -134,6 +134,16 @@ struct type_caster<other_lib::MyType> : public other_lib::my_caster {};
} // namespace detail } // namespace detail
} // namespace PYBIND11_NAMESPACE } // namespace PYBIND11_NAMESPACE
// This simply is required to compile
namespace ADL_issue {
template <typename OutStringType = std::string, typename... Args>
OutStringType concat(Args &&...) {
return OutStringType();
}
struct test {};
} // namespace ADL_issue
TEST_SUBMODULE(custom_type_casters, m) { TEST_SUBMODULE(custom_type_casters, m) {
// test_custom_type_casters // test_custom_type_casters
@ -206,4 +216,6 @@ TEST_SUBMODULE(custom_type_casters, m) {
py::return_value_policy::reference); py::return_value_policy::reference);
m.def("other_lib_type", [](other_lib::MyType x) { return x; }); m.def("other_lib_type", [](other_lib::MyType x) { return x; });
m.def("_adl_issue", [](const ADL_issue::test &) {});
} }

View File

@ -608,7 +608,9 @@ def test_both_ref_mutators():
def test_nocopy_wrapper(): def test_nocopy_wrapper():
# get_elem requires a column-contiguous matrix reference, but should be # get_elem requires a column-contiguous matrix reference, but should be
# callable with other types of matrix (via copying): # callable with other types of matrix (via copying):
int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order="F") int_matrix_colmajor = np.array(
[[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype="l", order="F"
)
dbl_matrix_colmajor = np.array( dbl_matrix_colmajor = np.array(
int_matrix_colmajor, dtype="double", order="F", copy=True int_matrix_colmajor, dtype="double", order="F", copy=True
) )

View File

@ -382,4 +382,7 @@ TEST_SUBMODULE(exceptions, m) {
// function returns None instead of int, should give a useful error message // function returns None instead of int, should give a useful error message
fn().cast<int>(); fn().cast<int>();
}); });
// m.def("pass_exception_void", [](const py::exception<void>&) {}); // Does not compile.
m.def("return_exception_void", []() { return py::exception<void>(); });
} }

View File

@ -4,7 +4,7 @@ import pytest
import env import env
import pybind11_cross_module_tests as cm import pybind11_cross_module_tests as cm
import pybind11_tests # noqa: F401 import pybind11_tests
from pybind11_tests import exceptions as m from pybind11_tests import exceptions as m
@ -248,6 +248,11 @@ def test_nested_throws(capture):
assert str(excinfo.value) == "this is a helper-defined translated exception" assert str(excinfo.value) == "this is a helper-defined translated exception"
# TODO: Investigate this crash, see pybind/pybind11#5062 for background
@pytest.mark.skipif(
sys.platform.startswith("win32") and "Clang" in pybind11_tests.compiler_info,
reason="Started segfaulting February 2024",
)
def test_throw_nested_exception(): def test_throw_nested_exception():
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.throw_nested_exception() m.throw_nested_exception()
@ -419,3 +424,9 @@ def test_fn_cast_int_exception():
assert str(excinfo.value).startswith( assert str(excinfo.value).startswith(
"Unable to cast Python instance of type <class 'NoneType'> to C++ type" "Unable to cast Python instance of type <class 'NoneType'> to C++ type"
) )
def test_return_exception_void():
with pytest.raises(TypeError) as excinfo:
m.return_exception_void()
assert "Exception" in str(excinfo.value)

View File

@ -536,7 +536,12 @@ def test_format_descriptors_for_floating_point_types(test_func):
@pytest.mark.parametrize("contiguity", [None, "C", "F"]) @pytest.mark.parametrize("contiguity", [None, "C", "F"])
@pytest.mark.parametrize("noconvert", [False, True]) @pytest.mark.parametrize("noconvert", [False, True])
@pytest.mark.filterwarnings( @pytest.mark.filterwarnings(
"ignore:Casting complex values to real discards the imaginary part:numpy.ComplexWarning" "ignore:Casting complex values to real discards the imaginary part:"
+ (
"numpy.exceptions.ComplexWarning"
if hasattr(np, "exceptions")
else "numpy.ComplexWarning"
)
) )
def test_argument_conversions(forcecast, contiguity, noconvert): def test_argument_conversions(forcecast, contiguity, noconvert):
function_name = "accept_double" function_name = "accept_double"
@ -583,7 +588,8 @@ def test_argument_conversions(forcecast, contiguity, noconvert):
def test_dtype_refcount_leak(): def test_dtype_refcount_leak():
from sys import getrefcount from sys import getrefcount
dtype = np.dtype(np.float_) # Was np.float_ but that alias for float64 was removed in NumPy 2.
dtype = np.dtype(np.float64)
a = np.array([1], dtype=dtype) a = np.array([1], dtype=dtype)
before = getrefcount(dtype) before = getrefcount(dtype)
m.ndim(a) m.ndim(a)

View File

@ -405,10 +405,35 @@ TEST_SUBMODULE(numpy_dtypes, m) {
}); });
// test_dtype // test_dtype
// Below we use `L` for unsigned long as unfortunately the only name that
// works reliably on Both NumPy 2.x and old NumPy 1.x.
std::vector<const char *> dtype_names{ std::vector<const char *> dtype_names{
"byte", "short", "intc", "int_", "longlong", "ubyte", "ushort", "byte",
"uintc", "uint", "ulonglong", "half", "single", "double", "longdouble", "short",
"csingle", "cdouble", "clongdouble", "bool_", "datetime64", "timedelta64", "object_"}; "intc",
"long",
"longlong",
"ubyte",
"ushort",
"uintc",
"L",
"ulonglong",
"half",
"single",
"double",
"longdouble",
"csingle",
"cdouble",
"clongdouble",
"bool_",
"datetime64",
"timedelta64",
"object_",
// platform dependent aliases (int_ and uint are also NumPy version dependent on windows)
"int_",
"uint",
"intp",
"uintp"};
m.def("print_dtypes", []() { m.def("print_dtypes", []() {
py::list l; py::list l;

View File

@ -3,6 +3,7 @@ import re
import pytest import pytest
import env # noqa: F401 import env # noqa: F401
from pybind11_tests import PYBIND11_NUMPY_1_ONLY
from pybind11_tests import numpy_dtypes as m from pybind11_tests import numpy_dtypes as m
np = pytest.importorskip("numpy") np = pytest.importorskip("numpy")
@ -172,13 +173,20 @@ def test_dtype(simple_dtype):
np.zeros(1, m.trailing_padding_dtype()) np.zeros(1, m.trailing_padding_dtype())
) )
expected_chars = "bhilqBHILQefdgFDG?MmO" expected_chars = list("bhilqBHILQefdgFDG?MmO")
assert m.test_dtype_kind() == list("iiiiiuuuuuffffcccbMmO") # Note that int_ and uint size and mapping is NumPy version dependent:
expected_chars += [np.dtype(_).char for _ in ("int_", "uint", "intp", "uintp")]
assert m.test_dtype_kind() == list("iiiiiuuuuuffffcccbMmOiuiu")
assert m.test_dtype_char_() == list(expected_chars) assert m.test_dtype_char_() == list(expected_chars)
assert m.test_dtype_num() == [np.dtype(ch).num for ch in expected_chars] assert m.test_dtype_num() == [np.dtype(ch).num for ch in expected_chars]
assert m.test_dtype_byteorder() == [np.dtype(ch).byteorder for ch in expected_chars] assert m.test_dtype_byteorder() == [np.dtype(ch).byteorder for ch in expected_chars]
assert m.test_dtype_alignment() == [np.dtype(ch).alignment for ch in expected_chars] assert m.test_dtype_alignment() == [np.dtype(ch).alignment for ch in expected_chars]
assert m.test_dtype_flags() == [chr(np.dtype(ch).flags) for ch in expected_chars] if not PYBIND11_NUMPY_1_ONLY:
assert m.test_dtype_flags() == [np.dtype(ch).flags for ch in expected_chars]
else:
assert m.test_dtype_flags() == [
chr(np.dtype(ch).flags) for ch in expected_chars
]
def test_recarray(simple_dtype, packed_dtype): def test_recarray(simple_dtype, packed_dtype):

View File

@ -41,6 +41,15 @@ class float_ : public py::object {
}; };
} // namespace external } // namespace external
namespace pybind11 {
namespace detail {
template <>
struct handle_type_name<external::float_> {
static constexpr auto name = const_name("float");
};
} // namespace detail
} // namespace pybind11
namespace implicit_conversion_from_0_to_handle { namespace implicit_conversion_from_0_to_handle {
// Uncomment to trigger compiler error. Note: Before PR #4008 this used to compile successfully. // Uncomment to trigger compiler error. Note: Before PR #4008 this used to compile successfully.
// void expected_to_trigger_compiler_error() { py::handle(0); } // void expected_to_trigger_compiler_error() { py::handle(0); }
@ -825,6 +834,8 @@ TEST_SUBMODULE(pytypes, m) {
m.def("annotate_tuple_float_str", [](const py::typing::Tuple<py::float_, py::str> &) {}); m.def("annotate_tuple_float_str", [](const py::typing::Tuple<py::float_, py::str> &) {});
m.def("annotate_tuple_empty", [](const py::typing::Tuple<> &) {}); m.def("annotate_tuple_empty", [](const py::typing::Tuple<> &) {});
m.def("annotate_tuple_variable_length",
[](const py::typing::Tuple<py::float_, py::ellipsis> &) {});
m.def("annotate_dict_str_int", [](const py::typing::Dict<py::str, int> &) {}); m.def("annotate_dict_str_int", [](const py::typing::Dict<py::str, int> &) {});
m.def("annotate_list_int", [](const py::typing::List<int> &) {}); m.def("annotate_list_int", [](const py::typing::List<int> &) {});
m.def("annotate_set_str", [](const py::typing::Set<std::string> &) {}); m.def("annotate_set_str", [](const py::typing::Set<std::string> &) {});

View File

@ -121,7 +121,7 @@ def test_set(capture, doc):
assert m.anyset_contains({"foo"}, "foo") assert m.anyset_contains({"foo"}, "foo")
assert doc(m.get_set) == "get_set() -> set" assert doc(m.get_set) == "get_set() -> set"
assert doc(m.print_anyset) == "print_anyset(arg0: anyset) -> None" assert doc(m.print_anyset) == "print_anyset(arg0: Union[set, frozenset]) -> None"
def test_frozenset(capture, doc): def test_frozenset(capture, doc):
@ -911,6 +911,13 @@ def test_tuple_empty_annotations(doc):
) )
def test_tuple_variable_length_annotations(doc):
assert (
doc(m.annotate_tuple_variable_length)
== "annotate_tuple_variable_length(arg0: tuple[float, ...]) -> None"
)
def test_dict_annotations(doc): def test_dict_annotations(doc):
assert ( assert (
doc(m.annotate_dict_str_int) doc(m.annotate_dict_str_int)

View File

@ -67,10 +67,12 @@ for issue in issues:
for cat, msgs in cats.items(): for cat, msgs in cats.items():
if msgs: if msgs:
desc = cats_descr[cat] desc = cats_descr[cat]
print(f"[bold]{desc}:\n" if desc else "") print(f"[bold]{desc}:" if desc else f".. {cat}")
print()
for msg in msgs: for msg in msgs:
print(Syntax(msg, "rst", theme="ansi_light", word_wrap=True)) print(Syntax(msg, "rst", theme="ansi_light", word_wrap=True))
print() print()
print()
if missing: if missing:
print() print()

View File

@ -173,12 +173,16 @@ endif()
# Check to see which Python mode we are in, new, old, or no python # Check to see which Python mode we are in, new, old, or no python
if(PYBIND11_NOPYTHON) if(PYBIND11_NOPYTHON)
set(_pybind11_nopython ON) set(_pybind11_nopython ON)
# We won't use new FindPython if PYBIND11_FINDPYTHON is defined and falselike
# Otherwise, we use if FindPythonLibs is missing or if FindPython was already used
elseif( elseif(
_pybind11_missing_old_python STREQUAL "NEW" (NOT DEFINED PYBIND11_FINDPYTHON OR PYBIND11_FINDPYTHON)
AND (_pybind11_missing_old_python STREQUAL "NEW"
OR PYBIND11_FINDPYTHON OR PYBIND11_FINDPYTHON
OR Python_FOUND OR Python_FOUND
OR Python2_FOUND OR Python3_FOUND
OR Python3_FOUND) ))
# New mode # New mode
include("${CMAKE_CURRENT_LIST_DIR}/pybind11NewTools.cmake") include("${CMAKE_CURRENT_LIST_DIR}/pybind11NewTools.cmake")