Compare commits

...

21 Commits

Author SHA1 Message Date
Francis Williams
9e511077c3
Merge c230777e92 into 83b92ceb35 2024-11-22 09:26:41 +09:00
Michael Šimáček
83b92ceb35
Try to fix reentrant write transient failures in tests (#5447)
* Disable print_destroyed in tests on GraalPy

* Reenable test_iostream on GraalPy
2024-11-18 14:39:59 -08:00
Ralf W. Grosse-Kunstleve
330aae51cf
Remove mingw-w64-i686-python-numpy from mingw32 build (it does not seem to exist anymore). (#5445)
Last successful: Sat, 16 Nov 2024 18:25:21 GMT

First failure: Sat, 16 Nov 2024 21:43:28 GMT

```
Installing additional packages through pacman...
  C:\Windows\system32\cmd.exe /D /S /C D:\a\_temp\setup-msys2\msys2.cmd -c "'pacman' '--noconfirm' '-S' '--needed' '--overwrite' '*' 'git' 'mingw-w64-i686-gcc' 'mingw-w64-i686-python-pip' 'mingw-w64-i686-python-numpy' 'mingw-w64-i686-cmake' 'mingw-w64-i686-make' 'mingw-w64-i686-python-pytest' 'mingw-w64-i686-boost' 'mingw-w64-i686-catch'"
  error: target not found: mingw-w64-i686-python-numpy
  Error: The process 'C:\Windows\system32\cmd.exe' failed with exit code 1
```
2024-11-17 11:46:55 -08:00
Maarten Baert
f41dae31a3
Add dtype::normalized_num and dtype::num_of (#5429)
* Add dtype::normalized_num and dtype::num_of

* Fix compiler warning and improve NumPy 1.x compatibility

* Fix clang-tidy warning

* Fix another clang-tidy warning

* Add extra comment
2024-11-17 07:56:02 -08:00
Maarten Baert
b9fb3168ab
Add support for array_t<handle> and array_t<object> (#5427)
* Add support for array_t<handle> and array_t<object>

* style: pre-commit fixes

* Remove loops that aren't strictly needed

* Fix compiler warning

* Disable GC-dependent checks when running on pypy or graalpy

* style: pre-commit fixes

* Remove PyValueHolder counter again

* Move tests to templates to avoid code duplication

* Rerun pre-commit

* Restore import that was erroneously removed by pre-commit

* Reduce code duplication with more template magic

* Bring back `.attr("value")` in `return_array_cpp_loop()`

This was meant to further stress-test correctness of refcount handling.

All modified test functions were manually leak-checked (`while True`, top command, Python 3.12.3, Ubuntu 24.01, gcc 13.2.0).

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2024-11-16 13:45:59 -08:00
Michael Šimáček
08095d9c70
Run pytest in verbose mode (#5443) 2024-11-14 09:03:56 -08:00
dependabot[bot]
0ed20f26ac
chore(deps): bump actions/attest-build-provenance in the actions group (#5440)
Bumps the actions group with 1 update: [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance).


Updates `actions/attest-build-provenance` from 1.4.3 to 1.4.4
- [Release notes](https://github.com/actions/attest-build-provenance/releases)
- [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md)
- [Commits](1c608d11d6...ef244123eb)

---
updated-dependencies:
- dependency-name: actions/attest-build-provenance
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 16:55:21 -08:00
Xuehai Pan
7f94f24d64
feat(typing): allow annotate methods with pos_only when only have the self argument (#5403)
* feat: allow annotate methods with `pos_only` when only have the `self` argument

* chore(typing): make arguments for auto-generated dunder methods positional-only

* docs: add more comments to improve readability

* style: fix nit suggestions

* Add test_self_only_pos_only() in tests/test_methods_and_attributes

* test: add docstring tests for generated dunder methods

* test: remove failed tests

* fix(test): run `gc.collect()` three times for refcount tests

---------

Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2024-11-11 15:35:28 -08:00
gentlegiantJGC
6d98d4d8d4
Add type hints for args and kwargs (#5357)
* Allow subclasses of args and kwargs

The current implementation disallows subclasses of args and kwargs

* Added object type hint to args and kwargs

* Added type hinted args and kwargs classes

* Changed default type hint to typing.Any

* Removed args and kwargs type hint

* Updated tests

Modified the tests from #5381 to use the real Args and KWArgs classes

* Added comment
2024-11-11 14:51:01 -08:00
Ralf W. Grosse-Kunstleve
a90e2af88d
Factor out pybind11/conduit/pybind11_platform_abi_id.h (#5375)
* Factor out pybind11/compat/wrap_include_python_h.h

* Fixes to resolve tests_packaging failures.

* Factor out pybind11/compat/pybind11_platform_abi_id.h

* Add pybind11/compat/README.txt and a couple source code comments.

* Minor changes to comments.

* Factor out pybind11/compat/pybind11_conduit_v1.h

* Add long comment to pybind11/compat/pybind11_conduit_v1.h

* Add pybind11/compat/README.txt to wheels.

* Add `-fno-exceptions` to compiler options for exo_planet_c_api

* 1. Move `target_compile_options()` into loop over test targets, in case the `"exo_planet_c_api"` target does not exist.  2. Add `-fno-exceptions` option also for `NVHPC`.  3. Also check for `__cpp_exceptions` in exo_planet_c_api.cpp.

* 1. Fix accident (forgot to undo temporary change).  2. Special-case __EMSCRIPTEN__ in exo_planet_c_api.cpp

* Give up on compiling exo_planet_c_api.cpp with MSVC `/EHs-c-`:

There was one trouble maker (all other jobs worked):

Visual Studio 15 2017:

```
cl : Command line warning D9025: overriding '/EHc' with '/EHc-' [C:\projects\pybind11\tests\exo_planet_c_api.vcxproj]
...
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include\xlocale(319): error C2220: warning treated as error - no 'object' file generated [C:\projects\pybind11\tests\exo_planet_c_api.vcxproj]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include\xlocale(319): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
```

* Move pybind11/compat to pybind11/conduit as suggested by @henryiii:

https://github.com/pybind/pybind11/pull/5375#pullrequestreview-2329006001
2024-11-10 12:17:35 -08:00
Isuru Fernando
ec9c26817f
Fix MSVC MT/MD incompatibility in PYBIND11_BUILD_ABI (#4953)
* Fix MSVC MT/MD incompatibility in PYBIND11_BUILD_ABI

* Update comment about which PR

* Use msvc major version

* Use _MSC_VER/100

* Fix figuring out MD vs MT

* Add some test runs

* Skip one test

* Fix preprocessor

* simplify code

* fix if

* support only msvc 19

* Fold in changes from experimental PR #5411. Polish error messages.

* Remove `&& defined(_DLL)` (TBD: is it needed? but what is correct?)

* Fix MT vs MD

* Add a couple comments, based on https://github.com/pybind/pybind11/pull/4953#issuecomment-2435138593 (posted by @isuruf).

* Replace misleading comment: NVHPC is NOT outdated.

* Update include/pybind11/detail/internals.h

Co-authored-by: Robert Maynard <robertjmaynard@gmail.com>

---------

Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rwgkio@gmail.com>
Co-authored-by: Robert Maynard <robertjmaynard@gmail.com>
2024-11-10 09:24:29 -08:00
Elliott Sales de Andrade
037310ea8a
Use std::unique_ptr in pybind11_getbuffer (#5435)
* Use std::unique_ptr in pybind11_getbuffer

* Move final assignment later
2024-11-07 21:58:24 -08:00
Francis Williams
c230777e92
Merge pull request #1 from zgojcic/zg/sync_pybind11
Zg/sync pybind11
2023-07-05 10:26:00 -04:00
Francis Williams
f6fc661a5e Update numpy.h 2023-07-04 10:57:09 +02:00
Francis Williams
7a78222b69 Update numpy.h
rm old code from npe
2023-07-04 10:57:09 +02:00
pre-commit-ci[bot]
49668e5e57 style: pre-commit fixes 2023-07-04 10:57:09 +02:00
Francis Williams
9ef681765d numpy in a new world 2023-07-04 10:57:09 +02:00
Francis Williams
6b0a4e8510
Update numpy.h 2023-01-11 17:04:51 -05:00
Francis Williams
142ae7e124
Update numpy.h
rm old code from npe
2023-01-11 17:04:29 -05:00
pre-commit-ci[bot]
3f0f27fc12 style: pre-commit fixes 2023-01-11 21:03:56 +00:00
Francis Williams
5cf262c762 numpy in a new world 2023-01-11 15:48:34 -05:00
34 changed files with 882 additions and 275 deletions

View File

@ -65,6 +65,24 @@ jobs:
# Inject a couple Windows 2019 runs # Inject a couple Windows 2019 runs
- runs-on: windows-2019 - runs-on: windows-2019
python: '3.9' python: '3.9'
# Inject a few runs with different runtime libraries
- runs-on: windows-2022
python: '3.9'
args: >
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded
- runs-on: windows-2022
python: '3.10'
args: >
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL
# This needs a python built with MTd
# - runs-on: windows-2022
# python: '3.11'
# args: >
# -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug
- runs-on: windows-2022
python: '3.12'
args: >
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebugDLL
# Extra ubuntu latest job # Extra ubuntu latest job
- runs-on: ubuntu-latest - runs-on: ubuntu-latest
python: '3.11' python: '3.11'
@ -127,6 +145,7 @@ jobs:
-DPYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION=ON -DPYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION=ON
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON
-DPYBIND11_NUMPY_1_ONLY=ON -DPYBIND11_NUMPY_1_ONLY=ON
-DPYBIND11_PYTEST_ARGS=-v
-DDOWNLOAD_CATCH=ON -DDOWNLOAD_CATCH=ON
-DDOWNLOAD_EIGEN=ON -DDOWNLOAD_EIGEN=ON
-DCMAKE_CXX_STANDARD=11 -DCMAKE_CXX_STANDARD=11
@ -156,6 +175,7 @@ jobs:
-DPYBIND11_WERROR=ON -DPYBIND11_WERROR=ON
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF
-DPYBIND11_NUMPY_1_ONLY=ON -DPYBIND11_NUMPY_1_ONLY=ON
-DPYBIND11_PYTEST_ARGS=-v
-DDOWNLOAD_CATCH=ON -DDOWNLOAD_CATCH=ON
-DDOWNLOAD_EIGEN=ON -DDOWNLOAD_EIGEN=ON
-DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD=17
@ -175,6 +195,7 @@ jobs:
run: > run: >
cmake -S . -B build3 cmake -S . -B build3
-DPYBIND11_WERROR=ON -DPYBIND11_WERROR=ON
-DPYBIND11_PYTEST_ARGS=-v
-DDOWNLOAD_CATCH=ON -DDOWNLOAD_CATCH=ON
-DDOWNLOAD_EIGEN=ON -DDOWNLOAD_EIGEN=ON
-DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD=17
@ -998,7 +1019,6 @@ jobs:
git git
mingw-w64-${{matrix.env}}-gcc mingw-w64-${{matrix.env}}-gcc
mingw-w64-${{matrix.env}}-python-pip mingw-w64-${{matrix.env}}-python-pip
mingw-w64-${{matrix.env}}-python-numpy
mingw-w64-${{matrix.env}}-cmake mingw-w64-${{matrix.env}}-cmake
mingw-w64-${{matrix.env}}-make mingw-w64-${{matrix.env}}-make
mingw-w64-${{matrix.env}}-python-pytest mingw-w64-${{matrix.env}}-python-pytest
@ -1010,7 +1030,7 @@ jobs:
with: with:
msystem: ${{matrix.sys}} msystem: ${{matrix.sys}}
install: >- install: >-
git mingw-w64-${{matrix.env}}-python-numpy
mingw-w64-${{matrix.env}}-python-scipy mingw-w64-${{matrix.env}}-python-scipy
mingw-w64-${{matrix.env}}-eigen3 mingw-w64-${{matrix.env}}-eigen3

View File

@ -103,7 +103,7 @@ jobs:
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
- name: Generate artifact attestation for sdist and wheel - name: Generate artifact attestation for sdist and wheel
uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1.4.4
with: with:
subject-path: "*/pybind11*" subject-path: "*/pybind11*"

View File

@ -143,6 +143,9 @@ set(PYBIND11_HEADERS
include/pybind11/chrono.h include/pybind11/chrono.h
include/pybind11/common.h include/pybind11/common.h
include/pybind11/complex.h include/pybind11/complex.h
include/pybind11/conduit/pybind11_conduit_v1.h
include/pybind11/conduit/pybind11_platform_abi_id.h
include/pybind11/conduit/wrap_include_python_h.h
include/pybind11/options.h include/pybind11/options.h
include/pybind11/eigen.h include/pybind11/eigen.h
include/pybind11/eigen/common.h include/pybind11/eigen/common.h

View File

@ -1012,10 +1012,18 @@ 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");
}; };
template <typename T>
struct handle_type_name<Args<T>> {
static constexpr auto name = const_name("*args: ") + make_caster<T>::name;
};
template <> 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 <typename T>
struct handle_type_name<KWArgs<T>> {
static constexpr auto name = const_name("**kwargs: ") + make_caster<T>::name;
};
template <> template <>
struct handle_type_name<obj_attr_accessor> { struct handle_type_name<obj_attr_accessor> {
static constexpr auto name = const_name<obj_attr_accessor>(); static constexpr auto name = const_name<obj_attr_accessor>();

View File

@ -0,0 +1,15 @@
NOTE
----
The C++ code here
** only depends on <Python.h> **
and nothing else.
DO NOT ADD CODE WITH OTHER EXTERNAL DEPENDENCIES TO THIS DIRECTORY.
Read on:
pybind11_conduit_v1.h — Type-safe interoperability between different
independent Python/C++ bindings systems.

View File

@ -0,0 +1,111 @@
// Copyright (c) 2024 The pybind Community.
/* The pybind11_conduit_v1 feature enables type-safe interoperability between
* different independent Python/C++ bindings systems,
* including pybind11 versions with different PYBIND11_INTERNALS_VERSION's.
The naming of the feature is a bit misleading:
* The feature is in no way tied to pybind11 internals.
* It just happens to originate from pybind11 and currently still lives there.
* The only external dependency is <Python.h>.
The implementation is a VERY light-weight dependency. It is designed to be
compatible with any ISO C++11 (or higher) compiler, and does NOT require
C++ Exception Handling to be enabled.
Please see https://github.com/pybind/pybind11/pull/5296 for more background.
The implementation involves a
def _pybind11_conduit_v1_(
self,
pybind11_platform_abi_id: bytes,
cpp_type_info_capsule: capsule,
pointer_kind: bytes) -> capsule
method that is meant to be added to Python objects wrapping C++ objects
(e.g. pybind11::class_-wrapped types).
The design of the _pybind11_conduit_v1_ feature provides two layers of
protection against C++ ABI mismatches:
* The first and most important layer is that the pybind11_platform_abi_id's
must match between extensions. This will never be perfect, but is the same
pragmatic approach used in pybind11 since 2017
(https://github.com/pybind/pybind11/commit/96997a4b9d4ec3d389a570604394af5d5eee2557,
PYBIND11_INTERNALS_ID).
* The second layer is that the typeid(std::type_info).name()'s must match
between extensions.
The implementation below (which is shorter than this comment!), serves as a
battle-tested specification. The main API is this one function:
auto *cpp_pointer = pybind11_conduit_v1::get_type_pointer_ephemeral<YourType>(py_obj);
It is meant to be a minimalistic reference implementation, intentionally
without comprehensive error reporting. It is expected that major bindings
systems will roll their own, compatible implementations, potentially with
system-specific error reporting. The essential specifications all bindings
systems need to agree on are merely:
* PYBIND11_PLATFORM_ABI_ID (const char* literal).
* The cpp_type_info capsule (see below: a void *ptr and a const char *name).
* The cpp_conduit capsule (see below: a void *ptr and a const char *name).
* "raw_pointer_ephemeral" means: the lifetime of the pointer is the lifetime
of the py_obj.
*/
// THIS MUST STAY AT THE TOP!
#include "pybind11_platform_abi_id.h"
#include <Python.h>
#include <typeinfo>
namespace pybind11_conduit_v1 {
inline void *get_raw_pointer_ephemeral(PyObject *py_obj, const std::type_info *cpp_type_info) {
PyObject *cpp_type_info_capsule
= PyCapsule_New(const_cast<void *>(static_cast<const void *>(cpp_type_info)),
typeid(std::type_info).name(),
nullptr);
if (cpp_type_info_capsule == nullptr) {
return nullptr;
}
PyObject *cpp_conduit = PyObject_CallMethod(py_obj,
"_pybind11_conduit_v1_",
"yOy",
PYBIND11_PLATFORM_ABI_ID,
cpp_type_info_capsule,
"raw_pointer_ephemeral");
Py_DECREF(cpp_type_info_capsule);
if (cpp_conduit == nullptr) {
return nullptr;
}
void *raw_ptr = PyCapsule_GetPointer(cpp_conduit, cpp_type_info->name());
Py_DECREF(cpp_conduit);
if (PyErr_Occurred()) {
return nullptr;
}
return raw_ptr;
}
template <typename T>
T *get_type_pointer_ephemeral(PyObject *py_obj) {
void *raw_ptr = get_raw_pointer_ephemeral(py_obj, &typeid(T));
if (raw_ptr == nullptr) {
return nullptr;
}
return static_cast<T *>(raw_ptr);
}
} // namespace pybind11_conduit_v1

View File

@ -0,0 +1,88 @@
#pragma once
// Copyright (c) 2024 The pybind Community.
// To maximize reusability:
// DO NOT ADD CODE THAT REQUIRES C++ EXCEPTION HANDLING.
#include "wrap_include_python_h.h"
// Implementation details. DO NOT USE ELSEWHERE. (Unfortunately we cannot #undef them.)
// This is duplicated here to maximize portability.
#define PYBIND11_PLATFORM_ABI_ID_STRINGIFY(x) #x
#define PYBIND11_PLATFORM_ABI_ID_TOSTRING(x) PYBIND11_PLATFORM_ABI_ID_STRINGIFY(x)
// On MSVC, debug and release builds are not ABI-compatible!
#if defined(_MSC_VER) && defined(_DEBUG)
# define PYBIND11_BUILD_TYPE "_debug"
#else
# define PYBIND11_BUILD_TYPE ""
#endif
// Let's assume that different compilers are ABI-incompatible.
// A user can manually set this string if they know their
// compiler is compatible.
#ifndef PYBIND11_COMPILER_TYPE
# if defined(_MSC_VER)
# define PYBIND11_COMPILER_TYPE "_msvc"
# elif defined(__INTEL_COMPILER)
# define PYBIND11_COMPILER_TYPE "_icc"
# elif defined(__clang__)
# define PYBIND11_COMPILER_TYPE "_clang"
# elif defined(__PGI)
# define PYBIND11_COMPILER_TYPE "_pgi"
# elif defined(__MINGW32__)
# define PYBIND11_COMPILER_TYPE "_mingw"
# elif defined(__CYGWIN__)
# define PYBIND11_COMPILER_TYPE "_gcc_cygwin"
# elif defined(__GNUC__)
# define PYBIND11_COMPILER_TYPE "_gcc"
# else
# define PYBIND11_COMPILER_TYPE "_unknown"
# endif
#endif
// Also standard libs
#ifndef PYBIND11_STDLIB
# if defined(_LIBCPP_VERSION)
# define PYBIND11_STDLIB "_libcpp"
# elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
# define PYBIND11_STDLIB "_libstdcpp"
# else
# define PYBIND11_STDLIB ""
# endif
#endif
#ifndef PYBIND11_BUILD_ABI
# if defined(__GXX_ABI_VERSION) // Linux/OSX.
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_PLATFORM_ABI_ID_TOSTRING(__GXX_ABI_VERSION)
# elif defined(_MSC_VER) // See PR #4953.
# if defined(_MT) && defined(_DLL) // Corresponding to CL command line options /MD or /MDd.
# if (_MSC_VER) / 100 == 19
# define PYBIND11_BUILD_ABI "_md_mscver19"
# else
# error "Unknown major version for MSC_VER: PLEASE REVISE THIS CODE."
# endif
# elif defined(_MT) // Corresponding to CL command line options /MT or /MTd.
# define PYBIND11_BUILD_ABI "_mt_mscver" PYBIND11_PLATFORM_ABI_ID_TOSTRING(_MSC_VER)
# else
# if (_MSC_VER) / 100 == 19
# define PYBIND11_BUILD_ABI "_none_mscver19"
# else
# error "Unknown major version for MSC_VER: PLEASE REVISE THIS CODE."
# endif
# endif
# elif defined(__NVCOMPILER) // NVHPC (PGI-based).
# define PYBIND11_BUILD_ABI "" // TODO: What should be here, to prevent UB?
# else
# error "Unknown platform or compiler: PLEASE REVISE THIS CODE."
# endif
#endif
#ifndef PYBIND11_INTERNALS_KIND
# define PYBIND11_INTERNALS_KIND ""
#endif
#define PYBIND11_PLATFORM_ABI_ID \
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
PYBIND11_BUILD_TYPE

View File

@ -0,0 +1,72 @@
#pragma once
// Copyright (c) 2024 The pybind Community.
// STRONG REQUIREMENT:
// This header is a wrapper around `#include <Python.h>`, therefore it
// MUST BE INCLUDED BEFORE ANY STANDARD HEADERS are included.
// See also:
// https://docs.python.org/3/c-api/intro.html#include-files
// Quoting from there:
// Note: Since Python may define some pre-processor definitions which affect
// the standard headers on some systems, you must include Python.h before
// any standard headers are included.
// To maximize reusability:
// DO NOT ADD CODE THAT REQUIRES C++ EXCEPTION HANDLING.
// Disable linking to pythonX_d.lib on Windows in debug mode.
#if defined(_MSC_VER) && defined(_DEBUG) && !defined(Py_DEBUG)
// Workaround for a VS 2022 issue.
// See https://github.com/pybind/pybind11/pull/3497 for full context.
// NOTE: This workaround knowingly violates the Python.h include order
// requirement (see above).
# include <yvals.h>
# if _MSVC_STL_VERSION >= 143
# include <crtdefs.h>
# endif
# define PYBIND11_DEBUG_MARKER
# undef _DEBUG
#endif
// Don't let Python.h #define (v)snprintf as macro because they are implemented
// properly in Visual Studio since 2015.
#if defined(_MSC_VER)
# define HAVE_SNPRINTF 1
#endif
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4505)
// C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed
#endif
#include <Python.h>
#include <frameobject.h>
#include <pythread.h>
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
#if defined(PYBIND11_DEBUG_MARKER)
# define _DEBUG
# undef PYBIND11_DEBUG_MARKER
#endif
// Python #defines overrides on all sorts of core functions, which
// tends to wreak havok in C++ codebases that expect these to work
// like regular functions (potentially with several overloads).
#if defined(isalnum)
# undef isalnum
# undef isalpha
# undef islower
# undef isspace
# undef isupper
# undef tolower
# undef toupper
#endif
#if defined(copysign)
# undef copysign
#endif

View File

@ -583,9 +583,9 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
return -1; return -1;
} }
std::memset(view, 0, sizeof(Py_buffer)); std::memset(view, 0, sizeof(Py_buffer));
buffer_info *info = nullptr; std::unique_ptr<buffer_info> info = nullptr;
try { try {
info = tinfo->get_buffer(obj, tinfo->get_buffer_data); info.reset(tinfo->get_buffer(obj, tinfo->get_buffer_data));
} catch (...) { } catch (...) {
try_translate_exceptions(); try_translate_exceptions();
raise_from(PyExc_BufferError, "Error getting buffer"); raise_from(PyExc_BufferError, "Error getting buffer");
@ -596,7 +596,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
} }
if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) { if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) {
delete info;
// view->obj = nullptr; // Was just memset to 0, so not necessary // view->obj = nullptr; // Was just memset to 0, so not necessary
set_error(PyExc_BufferError, "Writable buffer requested for readonly storage"); set_error(PyExc_BufferError, "Writable buffer requested for readonly storage");
return -1; return -1;
@ -604,9 +603,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
// Fill in all the information, and then downgrade as requested by the caller, or raise an // Fill in all the information, and then downgrade as requested by the caller, or raise an
// error if that's not possible. // error if that's not possible.
view->obj = obj;
view->internal = info;
view->buf = info->ptr;
view->itemsize = info->itemsize; view->itemsize = info->itemsize;
view->len = view->itemsize; view->len = view->itemsize;
for (auto s : info->shape) { for (auto s : info->shape) {
@ -624,7 +620,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
if ((flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) { if ((flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) {
if (PyBuffer_IsContiguous(view, 'C') == 0) { if (PyBuffer_IsContiguous(view, 'C') == 0) {
std::memset(view, 0, sizeof(Py_buffer)); std::memset(view, 0, sizeof(Py_buffer));
delete info;
set_error(PyExc_BufferError, set_error(PyExc_BufferError,
"C-contiguous buffer requested for discontiguous storage"); "C-contiguous buffer requested for discontiguous storage");
return -1; return -1;
@ -632,7 +627,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
} else if ((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) { } else if ((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) {
if (PyBuffer_IsContiguous(view, 'F') == 0) { if (PyBuffer_IsContiguous(view, 'F') == 0) {
std::memset(view, 0, sizeof(Py_buffer)); std::memset(view, 0, sizeof(Py_buffer));
delete info;
set_error(PyExc_BufferError, set_error(PyExc_BufferError,
"Fortran-contiguous buffer requested for discontiguous storage"); "Fortran-contiguous buffer requested for discontiguous storage");
return -1; return -1;
@ -640,7 +634,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
} else if ((flags & PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS) { } else if ((flags & PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS) {
if (PyBuffer_IsContiguous(view, 'A') == 0) { if (PyBuffer_IsContiguous(view, 'A') == 0) {
std::memset(view, 0, sizeof(Py_buffer)); std::memset(view, 0, sizeof(Py_buffer));
delete info;
set_error(PyExc_BufferError, "Contiguous buffer requested for discontiguous storage"); set_error(PyExc_BufferError, "Contiguous buffer requested for discontiguous storage");
return -1; return -1;
} }
@ -650,7 +643,6 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
// https://docs.python.org/3/c-api/buffer.html#contiguity-requests // https://docs.python.org/3/c-api/buffer.html#contiguity-requests
if (PyBuffer_IsContiguous(view, 'C') == 0) { if (PyBuffer_IsContiguous(view, 'C') == 0) {
std::memset(view, 0, sizeof(Py_buffer)); std::memset(view, 0, sizeof(Py_buffer));
delete info;
set_error(PyExc_BufferError, set_error(PyExc_BufferError,
"C-contiguous buffer requested for discontiguous storage"); "C-contiguous buffer requested for discontiguous storage");
return -1; return -1;
@ -665,6 +657,11 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
} }
} }
// Set these after all checks so they don't leak out into the caller, and can be automatically
// cleaned up on error.
view->buf = info->ptr;
view->internal = info.release();
view->obj = obj;
Py_INCREF(view->obj); Py_INCREF(view->obj);
return 0; return 0;
} }

View File

@ -9,6 +9,11 @@
#pragma once #pragma once
#include <pybind11/conduit/wrap_include_python_h.h>
#if PY_VERSION_HEX < 0x03080000
# error "PYTHON < 3.8 IS UNSUPPORTED. pybind11 v2.13 was the last to support Python 3.7."
#endif
#define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MAJOR 2
#define PYBIND11_VERSION_MINOR 14 #define PYBIND11_VERSION_MINOR 14
#define PYBIND11_VERSION_PATCH 0.dev1 #define PYBIND11_VERSION_PATCH 0.dev1
@ -204,31 +209,6 @@
# define PYBIND11_MAYBE_UNUSED __attribute__((__unused__)) # define PYBIND11_MAYBE_UNUSED __attribute__((__unused__))
#endif #endif
/* Don't let Python.h #define (v)snprintf as macro because they are implemented
properly in Visual Studio since 2015. */
#if defined(_MSC_VER)
# define HAVE_SNPRINTF 1
#endif
/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode
#if defined(_MSC_VER)
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_MSVC(4505)
// C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed (PyPy only)
# if defined(_DEBUG) && !defined(Py_DEBUG)
// Workaround for a VS 2022 issue.
// NOTE: This workaround knowingly violates the Python.h include order requirement:
// https://docs.python.org/3/c-api/intro.html#include-files
// See https://github.com/pybind/pybind11/pull/3497 for full context.
# include <yvals.h>
# if _MSVC_STL_VERSION >= 143
# include <crtdefs.h>
# endif
# define PYBIND11_DEBUG_MARKER
# undef _DEBUG
# endif
#endif
// https://en.cppreference.com/w/c/chrono/localtime // https://en.cppreference.com/w/c/chrono/localtime
#if defined(__STDC_LIB_EXT1__) && !defined(__STDC_WANT_LIB_EXT1__) #if defined(__STDC_LIB_EXT1__) && !defined(__STDC_WANT_LIB_EXT1__)
# define __STDC_WANT_LIB_EXT1__ # define __STDC_WANT_LIB_EXT1__
@ -263,30 +243,6 @@ PYBIND11_WARNING_DISABLE_MSVC(4505)
# endif # endif
#endif #endif
#include <Python.h>
#if PY_VERSION_HEX < 0x03080000
# error "PYTHON < 3.8 IS UNSUPPORTED. pybind11 v2.13 was the last to support Python 3.7."
#endif
#include <frameobject.h>
#include <pythread.h>
/* Python #defines overrides on all sorts of core functions, which
tends to weak havok in C++ codebases that expect these to work
like regular functions (potentially with several overloads) */
#if defined(isalnum)
# undef isalnum
# undef isalpha
# undef islower
# undef isspace
# undef isupper
# undef tolower
# undef toupper
#endif
#if defined(copysign)
# undef copysign
#endif
#if defined(PYBIND11_NUMPY_1_ONLY) #if defined(PYBIND11_NUMPY_1_ONLY)
# define PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED # define PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED
#endif #endif
@ -295,14 +251,6 @@ PYBIND11_WARNING_DISABLE_MSVC(4505)
# define PYBIND11_SIMPLE_GIL_MANAGEMENT # define PYBIND11_SIMPLE_GIL_MANAGEMENT
#endif #endif
#if defined(_MSC_VER)
# if defined(PYBIND11_DEBUG_MARKER)
# define _DEBUG
# undef PYBIND11_DEBUG_MARKER
# endif
PYBIND11_WARNING_POP
#endif
#include <cstddef> #include <cstddef>
#include <cstring> #include <cstring>
#include <exception> #include <exception>

View File

@ -410,7 +410,7 @@ struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
template <typename Class, typename... Extra> template <typename Class, typename... Extra>
void execute(Class &cl, const Extra &...extra) && { void execute(Class &cl, const Extra &...extra) && {
cl.def("__getstate__", std::move(get)); cl.def("__getstate__", std::move(get), pos_only());
#if defined(PYBIND11_CPP14) #if defined(PYBIND11_CPP14)
cl.def( cl.def(

View File

@ -15,6 +15,7 @@
# include <pybind11/gil.h> # include <pybind11/gil.h>
#endif #endif
#include <pybind11/conduit/pybind11_platform_abi_id.h>
#include <pybind11/pytypes.h> #include <pybind11/pytypes.h>
#include <exception> #include <exception>
@ -269,67 +270,6 @@ struct type_info {
bool module_local : 1; bool module_local : 1;
}; };
/// On MSVC, debug and release builds are not ABI-compatible!
#if defined(_MSC_VER) && defined(_DEBUG)
# define PYBIND11_BUILD_TYPE "_debug"
#else
# define PYBIND11_BUILD_TYPE ""
#endif
/// Let's assume that different compilers are ABI-incompatible.
/// A user can manually set this string if they know their
/// compiler is compatible.
#ifndef PYBIND11_COMPILER_TYPE
# if defined(_MSC_VER)
# define PYBIND11_COMPILER_TYPE "_msvc"
# elif defined(__INTEL_COMPILER)
# define PYBIND11_COMPILER_TYPE "_icc"
# elif defined(__clang__)
# define PYBIND11_COMPILER_TYPE "_clang"
# elif defined(__PGI)
# define PYBIND11_COMPILER_TYPE "_pgi"
# elif defined(__MINGW32__)
# define PYBIND11_COMPILER_TYPE "_mingw"
# elif defined(__CYGWIN__)
# define PYBIND11_COMPILER_TYPE "_gcc_cygwin"
# elif defined(__GNUC__)
# define PYBIND11_COMPILER_TYPE "_gcc"
# else
# define PYBIND11_COMPILER_TYPE "_unknown"
# endif
#endif
/// Also standard libs
#ifndef PYBIND11_STDLIB
# if defined(_LIBCPP_VERSION)
# define PYBIND11_STDLIB "_libcpp"
# elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
# define PYBIND11_STDLIB "_libstdcpp"
# else
# define PYBIND11_STDLIB ""
# endif
#endif
/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility.
/// On MSVC, changes in _MSC_VER may indicate ABI incompatibility (#2898).
#ifndef PYBIND11_BUILD_ABI
# if defined(__GXX_ABI_VERSION)
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION)
# elif defined(_MSC_VER)
# define PYBIND11_BUILD_ABI "_mscver" PYBIND11_TOSTRING(_MSC_VER)
# else
# define PYBIND11_BUILD_ABI ""
# endif
#endif
#ifndef PYBIND11_INTERNALS_KIND
# define PYBIND11_INTERNALS_KIND ""
#endif
#define PYBIND11_PLATFORM_ABI_ID \
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
PYBIND11_BUILD_TYPE
#define PYBIND11_INTERNALS_ID \ #define PYBIND11_INTERNALS_ID \
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \ "__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
PYBIND11_PLATFORM_ABI_ID "__" PYBIND11_PLATFORM_ABI_ID "__"

View File

@ -212,6 +212,7 @@ constexpr int platform_lookup(int I, Ints... Is) {
} }
struct npy_api { struct npy_api {
// If you change this code, please review `normalized_dtype_num` below.
enum constants { enum constants {
NPY_ARRAY_C_CONTIGUOUS_ = 0x0001, NPY_ARRAY_C_CONTIGUOUS_ = 0x0001,
NPY_ARRAY_F_CONTIGUOUS_ = 0x0002, NPY_ARRAY_F_CONTIGUOUS_ = 0x0002,
@ -384,6 +385,74 @@ private:
} }
}; };
// This table normalizes typenums by mapping NPY_INT_, NPY_LONG, ... to NPY_INT32_, NPY_INT64, ...
// This is needed to correctly handle situations where multiple typenums map to the same type,
// e.g. NPY_LONG_ may be equivalent to NPY_INT_ or NPY_LONGLONG_ despite having a different
// typenum. The normalized typenum should always match the values used in npy_format_descriptor.
// If you change this code, please review `enum constants` above.
static constexpr int normalized_dtype_num[npy_api::NPY_VOID_ + 1] = {
// NPY_BOOL_ =>
npy_api::NPY_BOOL_,
// NPY_BYTE_ =>
npy_api::NPY_BYTE_,
// NPY_UBYTE_ =>
npy_api::NPY_UBYTE_,
// NPY_SHORT_ =>
npy_api::NPY_INT16_,
// NPY_USHORT_ =>
npy_api::NPY_UINT16_,
// NPY_INT_ =>
sizeof(int) == sizeof(std::int16_t) ? npy_api::NPY_INT16_
: sizeof(int) == sizeof(std::int32_t) ? npy_api::NPY_INT32_
: sizeof(int) == sizeof(std::int64_t) ? npy_api::NPY_INT64_
: npy_api::NPY_INT_,
// NPY_UINT_ =>
sizeof(unsigned int) == sizeof(std::uint16_t) ? npy_api::NPY_UINT16_
: sizeof(unsigned int) == sizeof(std::uint32_t) ? npy_api::NPY_UINT32_
: sizeof(unsigned int) == sizeof(std::uint64_t) ? npy_api::NPY_UINT64_
: npy_api::NPY_UINT_,
// NPY_LONG_ =>
sizeof(long) == sizeof(std::int16_t) ? npy_api::NPY_INT16_
: sizeof(long) == sizeof(std::int32_t) ? npy_api::NPY_INT32_
: sizeof(long) == sizeof(std::int64_t) ? npy_api::NPY_INT64_
: npy_api::NPY_LONG_,
// NPY_ULONG_ =>
sizeof(unsigned long) == sizeof(std::uint16_t) ? npy_api::NPY_UINT16_
: sizeof(unsigned long) == sizeof(std::uint32_t) ? npy_api::NPY_UINT32_
: sizeof(unsigned long) == sizeof(std::uint64_t) ? npy_api::NPY_UINT64_
: npy_api::NPY_ULONG_,
// NPY_LONGLONG_ =>
sizeof(long long) == sizeof(std::int16_t) ? npy_api::NPY_INT16_
: sizeof(long long) == sizeof(std::int32_t) ? npy_api::NPY_INT32_
: sizeof(long long) == sizeof(std::int64_t) ? npy_api::NPY_INT64_
: npy_api::NPY_LONGLONG_,
// NPY_ULONGLONG_ =>
sizeof(unsigned long long) == sizeof(std::uint16_t) ? npy_api::NPY_UINT16_
: sizeof(unsigned long long) == sizeof(std::uint32_t) ? npy_api::NPY_UINT32_
: sizeof(unsigned long long) == sizeof(std::uint64_t) ? npy_api::NPY_UINT64_
: npy_api::NPY_ULONGLONG_,
// NPY_FLOAT_ =>
npy_api::NPY_FLOAT_,
// NPY_DOUBLE_ =>
npy_api::NPY_DOUBLE_,
// NPY_LONGDOUBLE_ =>
npy_api::NPY_LONGDOUBLE_,
// NPY_CFLOAT_ =>
npy_api::NPY_CFLOAT_,
// NPY_CDOUBLE_ =>
npy_api::NPY_CDOUBLE_,
// NPY_CLONGDOUBLE_ =>
npy_api::NPY_CLONGDOUBLE_,
// NPY_OBJECT_ =>
npy_api::NPY_OBJECT_,
// NPY_STRING_ =>
npy_api::NPY_STRING_,
// NPY_UNICODE_ =>
npy_api::NPY_UNICODE_,
// NPY_VOID_ =>
npy_api::NPY_VOID_,
};
inline PyArray_Proxy *array_proxy(void *ptr) { return reinterpret_cast<PyArray_Proxy *>(ptr); } inline PyArray_Proxy *array_proxy(void *ptr) { return reinterpret_cast<PyArray_Proxy *>(ptr); }
inline const PyArray_Proxy *array_proxy(const void *ptr) { inline const PyArray_Proxy *array_proxy(const void *ptr) {
@ -684,6 +753,13 @@ public:
return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::dtype(); return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::dtype();
} }
/// Return the type number associated with a C++ type.
/// This is the constexpr equivalent of `dtype::of<T>().num()`.
template <typename T>
static constexpr int num_of() {
return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::value;
}
/// Size of the data type in bytes. /// Size of the data type in bytes.
#ifdef PYBIND11_NUMPY_1_ONLY #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; }
@ -725,7 +801,9 @@ public:
return detail::array_descriptor_proxy(m_ptr)->type; return detail::array_descriptor_proxy(m_ptr)->type;
} }
/// type number of dtype. /// Type number of dtype. Note that different values may be returned for equivalent types,
/// e.g. even though ``long`` may be equivalent to ``int`` or ``long long``, they still have
/// different type numbers. Consider using `normalized_num` to avoid this.
int num() const { int num() const {
// Note: The signature, `dtype::num` follows the naming of NumPy's public // Note: The signature, `dtype::num` follows the naming of NumPy's public
// Python API (i.e., ``dtype.num``), rather than its internal // Python API (i.e., ``dtype.num``), rather than its internal
@ -733,6 +811,17 @@ public:
return detail::array_descriptor_proxy(m_ptr)->type_num; return detail::array_descriptor_proxy(m_ptr)->type_num;
} }
/// Type number of dtype, normalized to match the return value of `num_of` for equivalent
/// types. This function can be used to write switch statements that correctly handle
/// equivalent types with different type numbers.
int normalized_num() const {
int value = num();
if (value >= 0 && value <= detail::npy_api::NPY_VOID_) {
return detail::normalized_dtype_num[value];
}
return value;
}
/// 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; }
@ -760,6 +849,15 @@ public:
} }
#endif #endif
/// NumPy array type char
char type() const { return detail::array_descriptor_proxy(m_ptr)->type; }
/// NumPy array type num
int type_num() const { return detail::array_descriptor_proxy(m_ptr)->type_num; }
/// NumPy array element size
int elsize() const { return detail::array_descriptor_proxy(m_ptr)->elsize; }
private: private:
static object &_dtype_from_pep3118() { static object &_dtype_from_pep3118() {
PYBIND11_CONSTINIT static gil_safe_call_once_and_store<object> storage; PYBIND11_CONSTINIT static gil_safe_call_once_and_store<object> storage;
@ -965,6 +1063,9 @@ public:
/// Return the NumPy array flags /// Return the NumPy array flags
int flags() const { return detail::array_proxy(m_ptr)->flags; } int flags() const { return detail::array_proxy(m_ptr)->flags; }
/// Mutable NumPy array flags
int &flags() { return detail::array_proxy(m_ptr)->flags; }
/// If set, the array is writeable (otherwise the buffer is read-only) /// If set, the array is writeable (otherwise the buffer is read-only)
bool writeable() const { bool writeable() const {
return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_WRITEABLE_); return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_WRITEABLE_);
@ -1428,7 +1529,11 @@ public:
}; };
template <typename T> template <typename T>
struct npy_format_descriptor<T, enable_if_t<is_same_ignoring_cvref<T, PyObject *>::value>> { struct npy_format_descriptor<
T,
enable_if_t<is_same_ignoring_cvref<T, PyObject *>::value
|| ((std::is_same<T, handle>::value || std::is_same<T, object>::value)
&& sizeof(T) == sizeof(PyObject *))>> {
static constexpr auto name = const_name("object"); static constexpr auto name = const_name("object");
static constexpr int value = npy_api::NPY_OBJECT_; static constexpr int value = npy_api::NPY_OBJECT_;

View File

@ -301,9 +301,20 @@ protected:
constexpr bool has_kw_only_args = any_of<std::is_same<kw_only, Extra>...>::value, constexpr bool has_kw_only_args = any_of<std::is_same<kw_only, Extra>...>::value,
has_pos_only_args = any_of<std::is_same<pos_only, Extra>...>::value, has_pos_only_args = any_of<std::is_same<pos_only, Extra>...>::value,
has_arg_annotations = any_of<is_keyword<Extra>...>::value; has_arg_annotations = any_of<is_keyword<Extra>...>::value;
constexpr bool has_is_method = any_of<std::is_same<is_method, Extra>...>::value;
// The implicit `self` argument is not present and not counted in method definitions.
constexpr bool has_args = cast_in::args_pos >= 0;
constexpr bool is_method_with_self_arg_only = has_is_method && !has_args;
static_assert(has_arg_annotations || !has_kw_only_args, static_assert(has_arg_annotations || !has_kw_only_args,
"py::kw_only requires the use of argument annotations"); "py::kw_only requires the use of argument annotations");
static_assert(has_arg_annotations || !has_pos_only_args, static_assert(((/* Need `py::arg("arg_name")` annotation in function/method. */
has_arg_annotations)
|| (/* Allow methods with no arguments `def method(self, /): ...`.
* A method has at least one argument `self`. There can be no
* `py::arg` annotation. E.g. `class.def("method", py::pos_only())`.
*/
is_method_with_self_arg_only))
|| !has_pos_only_args,
"py::pos_only requires the use of argument annotations (for docstrings " "py::pos_only requires the use of argument annotations (for docstrings "
"and aligning the annotations to the argument)"); "and aligning the annotations to the argument)");
@ -2022,9 +2033,11 @@ struct enum_base {
.format(std::move(type_name), enum_name(arg), int_(arg)); .format(std::move(type_name), enum_name(arg), int_(arg));
}, },
name("__repr__"), name("__repr__"),
is_method(m_base)); is_method(m_base),
pos_only());
m_base.attr("name") = property(cpp_function(&enum_name, name("name"), is_method(m_base))); m_base.attr("name")
= property(cpp_function(&enum_name, name("name"), is_method(m_base), pos_only()));
m_base.attr("__str__") = cpp_function( m_base.attr("__str__") = cpp_function(
[](handle arg) -> str { [](handle arg) -> str {
@ -2032,7 +2045,8 @@ struct enum_base {
return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg)); return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg));
}, },
name("__str__"), name("__str__"),
is_method(m_base)); is_method(m_base),
pos_only());
if (options::show_enum_members_docstring()) { if (options::show_enum_members_docstring()) {
m_base.attr("__doc__") = static_property( m_base.attr("__doc__") = static_property(
@ -2087,7 +2101,8 @@ struct enum_base {
}, \ }, \
name(op), \ name(op), \
is_method(m_base), \ is_method(m_base), \
arg("other")) arg("other"), \
pos_only())
#define PYBIND11_ENUM_OP_CONV(op, expr) \ #define PYBIND11_ENUM_OP_CONV(op, expr) \
m_base.attr(op) = cpp_function( \ m_base.attr(op) = cpp_function( \
@ -2097,7 +2112,8 @@ struct enum_base {
}, \ }, \
name(op), \ name(op), \
is_method(m_base), \ is_method(m_base), \
arg("other")) arg("other"), \
pos_only())
#define PYBIND11_ENUM_OP_CONV_LHS(op, expr) \ #define PYBIND11_ENUM_OP_CONV_LHS(op, expr) \
m_base.attr(op) = cpp_function( \ m_base.attr(op) = cpp_function( \
@ -2107,7 +2123,8 @@ struct enum_base {
}, \ }, \
name(op), \ name(op), \
is_method(m_base), \ is_method(m_base), \
arg("other")) arg("other"), \
pos_only())
if (is_convertible) { if (is_convertible) {
PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b)); PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b));
@ -2127,7 +2144,8 @@ struct enum_base {
m_base.attr("__invert__") m_base.attr("__invert__")
= cpp_function([](const object &arg) { return ~(int_(arg)); }, = cpp_function([](const object &arg) { return ~(int_(arg)); },
name("__invert__"), name("__invert__"),
is_method(m_base)); is_method(m_base),
pos_only());
} }
} else { } else {
PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false); PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false);
@ -2147,11 +2165,15 @@ struct enum_base {
#undef PYBIND11_ENUM_OP_CONV #undef PYBIND11_ENUM_OP_CONV
#undef PYBIND11_ENUM_OP_STRICT #undef PYBIND11_ENUM_OP_STRICT
m_base.attr("__getstate__") = cpp_function( m_base.attr("__getstate__") = cpp_function([](const object &arg) { return int_(arg); },
[](const object &arg) { return int_(arg); }, name("__getstate__"), is_method(m_base)); name("__getstate__"),
is_method(m_base),
pos_only());
m_base.attr("__hash__") = cpp_function( m_base.attr("__hash__") = cpp_function([](const object &arg) { return int_(arg); },
[](const object &arg) { return int_(arg); }, name("__hash__"), is_method(m_base)); name("__hash__"),
is_method(m_base),
pos_only());
} }
PYBIND11_NOINLINE void value(char const *name_, object value, const char *doc = nullptr) { PYBIND11_NOINLINE void value(char const *name_, object value, const char *doc = nullptr) {
@ -2243,9 +2265,9 @@ public:
m_base.init(is_arithmetic, is_convertible); m_base.init(is_arithmetic, is_convertible);
def(init([](Scalar i) { return static_cast<Type>(i); }), arg("value")); def(init([](Scalar i) { return static_cast<Type>(i); }), arg("value"));
def_property_readonly("value", [](Type value) { return (Scalar) value; }); def_property_readonly("value", [](Type value) { return (Scalar) value; }, pos_only());
def("__int__", [](Type value) { return (Scalar) value; }); def("__int__", [](Type value) { return (Scalar) value; }, pos_only());
def("__index__", [](Type value) { return (Scalar) value; }); def("__index__", [](Type value) { return (Scalar) value; }, pos_only());
attr("__setstate__") = cpp_function( attr("__setstate__") = cpp_function(
[](detail::value_and_holder &v_h, Scalar arg) { [](detail::value_and_holder &v_h, Scalar arg) {
detail::initimpl::setstate<Base>( detail::initimpl::setstate<Base>(
@ -2254,7 +2276,8 @@ public:
detail::is_new_style_constructor(), detail::is_new_style_constructor(),
pybind11::name("__setstate__"), pybind11::name("__setstate__"),
is_method(*this), is_method(*this),
arg("state")); arg("state"),
pos_only());
} }
/// Export enumeration entries into the parent scope /// Export enumeration entries into the parent scope
@ -2440,7 +2463,8 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
if (!detail::get_type_info(typeid(state), false)) { if (!detail::get_type_info(typeid(state), false)) {
class_<state>(handle(), "iterator", pybind11::module_local()) class_<state>(handle(), "iterator", pybind11::module_local())
.def("__iter__", [](state &s) -> state & { return s; }) .def(
"__iter__", [](state &s) -> state & { return s; }, pos_only())
.def( .def(
"__next__", "__next__",
[](state &s) -> ValueType { [](state &s) -> ValueType {
@ -2457,6 +2481,7 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263 // NOLINTNEXTLINE(readability-const-return-type) // PR #3263
}, },
std::forward<Extra>(extra)..., std::forward<Extra>(extra)...,
pos_only(),
Policy); Policy);
} }

View File

@ -2226,6 +2226,18 @@ class kwargs : public dict {
PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check) PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check)
}; };
// Subclasses of args and kwargs to support type hinting
// as defined in PEP 484. See #5357 for more info.
template <typename T>
class Args : public args {
using args::args;
};
template <typename T>
class KWArgs : public kwargs {
using kwargs::kwargs;
};
class anyset : public object { class anyset : public object {
public: public:
PYBIND11_OBJECT(anyset, object, PyAnySet_Check) PYBIND11_OBJECT(anyset, object, PyAnySet_Check)

View File

@ -491,6 +491,12 @@ foreach(target ${test_targets})
if(SKBUILD) if(SKBUILD)
install(TARGETS ${target} LIBRARY DESTINATION .) install(TARGETS ${target} LIBRARY DESTINATION .)
endif() endif()
if("${target}" STREQUAL "exo_planet_c_api")
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang|NVHPC)")
target_compile_options(${target} PRIVATE -fno-exceptions)
endif()
endif()
endforeach() endforeach()
# Provide nice organisation in IDEs # Provide nice organisation in IDEs

View File

@ -198,10 +198,11 @@ def pytest_assertrepr_compare(op, left, right): # noqa: ARG001
def gc_collect(): def gc_collect():
"""Run the garbage collector twice (needed when running """Run the garbage collector three times (needed when running
reference counting tests with PyPy)""" reference counting tests with PyPy)"""
gc.collect() gc.collect()
gc.collect() gc.collect()
gc.collect()
def pytest_configure(): def pytest_configure():

View File

@ -312,8 +312,16 @@ void print_created(T *inst, Values &&...values) {
} }
template <class T, typename... Values> template <class T, typename... Values>
void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values
/*
* On GraalPy, destructors can trigger anywhere and this can cause random
* failures in unrelated tests.
*/
#if !defined(GRAALVM_PYTHON)
print_constr_details(inst, "destroyed", values...); print_constr_details(inst, "destroyed", values...);
track_destroyed(inst); track_destroyed(inst);
#else
py::detail::silence_unused_warnings(inst, values...);
#endif
} }
template <class T, typename... Values> template <class T, typename... Values>
void print_values(T *inst, Values &&...values) { void print_values(T *inst, Values &&...values) {

View File

@ -1,59 +1,33 @@
// Copyright (c) 2024 The pybind Community. // Copyright (c) 2024 The pybind Community.
// In production situations it is totally fine to build with
// C++ Exception Handling enabled. However, here we want to ensure that
// C++ Exception Handling is not required.
#if defined(_MSC_VER) || defined(__EMSCRIPTEN__)
// Too much trouble making the required cmake changes (see PR #5375).
#else
# ifdef __cpp_exceptions
// https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#__cpp_exceptions
# error This test is meant to be built with C++ Exception Handling disabled, but __cpp_exceptions is defined.
# endif
# ifdef __EXCEPTIONS
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
# error This test is meant to be built with C++ Exception Handling disabled, but __EXCEPTIONS is defined.
# endif
#endif
// THIS MUST STAY AT THE TOP! // THIS MUST STAY AT THE TOP!
#include <pybind11/pybind11.h> // EXCLUSIVELY for PYBIND11_PLATFORM_ABI_ID #include <pybind11/conduit/pybind11_conduit_v1.h> // VERY light-weight dependency.
// Potential future direction to maximize reusability:
// (e.g. for use from SWIG, Cython, PyCLIF, nanobind):
// #include <pybind11/compat/platform_abi_id.h>
// This would only depend on:
// 1. A C++ compiler, WITHOUT requiring -fexceptions.
// 2. Python.h
#include "test_cpp_conduit_traveler_types.h" #include "test_cpp_conduit_traveler_types.h"
#include <Python.h> #include <Python.h>
#include <typeinfo>
namespace { namespace {
void *get_cpp_conduit_void_ptr(PyObject *py_obj, const std::type_info *cpp_type_info) {
PyObject *cpp_type_info_capsule
= PyCapsule_New(const_cast<void *>(static_cast<const void *>(cpp_type_info)),
typeid(std::type_info).name(),
nullptr);
if (cpp_type_info_capsule == nullptr) {
return nullptr;
}
PyObject *cpp_conduit = PyObject_CallMethod(py_obj,
"_pybind11_conduit_v1_",
"yOy",
PYBIND11_PLATFORM_ABI_ID,
cpp_type_info_capsule,
"raw_pointer_ephemeral");
Py_DECREF(cpp_type_info_capsule);
if (cpp_conduit == nullptr) {
return nullptr;
}
void *void_ptr = PyCapsule_GetPointer(cpp_conduit, cpp_type_info->name());
Py_DECREF(cpp_conduit);
if (PyErr_Occurred()) {
return nullptr;
}
return void_ptr;
}
template <typename T>
T *get_cpp_conduit_type_ptr(PyObject *py_obj) {
void *void_ptr = get_cpp_conduit_void_ptr(py_obj, &typeid(T));
if (void_ptr == nullptr) {
return nullptr;
}
return static_cast<T *>(void_ptr);
}
extern "C" PyObject *wrapGetLuggage(PyObject * /*self*/, PyObject *traveler) { extern "C" PyObject *wrapGetLuggage(PyObject * /*self*/, PyObject *traveler) {
const auto *cpp_traveler const auto *cpp_traveler = pybind11_conduit_v1::get_type_pointer_ephemeral<
= get_cpp_conduit_type_ptr<pybind11_tests::test_cpp_conduit::Traveler>(traveler); pybind11_tests::test_cpp_conduit::Traveler>(traveler);
if (cpp_traveler == nullptr) { if (cpp_traveler == nullptr) {
return nullptr; return nullptr;
} }
@ -61,9 +35,8 @@ extern "C" PyObject *wrapGetLuggage(PyObject * /*self*/, PyObject *traveler) {
} }
extern "C" PyObject *wrapGetPoints(PyObject * /*self*/, PyObject *premium_traveler) { extern "C" PyObject *wrapGetPoints(PyObject * /*self*/, PyObject *premium_traveler) {
const auto *cpp_premium_traveler const auto *cpp_premium_traveler = pybind11_conduit_v1::get_type_pointer_ephemeral<
= get_cpp_conduit_type_ptr<pybind11_tests::test_cpp_conduit::PremiumTraveler>( pybind11_tests::test_cpp_conduit::PremiumTraveler>(premium_traveler);
premium_traveler);
if (cpp_premium_traveler == nullptr) { if (cpp_premium_traveler == nullptr) {
return nullptr; return nullptr;
} }

View File

@ -50,6 +50,13 @@ main_headers = {
"include/pybind11/warnings.h", "include/pybind11/warnings.h",
} }
conduit_headers = {
"include/pybind11/conduit/README.txt",
"include/pybind11/conduit/pybind11_conduit_v1.h",
"include/pybind11/conduit/pybind11_platform_abi_id.h",
"include/pybind11/conduit/wrap_include_python_h.h",
}
detail_headers = { detail_headers = {
"include/pybind11/detail/class.h", "include/pybind11/detail/class.h",
"include/pybind11/detail/common.h", "include/pybind11/detail/common.h",
@ -97,7 +104,7 @@ py_files = {
"setup_helpers.py", "setup_helpers.py",
} }
headers = main_headers | detail_headers | eigen_headers | stl_headers headers = main_headers | conduit_headers | detail_headers | eigen_headers | stl_headers
src_files = headers | cmake_files | pkgconfig_files src_files = headers | cmake_files | pkgconfig_files
all_files = src_files | py_files all_files = src_files | py_files
@ -106,6 +113,7 @@ sdist_files = {
"pybind11", "pybind11",
"pybind11/include", "pybind11/include",
"pybind11/include/pybind11", "pybind11/include/pybind11",
"pybind11/include/pybind11/conduit",
"pybind11/include/pybind11/detail", "pybind11/include/pybind11/detail",
"pybind11/include/pybind11/eigen", "pybind11/include/pybind11/eigen",
"pybind11/include/pybind11/stl", "pybind11/include/pybind11/stl",

View File

@ -1,6 +1,8 @@
# ruff: noqa: SIM201 SIM300 SIM202 # ruff: noqa: SIM201 SIM300 SIM202
from __future__ import annotations from __future__ import annotations
import re
import pytest import pytest
import env # noqa: F401 import env # noqa: F401
@ -271,3 +273,61 @@ def test_docstring_signatures():
def test_str_signature(): def test_str_signature():
for enum_type in [m.ScopedEnum, m.UnscopedEnum]: for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
assert enum_type.__str__.__doc__.startswith("__str__") assert enum_type.__str__.__doc__.startswith("__str__")
def test_generated_dunder_methods_pos_only():
for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
for binary_op in [
"__eq__",
"__ne__",
"__ge__",
"__gt__",
"__lt__",
"__le__",
"__and__",
"__rand__",
# "__or__", # fail with some compilers (__doc__ = "Return self|value.")
# "__ror__", # fail with some compilers (__doc__ = "Return value|self.")
"__xor__",
"__rxor__",
"__rxor__",
]:
method = getattr(enum_type, binary_op, None)
if method is not None:
assert (
re.match(
rf"^{binary_op}\(self: [\w\.]+, other: [\w\.]+, /\)",
method.__doc__,
)
is not None
)
for unary_op in [
"__int__",
"__index__",
"__hash__",
"__str__",
"__repr__",
]:
method = getattr(enum_type, unary_op, None)
if method is not None:
assert (
re.match(
rf"^{unary_op}\(self: [\w\.]+, /\)",
method.__doc__,
)
is not None
)
assert (
re.match(
r"^__getstate__\(self: [\w\.]+, /\)",
enum_type.__getstate__.__doc__,
)
is not None
)
assert (
re.match(
r"^__setstate__\(self: [\w\.]+, state: [\w\.]+, /\)",
enum_type.__setstate__.__doc__,
)
is not None
)

View File

@ -6,14 +6,8 @@ from io import StringIO
import pytest import pytest
import env # noqa: F401
from pybind11_tests import iostream as m from pybind11_tests import iostream as m
pytestmark = pytest.mark.skipif(
"env.GRAALPY",
reason="Delayed prints from finalizers from other tests can end up in the output",
)
def test_captured(capsys): def test_captured(capsys):
msg = "I've been redirected to Python, I hope!" msg = "I've been redirected to Python, I hope!"

View File

@ -14,26 +14,6 @@
#include <utility> #include <utility>
// Classes needed for subclass test.
class ArgsSubclass : public py::args {
using py::args::args;
};
class KWArgsSubclass : public py::kwargs {
using py::kwargs::kwargs;
};
namespace pybind11 {
namespace detail {
template <>
struct handle_type_name<ArgsSubclass> {
static constexpr auto name = const_name("*Args");
};
template <>
struct handle_type_name<KWArgsSubclass> {
static constexpr auto name = const_name("**KWArgs");
};
} // namespace detail
} // namespace pybind11
TEST_SUBMODULE(kwargs_and_defaults, m) { TEST_SUBMODULE(kwargs_and_defaults, m) {
auto kw_func auto kw_func
= [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); }; = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); };
@ -345,7 +325,7 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
// Test support for args and kwargs subclasses // Test support for args and kwargs subclasses
m.def("args_kwargs_subclass_function", m.def("args_kwargs_subclass_function",
[](const ArgsSubclass &args, const KWArgsSubclass &kwargs) { [](const py::Args<std::string> &args, const py::KWArgs<std::string> &kwargs) {
return py::make_tuple(args, kwargs); return py::make_tuple(args, kwargs);
}); });
} }

View File

@ -20,7 +20,7 @@ def test_function_signatures(doc):
) )
assert ( assert (
doc(m.args_kwargs_subclass_function) doc(m.args_kwargs_subclass_function)
== "args_kwargs_subclass_function(*Args, **KWArgs) -> tuple" == "args_kwargs_subclass_function(*args: str, **kwargs: str) -> tuple"
) )
assert ( assert (
doc(m.KWClass.foo0) doc(m.KWClass.foo0)

View File

@ -294,7 +294,7 @@ TEST_SUBMODULE(methods_and_attributes, m) {
static_cast<py::str (ExampleMandA::*)(int, int)>( static_cast<py::str (ExampleMandA::*)(int, int)>(
&ExampleMandA::overloaded)); &ExampleMandA::overloaded));
}) })
.def("__str__", &ExampleMandA::toString) .def("__str__", &ExampleMandA::toString, py::pos_only())
.def_readwrite("value", &ExampleMandA::value); .def_readwrite("value", &ExampleMandA::value);
// test_copy_method // test_copy_method

View File

@ -19,6 +19,13 @@ NO_DELETER_MSG = (
) )
def test_self_only_pos_only():
assert (
m.ExampleMandA.__str__.__doc__
== "__str__(self: pybind11_tests.methods_and_attributes.ExampleMandA, /) -> str\n"
)
def test_methods_and_attributes(): def test_methods_and_attributes():
instance1 = m.ExampleMandA() instance1 = m.ExampleMandA()
instance2 = m.ExampleMandA(32) instance2 = m.ExampleMandA(32)

View File

@ -156,6 +156,55 @@ py::handle auxiliaries(T &&r, T2 &&r2) {
return l.release(); return l.release();
} }
template <typename PyObjectType>
PyObjectType convert_to_pyobjecttype(py::object obj);
template <>
PyObject *convert_to_pyobjecttype<PyObject *>(py::object obj) {
return obj.release().ptr();
}
template <>
py::handle convert_to_pyobjecttype<py::handle>(py::object obj) {
return obj.release();
}
template <>
py::object convert_to_pyobjecttype<py::object>(py::object obj) {
return obj;
}
template <typename PyObjectType>
std::string pass_array_return_sum_str_values(const py::array_t<PyObjectType> &objs) {
std::string sum_str_values;
for (const auto &obj : objs) {
sum_str_values += py::str(obj.attr("value"));
}
return sum_str_values;
}
template <typename PyObjectType>
py::list pass_array_return_as_list(const py::array_t<PyObjectType> &objs) {
return objs;
}
template <typename PyObjectType>
py::array_t<PyObjectType> return_array_cpp_loop(const py::list &objs) {
py::size_t arr_size = py::len(objs);
py::array_t<PyObjectType> arr_from_list(static_cast<py::ssize_t>(arr_size));
PyObjectType *data = arr_from_list.mutable_data();
for (py::size_t i = 0; i < arr_size; i++) {
assert(!data[i]);
data[i] = convert_to_pyobjecttype<PyObjectType>(objs[i].attr("value"));
}
return arr_from_list;
}
template <typename PyObjectType>
py::array_t<PyObjectType> return_array_from_list(const py::list &objs) {
return objs;
}
// note: declaration at local scope would create a dangling reference! // note: declaration at local scope would create a dangling reference!
static int data_i = 42; static int data_i = 42;
@ -520,28 +569,21 @@ TEST_SUBMODULE(numpy_array, sm) {
sm.def("round_trip_float", [](double d) { return d; }); sm.def("round_trip_float", [](double d) { return d; });
sm.def("pass_array_pyobject_ptr_return_sum_str_values", sm.def("pass_array_pyobject_ptr_return_sum_str_values",
[](const py::array_t<PyObject *> &objs) { pass_array_return_sum_str_values<PyObject *>);
std::string sum_str_values; sm.def("pass_array_handle_return_sum_str_values",
for (const auto &obj : objs) { pass_array_return_sum_str_values<py::handle>);
sum_str_values += py::str(obj.attr("value")); sm.def("pass_array_object_return_sum_str_values",
} pass_array_return_sum_str_values<py::object>);
return sum_str_values;
});
sm.def("pass_array_pyobject_ptr_return_as_list", sm.def("pass_array_pyobject_ptr_return_as_list", pass_array_return_as_list<PyObject *>);
[](const py::array_t<PyObject *> &objs) -> py::list { return objs; }); sm.def("pass_array_handle_return_as_list", pass_array_return_as_list<py::handle>);
sm.def("pass_array_object_return_as_list", pass_array_return_as_list<py::object>);
sm.def("return_array_pyobject_ptr_cpp_loop", [](const py::list &objs) { sm.def("return_array_pyobject_ptr_cpp_loop", return_array_cpp_loop<PyObject *>);
py::size_t arr_size = py::len(objs); sm.def("return_array_handle_cpp_loop", return_array_cpp_loop<py::handle>);
py::array_t<PyObject *> arr_from_list(static_cast<py::ssize_t>(arr_size)); sm.def("return_array_object_cpp_loop", return_array_cpp_loop<py::object>);
PyObject **data = arr_from_list.mutable_data();
for (py::size_t i = 0; i < arr_size; i++) {
assert(data[i] == nullptr);
data[i] = py::cast<PyObject *>(objs[i].attr("value"));
}
return arr_from_list;
});
sm.def("return_array_pyobject_ptr_from_list", sm.def("return_array_pyobject_ptr_from_list", return_array_from_list<PyObject *>);
[](const py::list &objs) -> py::array_t<PyObject *> { return objs; }); sm.def("return_array_handle_from_list", return_array_from_list<py::handle>);
sm.def("return_array_object_from_list", return_array_from_list<py::object>);
} }

View File

@ -629,45 +629,61 @@ def UnwrapPyValueHolder(vhs):
return [vh.value for vh in vhs] return [vh.value for vh in vhs]
def test_pass_array_pyobject_ptr_return_sum_str_values_ndarray(): PASS_ARRAY_PYOBJECT_RETURN_SUM_STR_VALUES_FUNCTIONS = [
m.pass_array_pyobject_ptr_return_sum_str_values,
m.pass_array_handle_return_sum_str_values,
m.pass_array_object_return_sum_str_values,
]
@pytest.mark.parametrize(
"pass_array", PASS_ARRAY_PYOBJECT_RETURN_SUM_STR_VALUES_FUNCTIONS
)
def test_pass_array_object_return_sum_str_values_ndarray(pass_array):
# Intentionally all temporaries, do not change. # Intentionally all temporaries, do not change.
assert ( assert (
m.pass_array_pyobject_ptr_return_sum_str_values( pass_array(np.array(WrapWithPyValueHolder(-3, "four", 5.0), dtype=object))
np.array(WrapWithPyValueHolder(-3, "four", 5.0), dtype=object)
)
== "-3four5.0" == "-3four5.0"
) )
def test_pass_array_pyobject_ptr_return_sum_str_values_list(): @pytest.mark.parametrize(
"pass_array", PASS_ARRAY_PYOBJECT_RETURN_SUM_STR_VALUES_FUNCTIONS
)
def test_pass_array_object_return_sum_str_values_list(pass_array):
# Intentionally all temporaries, do not change. # Intentionally all temporaries, do not change.
assert ( assert pass_array(WrapWithPyValueHolder(2, "three", -4.0)) == "2three-4.0"
m.pass_array_pyobject_ptr_return_sum_str_values(
WrapWithPyValueHolder(2, "three", -4.0)
)
== "2three-4.0"
)
def test_pass_array_pyobject_ptr_return_as_list(): @pytest.mark.parametrize(
"pass_array",
[
m.pass_array_pyobject_ptr_return_as_list,
m.pass_array_handle_return_as_list,
m.pass_array_object_return_as_list,
],
)
def test_pass_array_object_return_as_list(pass_array):
# Intentionally all temporaries, do not change. # Intentionally all temporaries, do not change.
assert UnwrapPyValueHolder( assert UnwrapPyValueHolder(
m.pass_array_pyobject_ptr_return_as_list( pass_array(np.array(WrapWithPyValueHolder(-1, "two", 3.0), dtype=object))
np.array(WrapWithPyValueHolder(-1, "two", 3.0), dtype=object)
)
) == [-1, "two", 3.0] ) == [-1, "two", 3.0]
@pytest.mark.parametrize( @pytest.mark.parametrize(
("return_array_pyobject_ptr", "unwrap"), ("return_array", "unwrap"),
[ [
(m.return_array_pyobject_ptr_cpp_loop, list), (m.return_array_pyobject_ptr_cpp_loop, list),
(m.return_array_handle_cpp_loop, list),
(m.return_array_object_cpp_loop, list),
(m.return_array_pyobject_ptr_from_list, UnwrapPyValueHolder), (m.return_array_pyobject_ptr_from_list, UnwrapPyValueHolder),
(m.return_array_handle_from_list, UnwrapPyValueHolder),
(m.return_array_object_from_list, UnwrapPyValueHolder),
], ],
) )
def test_return_array_pyobject_ptr_cpp_loop(return_array_pyobject_ptr, unwrap): def test_return_array_object_cpp_loop(return_array, unwrap):
# Intentionally all temporaries, do not change. # Intentionally all temporaries, do not change.
arr_from_list = return_array_pyobject_ptr(WrapWithPyValueHolder(6, "seven", -8.0)) arr_from_list = return_array(WrapWithPyValueHolder(6, "seven", -8.0))
assert isinstance(arr_from_list, np.ndarray) assert isinstance(arr_from_list, np.ndarray)
assert arr_from_list.dtype == np.dtype("O") assert arr_from_list.dtype == np.dtype("O")
assert unwrap(arr_from_list) == [6, "seven", -8.0] assert unwrap(arr_from_list) == [6, "seven", -8.0]

View File

@ -11,6 +11,9 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <cstdint>
#include <stdexcept>
#ifdef __GNUC__ #ifdef __GNUC__
# define PYBIND11_PACKED(cls) cls __attribute__((__packed__)) # define PYBIND11_PACKED(cls) cls __attribute__((__packed__))
#else #else
@ -297,6 +300,15 @@ py::list test_dtype_ctors() {
return list; return list;
} }
template <typename T>
py::array_t<T> dispatch_array_increment(py::array_t<T> arr) {
py::array_t<T> res(arr.shape(0));
for (py::ssize_t i = 0; i < arr.shape(0); ++i) {
res.mutable_at(i) = T(arr.at(i) + 1);
}
return res;
}
struct A {}; struct A {};
struct B {}; struct B {};
@ -496,6 +508,98 @@ TEST_SUBMODULE(numpy_dtypes, m) {
} }
return list; return list;
}); });
m.def("test_dtype_num_of", []() -> py::list {
py::list res;
#define TEST_DTYPE(T) res.append(py::make_tuple(py::dtype::of<T>().num(), py::dtype::num_of<T>()));
TEST_DTYPE(bool)
TEST_DTYPE(char)
TEST_DTYPE(unsigned char)
TEST_DTYPE(short)
TEST_DTYPE(unsigned short)
TEST_DTYPE(int)
TEST_DTYPE(unsigned int)
TEST_DTYPE(long)
TEST_DTYPE(unsigned long)
TEST_DTYPE(long long)
TEST_DTYPE(unsigned long long)
TEST_DTYPE(float)
TEST_DTYPE(double)
TEST_DTYPE(long double)
TEST_DTYPE(std::complex<float>)
TEST_DTYPE(std::complex<double>)
TEST_DTYPE(std::complex<long double>)
TEST_DTYPE(int8_t)
TEST_DTYPE(uint8_t)
TEST_DTYPE(int16_t)
TEST_DTYPE(uint16_t)
TEST_DTYPE(int32_t)
TEST_DTYPE(uint32_t)
TEST_DTYPE(int64_t)
TEST_DTYPE(uint64_t)
#undef TEST_DTYPE
return res;
});
m.def("test_dtype_normalized_num", []() -> py::list {
py::list res;
#define TEST_DTYPE(NT, T) \
res.append(py::make_tuple(py::dtype(py::detail::npy_api::NT).normalized_num(), \
py::dtype::num_of<T>()));
TEST_DTYPE(NPY_BOOL_, bool)
TEST_DTYPE(NPY_BYTE_, char);
TEST_DTYPE(NPY_UBYTE_, unsigned char);
TEST_DTYPE(NPY_SHORT_, short);
TEST_DTYPE(NPY_USHORT_, unsigned short);
TEST_DTYPE(NPY_INT_, int);
TEST_DTYPE(NPY_UINT_, unsigned int);
TEST_DTYPE(NPY_LONG_, long);
TEST_DTYPE(NPY_ULONG_, unsigned long);
TEST_DTYPE(NPY_LONGLONG_, long long);
TEST_DTYPE(NPY_ULONGLONG_, unsigned long long);
TEST_DTYPE(NPY_FLOAT_, float);
TEST_DTYPE(NPY_DOUBLE_, double);
TEST_DTYPE(NPY_LONGDOUBLE_, long double);
TEST_DTYPE(NPY_CFLOAT_, std::complex<float>);
TEST_DTYPE(NPY_CDOUBLE_, std::complex<double>);
TEST_DTYPE(NPY_CLONGDOUBLE_, std::complex<long double>);
TEST_DTYPE(NPY_INT8_, int8_t);
TEST_DTYPE(NPY_UINT8_, uint8_t);
TEST_DTYPE(NPY_INT16_, int16_t);
TEST_DTYPE(NPY_UINT16_, uint16_t);
TEST_DTYPE(NPY_INT32_, int32_t);
TEST_DTYPE(NPY_UINT32_, uint32_t);
TEST_DTYPE(NPY_INT64_, int64_t);
TEST_DTYPE(NPY_UINT64_, uint64_t);
#undef TEST_DTYPE
return res;
});
m.def("test_dtype_switch", [](const py::array &arr) -> py::array {
switch (arr.dtype().normalized_num()) {
case py::dtype::num_of<int8_t>():
return dispatch_array_increment<int8_t>(arr);
case py::dtype::num_of<uint8_t>():
return dispatch_array_increment<uint8_t>(arr);
case py::dtype::num_of<int16_t>():
return dispatch_array_increment<int16_t>(arr);
case py::dtype::num_of<uint16_t>():
return dispatch_array_increment<uint16_t>(arr);
case py::dtype::num_of<int32_t>():
return dispatch_array_increment<int32_t>(arr);
case py::dtype::num_of<uint32_t>():
return dispatch_array_increment<uint32_t>(arr);
case py::dtype::num_of<int64_t>():
return dispatch_array_increment<int64_t>(arr);
case py::dtype::num_of<uint64_t>():
return dispatch_array_increment<uint64_t>(arr);
case py::dtype::num_of<float>():
return dispatch_array_increment<float>(arr);
case py::dtype::num_of<double>():
return dispatch_array_increment<double>(arr);
case py::dtype::num_of<long double>():
return dispatch_array_increment<long double>(arr);
default:
throw std::runtime_error("Unsupported dtype");
}
});
m.def("test_dtype_methods", []() { m.def("test_dtype_methods", []() {
py::list list; py::list list;
auto dt1 = py::dtype::of<int32_t>(); auto dt1 = py::dtype::of<int32_t>();

View File

@ -188,6 +188,28 @@ def test_dtype(simple_dtype):
chr(np.dtype(ch).flags) for ch in expected_chars chr(np.dtype(ch).flags) for ch in expected_chars
] ]
for a, b in m.test_dtype_num_of():
assert a == b
for a, b in m.test_dtype_normalized_num():
assert a == b
arr = np.array([4, 84, 21, 36])
# Note: "ulong" does not work in NumPy 1.x, so we use "L"
assert (m.test_dtype_switch(arr.astype("byte")) == arr + 1).all()
assert (m.test_dtype_switch(arr.astype("ubyte")) == arr + 1).all()
assert (m.test_dtype_switch(arr.astype("short")) == arr + 1).all()
assert (m.test_dtype_switch(arr.astype("ushort")) == arr + 1).all()
assert (m.test_dtype_switch(arr.astype("intc")) == arr + 1).all()
assert (m.test_dtype_switch(arr.astype("uintc")) == arr + 1).all()
assert (m.test_dtype_switch(arr.astype("long")) == arr + 1).all()
assert (m.test_dtype_switch(arr.astype("L")) == arr + 1).all()
assert (m.test_dtype_switch(arr.astype("longlong")) == arr + 1).all()
assert (m.test_dtype_switch(arr.astype("ulonglong")) == arr + 1).all()
assert (m.test_dtype_switch(arr.astype("single")) == arr + 1).all()
assert (m.test_dtype_switch(arr.astype("double")) == arr + 1).all()
assert (m.test_dtype_switch(arr.astype("longdouble")) == arr + 1).all()
def test_recarray(simple_dtype, packed_dtype): def test_recarray(simple_dtype, packed_dtype):
elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)] elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)]

