mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-30 00:47:12 +00:00
Merge branch 'master' into annotated_any
This commit is contained in:
commit
1e6bea27f7
10
.github/dependabot.yml
vendored
10
.github/dependabot.yml
vendored
@ -4,4 +4,12 @@ updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "weekly"
|
||||
groups:
|
||||
actions:
|
||||
patterns:
|
||||
- "*"
|
||||
ignore:
|
||||
- dependency-name: actions/checkout
|
||||
versions:
|
||||
- "<5"
|
||||
|
48
.github/workflows/ci.yml
vendored
48
.github/workflows/ci.yml
vendored
@ -86,11 +86,11 @@ jobs:
|
||||
run: brew install boost
|
||||
|
||||
- name: Update CMake
|
||||
uses: jwlawson/actions-setup-cmake@v1.14
|
||||
uses: jwlawson/actions-setup-cmake@v2.0
|
||||
|
||||
- name: Cache wheels
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
# This path is specific to macOS - we really only need it for PyPy NumPy wheels
|
||||
# See https://github.com/actions/cache/blob/master/examples.md#python---pip
|
||||
@ -108,12 +108,14 @@ jobs:
|
||||
run: python -m pip install pytest-github-actions-annotate-failures
|
||||
|
||||
# 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 }}
|
||||
run: >
|
||||
cmake -S . -B .
|
||||
-DPYBIND11_WERROR=ON
|
||||
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON
|
||||
-DPYBIND11_NUMPY_1_ONLY=ON
|
||||
-DDOWNLOAD_CATCH=ON
|
||||
-DDOWNLOAD_EIGEN=ON
|
||||
-DCMAKE_CXX_STANDARD=11
|
||||
@ -138,11 +140,13 @@ jobs:
|
||||
|
||||
# Second build - C++17 mode and in a build directory
|
||||
# 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
|
||||
run: >
|
||||
cmake -S . -B build2
|
||||
-DPYBIND11_WERROR=ON
|
||||
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF
|
||||
-DPYBIND11_NUMPY_1_ONLY=ON
|
||||
-DDOWNLOAD_CATCH=ON
|
||||
-DDOWNLOAD_EIGEN=ON
|
||||
-DCMAKE_CXX_STANDARD=17
|
||||
@ -214,11 +218,11 @@ jobs:
|
||||
debug: ${{ matrix.python-debug }}
|
||||
|
||||
- name: Update CMake
|
||||
uses: jwlawson/actions-setup-cmake@v1.14
|
||||
uses: jwlawson/actions-setup-cmake@v2.0
|
||||
|
||||
- name: Valgrind cache
|
||||
if: matrix.valgrind
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
id: cache-valgrind
|
||||
with:
|
||||
path: valgrind
|
||||
@ -484,7 +488,7 @@ jobs:
|
||||
run: python3 -m pip install --upgrade pip
|
||||
|
||||
- name: Update CMake
|
||||
uses: jwlawson/actions-setup-cmake@v1.14
|
||||
uses: jwlawson/actions-setup-cmake@v2.0
|
||||
|
||||
- name: Configure
|
||||
shell: bash
|
||||
@ -529,8 +533,6 @@ jobs:
|
||||
# Testing on ICC using the oneAPI apt repo
|
||||
icc:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
name: "🐍 3 • ICC latest • x64"
|
||||
|
||||
@ -662,6 +664,11 @@ jobs:
|
||||
run: |
|
||||
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
|
||||
shell: bash
|
||||
run: >
|
||||
@ -797,10 +804,10 @@ jobs:
|
||||
architecture: x86
|
||||
|
||||
- name: Update CMake
|
||||
uses: jwlawson/actions-setup-cmake@v1.14
|
||||
uses: jwlawson/actions-setup-cmake@v2.0
|
||||
|
||||
- name: Prepare MSVC
|
||||
uses: ilammy/msvc-dev-cmd@v1.12.1
|
||||
uses: ilammy/msvc-dev-cmd@v1.13.0
|
||||
with:
|
||||
arch: x86
|
||||
|
||||
@ -850,10 +857,10 @@ jobs:
|
||||
architecture: x86
|
||||
|
||||
- name: Update CMake
|
||||
uses: jwlawson/actions-setup-cmake@v1.14
|
||||
uses: jwlawson/actions-setup-cmake@v2.0
|
||||
|
||||
- name: Prepare MSVC
|
||||
uses: ilammy/msvc-dev-cmd@v1.12.1
|
||||
uses: ilammy/msvc-dev-cmd@v1.13.0
|
||||
with:
|
||||
arch: x86
|
||||
|
||||
@ -897,11 +904,13 @@ jobs:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
- name: Prepare env
|
||||
# Ensure use of NumPy 2 (via NumPy nightlies but can be changed soon)
|
||||
run: |
|
||||
python3 -m pip install -r tests/requirements.txt
|
||||
python3 -m pip install 'numpy>=2.0.0b1' 'scipy>=1.13.0rc1'
|
||||
|
||||
- name: Update CMake
|
||||
uses: jwlawson/actions-setup-cmake@v1.14
|
||||
uses: jwlawson/actions-setup-cmake@v2.0
|
||||
|
||||
- name: Configure C++20
|
||||
run: >
|
||||
@ -959,7 +968,6 @@ jobs:
|
||||
mingw-w64-${{matrix.env}}-gcc
|
||||
mingw-w64-${{matrix.env}}-python-pip
|
||||
mingw-w64-${{matrix.env}}-python-numpy
|
||||
mingw-w64-${{matrix.env}}-python-scipy
|
||||
mingw-w64-${{matrix.env}}-cmake
|
||||
mingw-w64-${{matrix.env}}-make
|
||||
mingw-w64-${{matrix.env}}-python-pytest
|
||||
@ -967,6 +975,14 @@ jobs:
|
||||
mingw-w64-${{matrix.env}}-boost
|
||||
mingw-w64-${{matrix.env}}-catch
|
||||
|
||||
- uses: msys2/setup-msys2@v2
|
||||
if: matrix.sys == 'mingw64'
|
||||
with:
|
||||
msystem: ${{matrix.sys}}
|
||||
install: >-
|
||||
git
|
||||
mingw-w64-${{matrix.env}}-python-scipy
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure C++11
|
||||
@ -1058,7 +1074,7 @@ jobs:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
- name: Update CMake
|
||||
uses: jwlawson/actions-setup-cmake@v1.14
|
||||
uses: jwlawson/actions-setup-cmake@v2.0
|
||||
|
||||
- name: Install ninja-build tool
|
||||
uses: seanmiddleditch/gha-setup-ninja@v4
|
||||
@ -1128,7 +1144,7 @@ jobs:
|
||||
run: clang++ --version
|
||||
|
||||
- name: Update CMake
|
||||
uses: jwlawson/actions-setup-cmake@v1.14
|
||||
uses: jwlawson/actions-setup-cmake@v2.0
|
||||
|
||||
- name: Run pip installs
|
||||
run: |
|
||||
|
2
.github/workflows/configure.yml
vendored
2
.github/workflows/configure.yml
vendored
@ -63,7 +63,7 @@ jobs:
|
||||
# An action for adding a specific version of CMake:
|
||||
# https://github.com/jwlawson/actions-setup-cmake
|
||||
- name: Setup CMake ${{ matrix.cmake }}
|
||||
uses: jwlawson/actions-setup-cmake@v1.14
|
||||
uses: jwlawson/actions-setup-cmake@v2.0
|
||||
with:
|
||||
cmake-version: ${{ matrix.cmake }}
|
||||
|
||||
|
2
.github/workflows/format.yml
vendored
2
.github/workflows/format.yml
vendored
@ -31,7 +31,7 @@ jobs:
|
||||
python-version: "3.x"
|
||||
- name: Add matchers
|
||||
run: echo "::add-matcher::$GITHUB_WORKSPACE/.github/matchers/pylint.json"
|
||||
- uses: pre-commit/action@v3.0.0
|
||||
- uses: pre-commit/action@v3.0.1
|
||||
with:
|
||||
# Slow hooks are marked with manual - slow is okay here, run them too
|
||||
extra_args: --hook-stage manual --all-files
|
||||
|
2
.github/workflows/upstream.yml
vendored
2
.github/workflows/upstream.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
run: sudo apt-get install libboost-dev
|
||||
|
||||
- name: Update CMake
|
||||
uses: jwlawson/actions-setup-cmake@v1.14
|
||||
uses: jwlawson/actions-setup-cmake@v2.0
|
||||
|
||||
- name: Run pip installs
|
||||
run: |
|
||||
|
@ -32,7 +32,7 @@ repos:
|
||||
|
||||
# Ruff, the Python auto-correcting linter/formatter written in Rust
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.1.6
|
||||
rev: v0.2.0
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: ["--fix", "--show-fixes"]
|
||||
@ -40,7 +40,7 @@ repos:
|
||||
|
||||
# Check static types with mypy
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: "v1.7.1"
|
||||
rev: "v1.8.0"
|
||||
hooks:
|
||||
- id: mypy
|
||||
args: []
|
||||
@ -93,7 +93,7 @@ repos:
|
||||
|
||||
# Avoid directional quotes
|
||||
- repo: https://github.com/sirosen/texthooks
|
||||
rev: "0.6.3"
|
||||
rev: "0.6.4"
|
||||
hooks:
|
||||
- id: fix-ligatures
|
||||
- id: fix-smartquotes
|
||||
@ -142,7 +142,14 @@ repos:
|
||||
|
||||
# PyLint has native support - not always usable, but works for us
|
||||
- repo: https://github.com/PyCQA/pylint
|
||||
rev: "v3.0.1"
|
||||
rev: "v3.0.3"
|
||||
hooks:
|
||||
- id: pylint
|
||||
files: ^pybind11
|
||||
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.28.0
|
||||
hooks:
|
||||
- id: check-readthedocs
|
||||
- id: check-github-workflows
|
||||
- id: check-dependabot
|
||||
|
@ -109,6 +109,8 @@ option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT})
|
||||
option(PYBIND11_NOPYTHON "Disable search for Python" OFF)
|
||||
option(PYBIND11_SIMPLE_GIL_MANAGEMENT
|
||||
"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
|
||||
""
|
||||
CACHE STRING "Override the ABI version, may be used to enable the unstable ABI.")
|
||||
@ -116,6 +118,9 @@ set(PYBIND11_INTERNALS_VERSION
|
||||
if(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||
add_compile_definitions(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||
endif()
|
||||
if(PYBIND11_NUMPY_1_ONLY)
|
||||
add_compile_definitions(PYBIND11_NUMPY_1_ONLY)
|
||||
endif()
|
||||
|
||||
cmake_dependent_option(
|
||||
USE_PYTHON_INCLUDE_DIR
|
||||
|
@ -639,3 +639,11 @@ cross-project dependency management. Additionally, it is able to autogenerate
|
||||
customizable pybind11-based wrappers by parsing C++ header files.
|
||||
|
||||
.. [robotpy-build] https://robotpy-build.readthedocs.io
|
||||
|
||||
[litgen]_ is an automatic python bindings generator with a focus on generating
|
||||
documented and discoverable bindings: bindings will nicely reproduce the documentation
|
||||
found in headers. It is is based on srcML (srcml.org), a highly scalable, multi-language
|
||||
parsing tool with a developer centric approach. The API that you want to expose to python
|
||||
must be C++14 compatible (but your implementation can use more modern constructs).
|
||||
|
||||
.. [litgen] https://pthom.github.io/litgen
|
||||
|
@ -327,8 +327,9 @@ public:
|
||||
value = false;
|
||||
return true;
|
||||
}
|
||||
if (convert || (std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name) == 0)) {
|
||||
// (allow non-implicit conversion for numpy booleans)
|
||||
if (convert || is_numpy_bool(src)) {
|
||||
// (allow non-implicit conversion for numpy booleans), use strncmp
|
||||
// since NumPy 1.x had an additional trailing underscore.
|
||||
|
||||
Py_ssize_t res = -1;
|
||||
if (src.is_none()) {
|
||||
@ -360,6 +361,15 @@ public:
|
||||
return handle(src ? Py_True : Py_False).inc_ref();
|
||||
}
|
||||
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:
|
||||
|
@ -296,6 +296,10 @@ PYBIND11_WARNING_DISABLE_MSVC(4505)
|
||||
# undef copysign
|
||||
#endif
|
||||
|
||||
#if defined(PYBIND11_NUMPY_1_ONLY)
|
||||
# define PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED
|
||||
#endif
|
||||
|
||||
#if defined(PYPY_VERSION) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
||||
# define PYBIND11_SIMPLE_GIL_MANAGEMENT
|
||||
#endif
|
||||
|
@ -67,9 +67,14 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
|
||||
// `Py_LIMITED_API` anyway.
|
||||
# if PYBIND11_INTERNALS_VERSION > 4
|
||||
# define PYBIND11_TLS_KEY_REF Py_tss_t &
|
||||
# if defined(__GNUC__) && !defined(__INTEL_COMPILER)
|
||||
// Clang on macOS warns due to `Py_tss_NEEDS_INIT` not specifying an initializer
|
||||
// for every field.
|
||||
# if defined(__clang__)
|
||||
# define PYBIND11_TLS_KEY_INIT(var) \
|
||||
_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) \
|
||||
_Pragma("GCC diagnostic push") /**/ \
|
||||
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
|
||||
|
@ -29,10 +29,15 @@
|
||||
#include <utility>
|
||||
#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
|
||||
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
|
||||
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(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)
|
||||
@ -59,7 +64,8 @@ struct handle_type_name<array> {
|
||||
template <typename type, typename SFINAE = void>
|
||||
struct npy_format_descriptor;
|
||||
|
||||
struct PyArrayDescr_Proxy {
|
||||
/* NumPy 1 proxy (always includes legacy fields) */
|
||||
struct PyArrayDescr1_Proxy {
|
||||
PyObject_HEAD
|
||||
PyObject *typeobj;
|
||||
char kind;
|
||||
@ -74,6 +80,43 @@ struct PyArrayDescr_Proxy {
|
||||
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 {
|
||||
PyObject_HEAD
|
||||
char *data;
|
||||
@ -137,6 +180,14 @@ PYBIND11_NOINLINE module_ import_numpy_core_submodule(const char *submodule_name
|
||||
object numpy_version = numpy_lib.attr("NumpyVersion")(version_string);
|
||||
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
|
||||
became a private module. */
|
||||
std::string numpy_core_path = major_version >= 2 ? "numpy._core" : "numpy.core";
|
||||
@ -209,6 +260,8 @@ struct npy_api {
|
||||
NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_),
|
||||
};
|
||||
|
||||
unsigned int PyArray_RUNTIME_VERSION_;
|
||||
|
||||
struct PyArray_Dims {
|
||||
Py_intptr_t *ptr;
|
||||
int len;
|
||||
@ -247,6 +300,7 @@ struct npy_api {
|
||||
PyObject *(*PyArray_FromAny_)(PyObject *, PyObject *, int, int, int, PyObject *);
|
||||
int (*PyArray_DescrConverter_)(PyObject *, PyObject **);
|
||||
bool (*PyArray_EquivTypes_)(PyObject *, PyObject *);
|
||||
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||
int (*PyArray_GetArrayParamsFromObject_)(PyObject *,
|
||||
PyObject *,
|
||||
unsigned char,
|
||||
@ -255,6 +309,7 @@ struct npy_api {
|
||||
Py_intptr_t *,
|
||||
PyObject **,
|
||||
PyObject *);
|
||||
#endif
|
||||
PyObject *(*PyArray_Squeeze_)(PyObject *);
|
||||
// Unused. Not removed because that affects ABI of the class.
|
||||
int (*PyArray_SetBaseObject_)(PyObject *, PyObject *);
|
||||
@ -272,7 +327,8 @@ private:
|
||||
API_PyArray_DescrFromScalar = 57,
|
||||
API_PyArray_FromAny = 69,
|
||||
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_NewFromDescr = 94,
|
||||
API_PyArray_DescrNewFromType = 96,
|
||||
@ -281,7 +337,9 @@ private:
|
||||
API_PyArray_View = 137,
|
||||
API_PyArray_DescrConverter = 174,
|
||||
API_PyArray_EquivTypes = 182,
|
||||
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||
API_PyArray_GetArrayParamsFromObject = 278,
|
||||
#endif
|
||||
API_PyArray_SetBaseObject = 282
|
||||
};
|
||||
|
||||
@ -296,7 +354,8 @@ private:
|
||||
npy_api api;
|
||||
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
|
||||
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");
|
||||
}
|
||||
DECL_NPY_API(PyArray_Type);
|
||||
@ -315,7 +374,9 @@ private:
|
||||
DECL_NPY_API(PyArray_View);
|
||||
DECL_NPY_API(PyArray_DescrConverter);
|
||||
DECL_NPY_API(PyArray_EquivTypes);
|
||||
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||
DECL_NPY_API(PyArray_GetArrayParamsFromObject);
|
||||
#endif
|
||||
DECL_NPY_API(PyArray_SetBaseObject);
|
||||
|
||||
#undef DECL_NPY_API
|
||||
@ -337,6 +398,14 @@ inline const PyArrayDescr_Proxy *array_descriptor_proxy(const PyObject *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) {
|
||||
return (flag == (array_proxy(ptr)->flags & flag));
|
||||
}
|
||||
@ -616,10 +685,32 @@ public:
|
||||
}
|
||||
|
||||
/// Size of the data type in bytes.
|
||||
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||
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.
|
||||
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||
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.
|
||||
/// For example, floating point types are 'f' and integral types are 'i'.
|
||||
@ -645,11 +736,29 @@ public:
|
||||
/// Single character for 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; }
|
||||
#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; }
|
||||
#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:
|
||||
static object &_dtype_from_pep3118() {
|
||||
@ -816,9 +925,7 @@ public:
|
||||
}
|
||||
|
||||
/// Byte size of a single element
|
||||
ssize_t itemsize() const {
|
||||
return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize;
|
||||
}
|
||||
ssize_t itemsize() const { return dtype().itemsize(); }
|
||||
|
||||
/// Total number of bytes
|
||||
ssize_t nbytes() const { return size() * itemsize(); }
|
||||
|
@ -172,7 +172,7 @@ struct list_caster {
|
||||
auto s = reinterpret_borrow<sequence>(src);
|
||||
value.clear();
|
||||
reserve_maybe(s, &value);
|
||||
for (auto it : s) {
|
||||
for (const auto &it : s) {
|
||||
value_conv conv;
|
||||
if (!conv.load(it, convert)) {
|
||||
return false;
|
||||
@ -247,7 +247,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
size_t ctr = 0;
|
||||
for (auto it : l) {
|
||||
for (const auto &it : l) {
|
||||
value_conv conv;
|
||||
if (!conv.load(it, convert)) {
|
||||
return false;
|
||||
|
@ -645,49 +645,50 @@ auto map_if_insertion_operator(Class_ &cl, std::string const &name)
|
||||
"Return the canonical string representation of this map.");
|
||||
}
|
||||
|
||||
template <typename KeyType>
|
||||
struct keys_view {
|
||||
virtual size_t len() = 0;
|
||||
virtual iterator iter() = 0;
|
||||
virtual bool contains(const KeyType &k) = 0;
|
||||
virtual bool contains(const object &k) = 0;
|
||||
virtual bool contains(const handle &k) = 0;
|
||||
virtual ~keys_view() = default;
|
||||
};
|
||||
|
||||
template <typename MappedType>
|
||||
struct values_view {
|
||||
virtual size_t len() = 0;
|
||||
virtual iterator iter() = 0;
|
||||
virtual ~values_view() = default;
|
||||
};
|
||||
|
||||
template <typename KeyType, typename MappedType>
|
||||
struct items_view {
|
||||
virtual size_t len() = 0;
|
||||
virtual iterator iter() = 0;
|
||||
virtual ~items_view() = default;
|
||||
};
|
||||
|
||||
template <typename Map, typename KeysView>
|
||||
struct KeysViewImpl : public KeysView {
|
||||
template <typename Map>
|
||||
struct KeysViewImpl : public detail::keys_view {
|
||||
explicit KeysViewImpl(Map &map) : map(map) {}
|
||||
size_t len() override { return map.size(); }
|
||||
iterator iter() override { return make_key_iterator(map.begin(), map.end()); }
|
||||
bool contains(const typename Map::key_type &k) override { return map.find(k) != map.end(); }
|
||||
bool contains(const object &) override { return false; }
|
||||
bool contains(const handle &k) override {
|
||||
try {
|
||||
return map.find(k.template cast<typename Map::key_type>()) != map.end();
|
||||
} catch (const cast_error &) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Map ↦
|
||||
};
|
||||
|
||||
template <typename Map, typename ValuesView>
|
||||
struct ValuesViewImpl : public ValuesView {
|
||||
template <typename Map>
|
||||
struct ValuesViewImpl : public detail::values_view {
|
||||
explicit ValuesViewImpl(Map &map) : map(map) {}
|
||||
size_t len() override { return map.size(); }
|
||||
iterator iter() override { return make_value_iterator(map.begin(), map.end()); }
|
||||
Map ↦
|
||||
};
|
||||
|
||||
template <typename Map, typename ItemsView>
|
||||
struct ItemsViewImpl : public ItemsView {
|
||||
template <typename Map>
|
||||
struct ItemsViewImpl : public detail::items_view {
|
||||
explicit ItemsViewImpl(Map &map) : map(map) {}
|
||||
size_t len() override { return map.size(); }
|
||||
iterator iter() override { return make_iterator(map.begin(), map.end()); }
|
||||
@ -700,11 +701,9 @@ template <typename Map, typename holder_type = std::unique_ptr<Map>, typename...
|
||||
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
|
||||
using KeyType = typename Map::key_type;
|
||||
using MappedType = typename Map::mapped_type;
|
||||
using StrippedKeyType = detail::remove_cvref_t<KeyType>;
|
||||
using StrippedMappedType = detail::remove_cvref_t<MappedType>;
|
||||
using KeysView = detail::keys_view<StrippedKeyType>;
|
||||
using ValuesView = detail::values_view<StrippedMappedType>;
|
||||
using ItemsView = detail::items_view<StrippedKeyType, StrippedMappedType>;
|
||||
using KeysView = detail::keys_view;
|
||||
using ValuesView = detail::values_view;
|
||||
using ItemsView = detail::items_view;
|
||||
using Class_ = class_<Map, holder_type>;
|
||||
|
||||
// If either type is a non-module-local bound type then make the map binding non-local as well;
|
||||
@ -718,39 +717,20 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
|
||||
}
|
||||
|
||||
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
||||
static constexpr auto key_type_descr = detail::make_caster<KeyType>::name;
|
||||
static constexpr auto mapped_type_descr = detail::make_caster<MappedType>::name;
|
||||
std::string key_type_name(key_type_descr.text), mapped_type_name(mapped_type_descr.text);
|
||||
|
||||
// If key type isn't properly wrapped, fall back to C++ names
|
||||
if (key_type_name == "%") {
|
||||
key_type_name = detail::type_info_description(typeid(KeyType));
|
||||
}
|
||||
// Similarly for value type:
|
||||
if (mapped_type_name == "%") {
|
||||
mapped_type_name = detail::type_info_description(typeid(MappedType));
|
||||
}
|
||||
|
||||
// Wrap KeysView[KeyType] if it wasn't already wrapped
|
||||
// Wrap KeysView if it wasn't already wrapped
|
||||
if (!detail::get_type_info(typeid(KeysView))) {
|
||||
class_<KeysView> keys_view(
|
||||
scope, ("KeysView[" + key_type_name + "]").c_str(), pybind11::module_local(local));
|
||||
class_<KeysView> keys_view(scope, "KeysView", pybind11::module_local(local));
|
||||
keys_view.def("__len__", &KeysView::len);
|
||||
keys_view.def("__iter__",
|
||||
&KeysView::iter,
|
||||
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
||||
);
|
||||
keys_view.def("__contains__",
|
||||
static_cast<bool (KeysView::*)(const KeyType &)>(&KeysView::contains));
|
||||
// Fallback for when the object is not of the key type
|
||||
keys_view.def("__contains__",
|
||||
static_cast<bool (KeysView::*)(const object &)>(&KeysView::contains));
|
||||
keys_view.def("__contains__", &KeysView::contains);
|
||||
}
|
||||
// Similarly for ValuesView:
|
||||
if (!detail::get_type_info(typeid(ValuesView))) {
|
||||
class_<ValuesView> values_view(scope,
|
||||
("ValuesView[" + mapped_type_name + "]").c_str(),
|
||||
pybind11::module_local(local));
|
||||
class_<ValuesView> values_view(scope, "ValuesView", pybind11::module_local(local));
|
||||
values_view.def("__len__", &ValuesView::len);
|
||||
values_view.def("__iter__",
|
||||
&ValuesView::iter,
|
||||
@ -759,10 +739,7 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
|
||||
}
|
||||
// Similarly for ItemsView:
|
||||
if (!detail::get_type_info(typeid(ItemsView))) {
|
||||
class_<ItemsView> items_view(
|
||||
scope,
|
||||
("ItemsView[" + key_type_name + ", ").append(mapped_type_name + "]").c_str(),
|
||||
pybind11::module_local(local));
|
||||
class_<ItemsView> items_view(scope, "ItemsView", pybind11::module_local(local));
|
||||
items_view.def("__len__", &ItemsView::len);
|
||||
items_view.def("__iter__",
|
||||
&ItemsView::iter,
|
||||
@ -788,25 +765,19 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
|
||||
|
||||
cl.def(
|
||||
"keys",
|
||||
[](Map &m) {
|
||||
return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map, KeysView>(m));
|
||||
},
|
||||
[](Map &m) { return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map>(m)); },
|
||||
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||
);
|
||||
|
||||
cl.def(
|
||||
"values",
|
||||
[](Map &m) {
|
||||
return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map, ValuesView>(m));
|
||||
},
|
||||
[](Map &m) { return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map>(m)); },
|
||||
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||
);
|
||||
|
||||
cl.def(
|
||||
"items",
|
||||
[](Map &m) {
|
||||
return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map, ItemsView>(m));
|
||||
},
|
||||
[](Map &m) { return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map>(m)); },
|
||||
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||
);
|
||||
|
||||
|
@ -79,6 +79,13 @@ struct handle_type_name<typing::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>
|
||||
struct handle_type_name<typing::Dict<K, V>> {
|
||||
static constexpr auto name = const_name("dict[") + make_caster<K>::name + const_name(", ")
|
||||
|
@ -521,11 +521,15 @@ set(PYBIND11_TEST_PREFIX_COMMAND
|
||||
""
|
||||
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
|
||||
add_custom_target(
|
||||
pytest
|
||||
COMMAND ${PYBIND11_TEST_PREFIX_COMMAND} ${PYTHON_EXECUTABLE} -m pytest
|
||||
${PYBIND11_ABS_PYTEST_FILES}
|
||||
${PYBIND11_ABS_PYTEST_FILES} ${PYBIND11_PYTEST_ARGS}
|
||||
DEPENDS ${test_targets}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
USES_TERMINAL)
|
||||
|
@ -218,4 +218,5 @@ def pytest_report_header(config):
|
||||
f" {pybind11_tests.cpp_std}"
|
||||
f" {pybind11_tests.PYBIND11_INTERNALS_ID}"
|
||||
f" PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}"
|
||||
f" PYBIND11_NUMPY_1_ONLY={pybind11_tests.PYBIND11_NUMPY_1_ONLY}"
|
||||
)
|
||||
|
@ -80,10 +80,10 @@ PYBIND11_MODULE(pybind11_tests, m) {
|
||||
|
||||
// Intentionally kept minimal to not create a maintenance chore
|
||||
// ("just enough" to be conclusive).
|
||||
#if defined(_MSC_FULL_VER)
|
||||
m.attr("compiler_info") = "MSVC " PYBIND11_TOSTRING(_MSC_FULL_VER);
|
||||
#elif defined(__VERSION__)
|
||||
#if defined(__VERSION__)
|
||||
m.attr("compiler_info") = __VERSION__;
|
||||
#elif defined(_MSC_FULL_VER)
|
||||
m.attr("compiler_info") = "MSVC " PYBIND11_TOSTRING(_MSC_FULL_VER);
|
||||
#else
|
||||
m.attr("compiler_info") = py::none();
|
||||
#endif
|
||||
@ -95,6 +95,12 @@ PYBIND11_MODULE(pybind11_tests, m) {
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
m.attr("PYBIND11_NUMPY_1_ONLY") =
|
||||
#if defined(PYBIND11_NUMPY_1_ONLY)
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
|
||||
bind_ConstructorStats(m);
|
||||
|
||||
|
@ -54,7 +54,11 @@ int f2(int x) noexcept(true) { return x + 2; }
|
||||
int f3(int x) noexcept(false) { return x + 3; }
|
||||
PYBIND11_WARNING_PUSH
|
||||
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")
|
||||
#endif
|
||||
// NOLINTNEXTLINE(modernize-use-noexcept)
|
||||
int f4(int x) throw() { return x + 4; } // Deprecated equivalent to noexcept(true)
|
||||
PYBIND11_WARNING_POP
|
||||
|
@ -608,7 +608,9 @@ def test_both_ref_mutators():
|
||||
def test_nocopy_wrapper():
|
||||
# get_elem requires a column-contiguous matrix reference, but should be
|
||||
# callable with other types of matrix (via copying):
|
||||
int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order="F")
|
||||
int_matrix_colmajor = np.array(
|
||||
[[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype="l", order="F"
|
||||
)
|
||||
dbl_matrix_colmajor = np.array(
|
||||
int_matrix_colmajor, dtype="double", order="F", copy=True
|
||||
)
|
||||
|
@ -4,7 +4,7 @@ import pytest
|
||||
|
||||
import env
|
||||
import pybind11_cross_module_tests as cm
|
||||
import pybind11_tests # noqa: F401
|
||||
import pybind11_tests
|
||||
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"
|
||||
|
||||
|
||||
# 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():
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
m.throw_nested_exception()
|
||||
|
@ -536,7 +536,12 @@ def test_format_descriptors_for_floating_point_types(test_func):
|
||||
@pytest.mark.parametrize("contiguity", [None, "C", "F"])
|
||||
@pytest.mark.parametrize("noconvert", [False, True])
|
||||
@pytest.mark.filterwarnings(
|
||||
"ignore:Casting complex values to real discards the imaginary part:numpy.ComplexWarning"
|
||||
"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):
|
||||
function_name = "accept_double"
|
||||
@ -583,7 +588,8 @@ def test_argument_conversions(forcecast, contiguity, noconvert):
|
||||
def test_dtype_refcount_leak():
|
||||
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)
|
||||
before = getrefcount(dtype)
|
||||
m.ndim(a)
|
||||
|
@ -405,10 +405,35 @@ TEST_SUBMODULE(numpy_dtypes, m) {
|
||||
});
|
||||
|
||||
// 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{
|
||||
"byte", "short", "intc", "int_", "longlong", "ubyte", "ushort",
|
||||
"uintc", "uint", "ulonglong", "half", "single", "double", "longdouble",
|
||||
"csingle", "cdouble", "clongdouble", "bool_", "datetime64", "timedelta64", "object_"};
|
||||
"byte",
|
||||
"short",
|
||||
"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", []() {
|
||||
py::list l;
|
||||
|
@ -3,6 +3,7 @@ import re
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
from pybind11_tests import PYBIND11_NUMPY_1_ONLY
|
||||
from pybind11_tests import numpy_dtypes as m
|
||||
|
||||
np = pytest.importorskip("numpy")
|
||||
@ -172,13 +173,20 @@ def test_dtype(simple_dtype):
|
||||
np.zeros(1, m.trailing_padding_dtype())
|
||||
)
|
||||
|
||||
expected_chars = "bhilqBHILQefdgFDG?MmO"
|
||||
assert m.test_dtype_kind() == list("iiiiiuuuuuffffcccbMmO")
|
||||
expected_chars = list("bhilqBHILQefdgFDG?MmO")
|
||||
# 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_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_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):
|
||||
|
@ -834,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_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_list_int", [](const py::typing::List<int> &) {});
|
||||
m.def("annotate_set_str", [](const py::typing::Set<std::string> &) {});
|
||||
|
@ -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):
|
||||
assert (
|
||||
doc(m.annotate_dict_str_int)
|
||||
|
@ -103,21 +103,26 @@ private:
|
||||
int value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::unordered_set<T *> &pointer_set() {
|
||||
// https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
|
||||
static auto singleton = new std::unordered_set<T *>();
|
||||
return *singleton;
|
||||
}
|
||||
|
||||
// test_unique_nodelete
|
||||
// Object with a private destructor
|
||||
class MyObject4;
|
||||
std::unordered_set<MyObject4 *> myobject4_instances;
|
||||
class MyObject4 {
|
||||
public:
|
||||
explicit MyObject4(int value) : value{value} {
|
||||
print_created(this);
|
||||
myobject4_instances.insert(this);
|
||||
pointer_set<MyObject4>().insert(this);
|
||||
}
|
||||
int value;
|
||||
|
||||
static void cleanupAllInstances() {
|
||||
auto tmp = std::move(myobject4_instances);
|
||||
myobject4_instances.clear();
|
||||
auto tmp = std::move(pointer_set<MyObject4>());
|
||||
pointer_set<MyObject4>().clear();
|
||||
for (auto *o : tmp) {
|
||||
delete o;
|
||||
}
|
||||
@ -125,7 +130,7 @@ public:
|
||||
|
||||
private:
|
||||
~MyObject4() {
|
||||
myobject4_instances.erase(this);
|
||||
pointer_set<MyObject4>().erase(this);
|
||||
print_destroyed(this);
|
||||
}
|
||||
};
|
||||
@ -133,19 +138,17 @@ private:
|
||||
// test_unique_deleter
|
||||
// Object with std::unique_ptr<T, D> where D is not matching the base class
|
||||
// Object with a protected destructor
|
||||
class MyObject4a;
|
||||
std::unordered_set<MyObject4a *> myobject4a_instances;
|
||||
class MyObject4a {
|
||||
public:
|
||||
explicit MyObject4a(int i) : value{i} {
|
||||
print_created(this);
|
||||
myobject4a_instances.insert(this);
|
||||
pointer_set<MyObject4a>().insert(this);
|
||||
};
|
||||
int value;
|
||||
|
||||
static void cleanupAllInstances() {
|
||||
auto tmp = std::move(myobject4a_instances);
|
||||
myobject4a_instances.clear();
|
||||
auto tmp = std::move(pointer_set<MyObject4a>());
|
||||
pointer_set<MyObject4a>().clear();
|
||||
for (auto *o : tmp) {
|
||||
delete o;
|
||||
}
|
||||
@ -153,7 +156,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual ~MyObject4a() {
|
||||
myobject4a_instances.erase(this);
|
||||
pointer_set<MyObject4a>().erase(this);
|
||||
print_destroyed(this);
|
||||
}
|
||||
};
|
||||
|
@ -192,6 +192,16 @@ TEST_SUBMODULE(stl_binders, m) {
|
||||
py::bind_map<std::unordered_map<std::string, double const>>(m,
|
||||
"UnorderedMapStringDoubleConst");
|
||||
|
||||
// test_map_view_types
|
||||
py::bind_map<std::map<std::string, float>>(m, "MapStringFloat");
|
||||
py::bind_map<std::unordered_map<std::string, float>>(m, "UnorderedMapStringFloat");
|
||||
|
||||
py::bind_map<std::map<std::pair<double, int>, int32_t>>(m, "MapPairDoubleIntInt32");
|
||||
py::bind_map<std::map<std::pair<double, int>, int64_t>>(m, "MapPairDoubleIntInt64");
|
||||
|
||||
py::bind_map<std::map<int, py::object>>(m, "MapIntObject");
|
||||
py::bind_map<std::map<std::string, py::object>>(m, "MapStringObject");
|
||||
|
||||
py::class_<E_nc>(m, "ENC").def(py::init<int>()).def_readwrite("value", &E_nc::value);
|
||||
|
||||
// test_noncopyable_containers
|
||||
|
@ -317,9 +317,9 @@ def test_map_view_types():
|
||||
map_string_double_const = m.MapStringDoubleConst()
|
||||
unordered_map_string_double_const = m.UnorderedMapStringDoubleConst()
|
||||
|
||||
assert map_string_double.keys().__class__.__name__ == "KeysView[str]"
|
||||
assert map_string_double.values().__class__.__name__ == "ValuesView[float]"
|
||||
assert map_string_double.items().__class__.__name__ == "ItemsView[str, float]"
|
||||
assert map_string_double.keys().__class__.__name__ == "KeysView"
|
||||
assert map_string_double.values().__class__.__name__ == "ValuesView"
|
||||
assert map_string_double.items().__class__.__name__ == "ItemsView"
|
||||
|
||||
keys_type = type(map_string_double.keys())
|
||||
assert type(unordered_map_string_double.keys()) is keys_type
|
||||
@ -336,6 +336,30 @@ def test_map_view_types():
|
||||
assert type(map_string_double_const.items()) is items_type
|
||||
assert type(unordered_map_string_double_const.items()) is items_type
|
||||
|
||||
map_string_float = m.MapStringFloat()
|
||||
unordered_map_string_float = m.UnorderedMapStringFloat()
|
||||
|
||||
assert type(map_string_float.keys()) is keys_type
|
||||
assert type(unordered_map_string_float.keys()) is keys_type
|
||||
assert type(map_string_float.values()) is values_type
|
||||
assert type(unordered_map_string_float.values()) is values_type
|
||||
assert type(map_string_float.items()) is items_type
|
||||
assert type(unordered_map_string_float.items()) is items_type
|
||||
|
||||
map_pair_double_int_int32 = m.MapPairDoubleIntInt32()
|
||||
map_pair_double_int_int64 = m.MapPairDoubleIntInt64()
|
||||
|
||||
assert type(map_pair_double_int_int32.values()) is values_type
|
||||
assert type(map_pair_double_int_int64.values()) is values_type
|
||||
|
||||
map_int_object = m.MapIntObject()
|
||||
map_string_object = m.MapStringObject()
|
||||
|
||||
assert type(map_int_object.keys()) is keys_type
|
||||
assert type(map_string_object.keys()) is keys_type
|
||||
assert type(map_int_object.items()) is items_type
|
||||
assert type(map_string_object.items()) is items_type
|
||||
|
||||
|
||||
def test_recursive_vector():
|
||||
recursive_vector = m.RecursiveVector()
|
||||
|
@ -173,12 +173,16 @@ endif()
|
||||
# Check to see which Python mode we are in, new, old, or no python
|
||||
if(PYBIND11_NOPYTHON)
|
||||
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(
|
||||
_pybind11_missing_old_python STREQUAL "NEW"
|
||||
OR PYBIND11_FINDPYTHON
|
||||
OR Python_FOUND
|
||||
OR Python2_FOUND
|
||||
OR Python3_FOUND)
|
||||
(NOT DEFINED PYBIND11_FINDPYTHON OR PYBIND11_FINDPYTHON)
|
||||
AND (_pybind11_missing_old_python STREQUAL "NEW"
|
||||
OR PYBIND11_FINDPYTHON
|
||||
OR Python_FOUND
|
||||
OR Python3_FOUND
|
||||
))
|
||||
|
||||
# New mode
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/pybind11NewTools.cmake")
|
||||
|
||||
|
@ -110,15 +110,17 @@ if(NOT DEFINED ${_Python}_EXECUTABLE)
|
||||
|
||||
endif()
|
||||
|
||||
if(NOT ${_Python}_EXECUTABLE STREQUAL PYBIND11_PYTHON_EXECUTABLE_LAST)
|
||||
if(DEFINED PYBIND11_PYTHON_EXECUTABLE_LAST AND NOT ${_Python}_EXECUTABLE STREQUAL
|
||||
PYBIND11_PYTHON_EXECUTABLE_LAST)
|
||||
# Detect changes to the Python version/binary in subsequent CMake runs, and refresh config if needed
|
||||
unset(PYTHON_IS_DEBUG CACHE)
|
||||
unset(PYTHON_MODULE_EXTENSION CACHE)
|
||||
set(PYBIND11_PYTHON_EXECUTABLE_LAST
|
||||
"${${_Python}_EXECUTABLE}"
|
||||
CACHE INTERNAL "Python executable during the last CMake run")
|
||||
endif()
|
||||
|
||||
set(PYBIND11_PYTHON_EXECUTABLE_LAST
|
||||
"${${_Python}_EXECUTABLE}"
|
||||
CACHE INTERNAL "Python executable during the last CMake run")
|
||||
|
||||
if(NOT DEFINED PYTHON_IS_DEBUG)
|
||||
# Debug check - see https://stackoverflow.com/questions/646518/python-how-to-detect-debug-Interpreter
|
||||
execute_process(
|
||||
|
Loading…
Reference in New Issue
Block a user