View File

@ -93,3 +93,20 @@ def test_roundtrip_simple_cpp_derived():
# Issue #3062: pickleable base C++ classes can incur object slicing # Issue #3062: pickleable base C++ classes can incur object slicing
# if derived typeid is not registered with pybind11 # if derived typeid is not registered with pybind11
assert not m.check_dynamic_cast_SimpleCppDerived(p2) assert not m.check_dynamic_cast_SimpleCppDerived(p2)
def test_new_style_pickle_getstate_pos_only():
assert (
re.match(
r"^__getstate__\(self: [\w\.]+, /\)", m.PickleableNew.__getstate__.__doc__
)
is not None
)
if hasattr(m, "PickleableWithDictNew"):
assert (
re.match(
r"^__getstate__\(self: [\w\.]+, /\)",
m.PickleableWithDictNew.__getstate__.__doc__,
)
is not None
)

View File

@ -1,5 +1,7 @@
from __future__ import annotations from __future__ import annotations
import re
import pytest import pytest
from pytest import approx # noqa: PT013 from pytest import approx # noqa: PT013
@ -253,16 +255,12 @@ def test_python_iterator_in_cpp():
def test_iterator_passthrough(): def test_iterator_passthrough():
"""#181: iterator passthrough did not compile""" """#181: iterator passthrough did not compile"""
from pybind11_tests.sequences_and_iterators import iterator_passthrough
values = [3, 5, 7, 9, 11, 13, 15] values = [3, 5, 7, 9, 11, 13, 15]
assert list(iterator_passthrough(iter(values))) == values assert list(m.iterator_passthrough(iter(values))) == values
def test_iterator_rvp(): 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] assert list(m.make_iterator_1()) == [1, 2, 3]
assert list(m.make_iterator_2()) == [1, 2, 3] assert list(m.make_iterator_2()) == [1, 2, 3]
assert not isinstance(m.make_iterator_1(), type(m.make_iterator_2())) assert not isinstance(m.make_iterator_1(), type(m.make_iterator_2()))
@ -274,3 +272,25 @@ def test_carray_iterator():
arr_h = m.CArrayHolder(*args_gt) arr_h = m.CArrayHolder(*args_gt)
args = list(arr_h) args = list(arr_h)
assert args_gt == args assert args_gt == args
def test_generated_dunder_methods_pos_only():
string_map = m.StringMap({"hi": "bye", "black": "white"})
for it in (
m.make_iterator_1(),
m.make_iterator_2(),
m.iterator_passthrough(iter([3, 5, 7])),
iter(m.Sequence(5)),
iter(string_map),
string_map.items(),
string_map.values(),
iter(m.CArrayHolder(*[float(i) for i in range(3)])),
):
assert (
re.match(r"^__iter__\(self: [\w\.]+, /\)", type(it).__iter__.__doc__)
is not None
)
assert (
re.match(r"^__next__\(self: [\w\.]+, /\)", type(it).__next__.__doc__)
is not None
)

View File

@ -26,12 +26,14 @@ class InstallHeadersNested(install_headers):
main_headers = glob.glob("pybind11/include/pybind11/*.h") main_headers = glob.glob("pybind11/include/pybind11/*.h")
conduit_headers = sum([glob.glob(f"pybind11/include/pybind11/conduit/*.{ext}")
for ext in ("h", "txt")], [])
detail_headers = glob.glob("pybind11/include/pybind11/detail/*.h") detail_headers = glob.glob("pybind11/include/pybind11/detail/*.h")
eigen_headers = glob.glob("pybind11/include/pybind11/eigen/*.h") eigen_headers = glob.glob("pybind11/include/pybind11/eigen/*.h")
stl_headers = glob.glob("pybind11/include/pybind11/stl/*.h") stl_headers = glob.glob("pybind11/include/pybind11/stl/*.h")
cmake_files = glob.glob("pybind11/share/cmake/pybind11/*.cmake") cmake_files = glob.glob("pybind11/share/cmake/pybind11/*.cmake")
pkgconfig_files = glob.glob("pybind11/share/pkgconfig/*.pc") pkgconfig_files = glob.glob("pybind11/share/pkgconfig/*.pc")
headers = main_headers + detail_headers + stl_headers + eigen_headers headers = main_headers + conduit_headers + detail_headers + eigen_headers + stl_headers
cmdclass = {"install_headers": InstallHeadersNested} cmdclass = {"install_headers": InstallHeadersNested}
$extra_cmd $extra_cmd
@ -55,6 +57,7 @@ setup(
(base + "share/cmake/pybind11", cmake_files), (base + "share/cmake/pybind11", cmake_files),
(base + "share/pkgconfig", pkgconfig_files), (base + "share/pkgconfig", pkgconfig_files),
(base + "include/pybind11", main_headers), (base + "include/pybind11", main_headers),
(base + "include/pybind11/conduit", conduit_headers),
(base + "include/pybind11/detail", detail_headers), (base + "include/pybind11/detail", detail_headers),
(base + "include/pybind11/eigen", eigen_headers), (base + "include/pybind11/eigen", eigen_headers),
(base + "include/pybind11/stl", stl_headers), (base + "include/pybind11/stl", stl_headers),

View File

@ -14,6 +14,7 @@ setup(
packages=[ packages=[
"pybind11", "pybind11",
"pybind11.include.pybind11", "pybind11.include.pybind11",
"pybind11.include.pybind11.conduit",
"pybind11.include.pybind11.detail", "pybind11.include.pybind11.detail",
"pybind11.include.pybind11.eigen", "pybind11.include.pybind11.eigen",
"pybind11.include.pybind11.stl", "pybind11.include.pybind11.stl",
@ -23,6 +24,7 @@ setup(
package_data={ package_data={
"pybind11": ["py.typed"], "pybind11": ["py.typed"],
"pybind11.include.pybind11": ["*.h"], "pybind11.include.pybind11": ["*.h"],
"pybind11.include.pybind11.conduit": ["*.h", "*.txt"],
"pybind11.include.pybind11.detail": ["*.h"], "pybind11.include.pybind11.detail": ["*.h"],
"pybind11.include.pybind11.eigen": ["*.h"], "pybind11.include.pybind11.eigen": ["*.h"],
"pybind11.include.pybind11.stl": ["*.h"], "pybind11.include.pybind11.stl": ["*.h"],