mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
Merge branch 'v2.13' into stable
This commit is contained in:
commit
5211a1715a
@ -57,10 +57,12 @@ Checks: |
|
||||
readability-string-compare,
|
||||
readability-suspicious-call-argument,
|
||||
readability-uniqueptr-delete-release,
|
||||
-bugprone-chained-comparison,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-exception-escape,
|
||||
-bugprone-reserved-identifier,
|
||||
-bugprone-unused-raii,
|
||||
-performance-enum-size,
|
||||
|
||||
CheckOptions:
|
||||
- key: modernize-use-equals-default.IgnoreMacros
|
||||
|
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@ -340,6 +340,12 @@ jobs:
|
||||
- clang: 16
|
||||
std: 20
|
||||
container_suffix: "-bullseye"
|
||||
- clang: 17
|
||||
std: 20
|
||||
container_suffix: "-bookworm"
|
||||
- clang: 18
|
||||
std: 20
|
||||
container_suffix: "-bookworm"
|
||||
|
||||
name: "🐍 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64"
|
||||
container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}"
|
||||
@ -501,7 +507,9 @@ jobs:
|
||||
- { gcc: 7, std: 17 }
|
||||
- { gcc: 8, std: 14 }
|
||||
- { gcc: 8, std: 17 }
|
||||
- { gcc: 9, std: 20 }
|
||||
- { gcc: 10, std: 17 }
|
||||
- { gcc: 10, std: 20 }
|
||||
- { gcc: 11, std: 20 }
|
||||
- { gcc: 12, std: 20 }
|
||||
- { gcc: 13, std: 20 }
|
||||
|
30
.github/workflows/emscripten.yaml
vendored
Normal file
30
.github/workflows/emscripten.yaml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: WASM
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- stable
|
||||
- v*
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-wasm-emscripten:
|
||||
name: Pyodide wheel
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: pypa/cibuildwheel@v2.20
|
||||
env:
|
||||
PYODIDE_BUILD_EXPORTS: whole_archive
|
||||
with:
|
||||
package-dir: tests
|
||||
only: cp312-pyodide_wasm32
|
2
.github/workflows/format.yml
vendored
2
.github/workflows/format.yml
vendored
@ -41,7 +41,7 @@ jobs:
|
||||
# in .github/CONTRIBUTING.md and update as needed.
|
||||
name: Clang-Tidy
|
||||
runs-on: ubuntu-latest
|
||||
container: silkeh/clang:15-bullseye
|
||||
container: silkeh/clang:18-bookworm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
2
.github/workflows/pip.yml
vendored
2
.github/workflows/pip.yml
vendored
@ -102,7 +102,7 @@ jobs:
|
||||
- uses: actions/download-artifact@v4
|
||||
|
||||
- name: Generate artifact attestation for sdist and wheel
|
||||
uses: actions/attest-build-provenance@173725a1209d09b31f9d30a3890cf2757ebbff0d # v1.1.2
|
||||
uses: actions/attest-build-provenance@310b0a4a3b0b78ef57ecda988ee04b132db73ef8 # v1.4.1
|
||||
with:
|
||||
subject-path: "*/pybind11*"
|
||||
|
||||
|
@ -25,14 +25,14 @@ repos:
|
||||
|
||||
# Clang format the codebase automatically
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: "v18.1.5"
|
||||
rev: "v18.1.8"
|
||||
hooks:
|
||||
- id: clang-format
|
||||
types_or: [c++, c, cuda]
|
||||
|
||||
# Ruff, the Python auto-correcting linter/formatter written in Rust
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.4.7
|
||||
rev: v0.5.6
|
||||
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.10.0"
|
||||
rev: "v1.11.1"
|
||||
hooks:
|
||||
- id: mypy
|
||||
args: []
|
||||
@ -79,7 +79,7 @@ repos:
|
||||
|
||||
# Also code format the docs
|
||||
- repo: https://github.com/adamchainz/blacken-docs
|
||||
rev: "1.16.0"
|
||||
rev: "1.18.0"
|
||||
hooks:
|
||||
- id: blacken-docs
|
||||
additional_dependencies:
|
||||
@ -142,14 +142,14 @@ repos:
|
||||
|
||||
# PyLint has native support - not always usable, but works for us
|
||||
- repo: https://github.com/PyCQA/pylint
|
||||
rev: "v3.2.2"
|
||||
rev: "v3.2.6"
|
||||
hooks:
|
||||
- id: pylint
|
||||
files: ^pybind11
|
||||
|
||||
# Check schemas on some of our YAML files
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.28.4
|
||||
rev: 0.29.1
|
||||
hooks:
|
||||
- id: check-readthedocs
|
||||
- id: check-github-workflows
|
||||
|
@ -154,6 +154,7 @@ set(PYBIND11_HEADERS
|
||||
include/pybind11/detail/internals.h
|
||||
include/pybind11/detail/type_caster_base.h
|
||||
include/pybind11/detail/typeid.h
|
||||
include/pybind11/detail/value_and_holder.h
|
||||
include/pybind11/attr.h
|
||||
include/pybind11/buffer_info.h
|
||||
include/pybind11/cast.h
|
||||
|
@ -259,7 +259,7 @@ copying to take place:
|
||||
"small"_a // <- This one can be copied if needed
|
||||
);
|
||||
|
||||
With the above binding code, attempting to call the the ``some_method(m)``
|
||||
With the above binding code, attempting to call the ``some_method(m)``
|
||||
method on a ``MyClass`` object, or attempting to call ``some_function(m, m2)``
|
||||
will raise a ``RuntimeError`` rather than making a temporary copy of the array.
|
||||
It will, however, allow the ``m2`` argument to be copied into a temporary if
|
||||
|
@ -15,6 +15,98 @@ IN DEVELOPMENT
|
||||
|
||||
Changes will be summarized here periodically.
|
||||
|
||||
New Features:
|
||||
|
||||
* Support for Python 3.7 was removed. (Official end-of-life: 2023-06-27).
|
||||
`#5191 <https://github.com/pybind/pybind11/pull/5191>`_
|
||||
|
||||
* stl.h ``list|set|map_caster`` were made more user friendly: it is no longer
|
||||
necessary to explicitly convert Python iterables to ``tuple()``, ``set()``,
|
||||
or ``map()`` in many common situations.
|
||||
`#4686 <https://github.com/pybind/pybind11/pull/4686>`_
|
||||
|
||||
* Support for CMake older than 3.15 removed. CMake 3.15-3.30 supported.
|
||||
`#5304 <https://github.com/pybind/pybind11/pull/5304>`_
|
||||
|
||||
Version 2.13.4 (August 14, 2024)
|
||||
--------------------------------
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* Fix paths with spaces, including on Windows.
|
||||
(Replaces regression from `#5302 <https://github.com/pybind/pybind11/pull/5302>`_)
|
||||
`#4874 <https://github.com/pybind/pybind11/pull/4874>`_
|
||||
|
||||
Documentation:
|
||||
|
||||
* Remove repetitive words.
|
||||
`#5308 <https://github.com/pybind/pybind11/pull/5308>`_
|
||||
|
||||
|
||||
Version 2.13.3 (August 13, 2024)
|
||||
--------------------------------
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* Quote paths from pybind11-config
|
||||
`#5302 <https://github.com/pybind/pybind11/pull/5302>`_
|
||||
|
||||
|
||||
* Fix typo in Emscripten support when in config mode (CMake)
|
||||
`#5301 <https://github.com/pybind/pybind11/pull/5301>`_
|
||||
|
||||
|
||||
Version 2.13.2 (August 13, 2024)
|
||||
--------------------------------
|
||||
|
||||
New Features:
|
||||
|
||||
* A ``pybind11::detail::type_caster_std_function_specializations`` feature was added, to support specializations for
|
||||
``std::function``'s with return types that require custom to-Python conversion behavior (to primary use case is to catch and
|
||||
convert exceptions).
|
||||
`#4597 <https://github.com/pybind/pybind11/pull/4597>`_
|
||||
|
||||
|
||||
Changes:
|
||||
|
||||
|
||||
* Use ``PyMutex`` instead of ``std::mutex`` for internal locking in the free-threaded build.
|
||||
`#5219 <https://github.com/pybind/pybind11/pull/5219>`_
|
||||
|
||||
* Add a special type annotation for C++ empty tuple.
|
||||
`#5214 <https://github.com/pybind/pybind11/pull/5214>`_
|
||||
|
||||
* When compiling for WebAssembly, add the required exception flags (CMake 3.13+).
|
||||
`#5298 <https://github.com/pybind/pybind11/pull/5298>`_
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* Make ``gil_safe_call_once_and_store`` thread-safe in free-threaded CPython.
|
||||
`#5246 <https://github.com/pybind/pybind11/pull/5246>`_
|
||||
|
||||
* A missing ``#include <algorithm>`` in pybind11/typing.h was added to fix build errors (in case user code does not already depend
|
||||
on that include).
|
||||
`#5208 <https://github.com/pybind/pybind11/pull/5208>`_
|
||||
|
||||
* Fix regression introduced in #5201 for GCC<10.3 in C++20 mode.
|
||||
`#5205 <https://github.com/pybind/pybind11/pull/5205>`_
|
||||
|
||||
|
||||
.. fix(cmake)
|
||||
|
||||
* Remove extra = when assigning flto value in the case for Clang in CMake.
|
||||
`#5207 <https://github.com/pybind/pybind11/pull/5207>`_
|
||||
|
||||
|
||||
Tests:
|
||||
|
||||
* Adding WASM testing to our CI (Pyodide / Emscripten via scikit-build-core).
|
||||
`#4745 <https://github.com/pybind/pybind11/pull/4745>`_
|
||||
|
||||
* clang-tidy (in GitHub Actions) was updated from clang 15 to clang 18.
|
||||
`#5272 <https://github.com/pybind/pybind11/pull/5272>`_
|
||||
|
||||
|
||||
Version 2.13.1 (June 26, 2024)
|
||||
------------------------------
|
||||
|
||||
|
@ -25,7 +25,7 @@ A Python extension module can be created with just a few lines of code:
|
||||
find_package(pybind11 CONFIG REQUIRED)
|
||||
|
||||
pybind11_add_module(example example.cpp)
|
||||
install(TARGET example DESTINATION .)
|
||||
install(TARGETS example DESTINATION .)
|
||||
|
||||
(You use the ``add_subdirectory`` instead, see the example in :ref:`cmake`.) In
|
||||
this example, the code is located in a file named :file:`example.cpp`. Either
|
||||
@ -388,7 +388,7 @@ that will be respected instead of the built-in flag search.
|
||||
|
||||
The ``OPT_SIZE`` flag enables size-based optimization equivalent to the
|
||||
standard ``/Os`` or ``-Os`` compiler flags and the ``MinSizeRel`` build type,
|
||||
which avoid optimizations that that can substantially increase the size of the
|
||||
which avoid optimizations that can substantially increase the size of the
|
||||
resulting binary. This flag is particularly useful in projects that are split
|
||||
into performance-critical parts and associated bindings. In this case, we can
|
||||
compile the project in release mode (and hence, optimize performance globally),
|
||||
@ -719,7 +719,7 @@ customizable pybind11-based wrappers by parsing C++ header files.
|
||||
|
||||
[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
|
||||
found in headers. It 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).
|
||||
|
||||
|
@ -50,10 +50,6 @@ clean, well written patch would likely be accepted to solve them.
|
||||
One consequence is that containers of ``char *`` are currently not supported.
|
||||
`#2245 <https://github.com/pybind/pybind11/issues/2245>`_
|
||||
|
||||
- The ``cpptest`` does not run on Windows with Python 3.8 or newer, due to DLL
|
||||
loader changes. User code that is correctly installed should not be affected.
|
||||
`#2560 <https://github.com/pybind/pybind11/issue/2560>`_
|
||||
|
||||
Python 3.9.0 warning
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -16,9 +16,9 @@ breathe==4.35.0 \
|
||||
--hash=sha256:5165541c3c67b6c7adde8b3ecfe895c6f7844783c4076b6d8d287e4f33d62386 \
|
||||
--hash=sha256:52c581f42ca4310737f9e435e3851c3d1f15446205a85fbc272f1f97ed74f5be
|
||||
# via -r requirements.in
|
||||
certifi==2024.2.2 \
|
||||
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
|
||||
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
|
||||
certifi==2024.7.4 \
|
||||
--hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
|
||||
--hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
|
||||
# via requests
|
||||
charset-normalizer==3.3.2 \
|
||||
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
|
||||
|
@ -740,6 +740,13 @@ class type_caster<std::pair<T1, T2>> : public tuple_caster<std::pair, T1, T2> {}
|
||||
template <typename... Ts>
|
||||
class type_caster<std::tuple<Ts...>> : public tuple_caster<std::tuple, Ts...> {};
|
||||
|
||||
template <>
|
||||
class type_caster<std::tuple<>> : public tuple_caster<std::tuple> {
|
||||
public:
|
||||
// PEP 484 specifies this syntax for an empty tuple
|
||||
static constexpr auto name = const_name("tuple[()]");
|
||||
};
|
||||
|
||||
/// Helper class which abstracts away certain actions. Users can provide specializations for
|
||||
/// custom holders, but it's only necessary if the type has a non-standard interface.
|
||||
template <typename T>
|
||||
@ -787,11 +794,11 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
bool load_value(value_and_holder &&v_h) {
|
||||
void load_value(value_and_holder &&v_h) {
|
||||
if (v_h.holder_constructed()) {
|
||||
value = v_h.value_ptr();
|
||||
holder = v_h.template holder<holder_type>();
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
|
||||
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||
|
@ -11,11 +11,11 @@
|
||||
|
||||
#define PYBIND11_VERSION_MAJOR 2
|
||||
#define PYBIND11_VERSION_MINOR 13
|
||||
#define PYBIND11_VERSION_PATCH 1
|
||||
#define PYBIND11_VERSION_PATCH 4
|
||||
|
||||
// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html
|
||||
// Additional convention: 0xD = dev
|
||||
#define PYBIND11_VERSION_HEX 0x020D0100
|
||||
#define PYBIND11_VERSION_HEX 0x020D0400
|
||||
|
||||
// Define some generic pybind11 helper macros for warning management.
|
||||
//
|
||||
@ -462,6 +462,22 @@ PYBIND11_WARNING_POP
|
||||
return "Hello, World!";
|
||||
});
|
||||
}
|
||||
|
||||
The third macro argument is optional (available since 2.13.0), and can be used to
|
||||
mark the extension module as safe to run without the GIL under a free-threaded CPython
|
||||
interpreter. Passing this argument has no effect on other interpreters.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
PYBIND11_MODULE(example, m, py::mod_gil_not_used()) {
|
||||
m.doc() = "pybind11 example module safe to run without the GIL";
|
||||
|
||||
// Add bindings here
|
||||
m.def("foo", []() {
|
||||
return "Hello, Free-threaded World!";
|
||||
});
|
||||
}
|
||||
|
||||
\endrst */
|
||||
#define PYBIND11_MODULE(name, variable, ...) \
|
||||
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name) \
|
||||
@ -538,7 +554,7 @@ enum class return_value_policy : uint8_t {
|
||||
object without taking ownership similar to the above
|
||||
return_value_policy::reference policy. In contrast to that policy, the
|
||||
function or property's implicit this argument (called the parent) is
|
||||
considered to be the the owner of the return value (the child).
|
||||
considered to be the owner of the return value (the child).
|
||||
pybind11 then couples the lifetime of the parent to the child via a
|
||||
reference relationship that ensures that the parent cannot be garbage
|
||||
collected while Python is still using the child. More advanced
|
||||
|
@ -128,11 +128,13 @@ void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
|
||||
// the holder and destruction happens when we leave the C++ scope, and the holder
|
||||
// class gets to handle the destruction however it likes.
|
||||
v_h.value_ptr() = ptr;
|
||||
v_h.set_instance_registered(true); // To prevent init_instance from registering it
|
||||
v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
|
||||
v_h.set_instance_registered(true); // Trick to prevent init_instance from registering it
|
||||
// DANGER ZONE BEGIN: exceptions will leave v_h in an invalid state.
|
||||
v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
|
||||
Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
|
||||
v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
|
||||
v_h.set_instance_registered(false);
|
||||
// DANGER ZONE END.
|
||||
|
||||
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
|
||||
} else {
|
||||
|
@ -148,20 +148,35 @@ struct override_hash {
|
||||
|
||||
using instance_map = std::unordered_multimap<const void *, instance *>;
|
||||
|
||||
#ifdef Py_GIL_DISABLED
|
||||
// Wrapper around PyMutex to provide BasicLockable semantics
|
||||
class pymutex {
|
||||
PyMutex mutex;
|
||||
|
||||
public:
|
||||
pymutex() : mutex({}) {}
|
||||
void lock() { PyMutex_Lock(&mutex); }
|
||||
void unlock() { PyMutex_Unlock(&mutex); }
|
||||
};
|
||||
|
||||
// Instance map shards are used to reduce mutex contention in free-threaded Python.
|
||||
struct instance_map_shard {
|
||||
std::mutex mutex;
|
||||
instance_map registered_instances;
|
||||
pymutex mutex;
|
||||
// alignas(64) would be better, but causes compile errors in macOS before 10.14 (see #5200)
|
||||
char padding[64 - (sizeof(std::mutex) + sizeof(instance_map)) % 64];
|
||||
char padding[64 - (sizeof(instance_map) + sizeof(pymutex)) % 64];
|
||||
};
|
||||
|
||||
static_assert(sizeof(instance_map_shard) % 64 == 0,
|
||||
"instance_map_shard size is not a multiple of 64 bytes");
|
||||
#endif
|
||||
|
||||
/// Internal data structure used to track registered instances and types.
|
||||
/// Whenever binary incompatible changes are made to this structure,
|
||||
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
|
||||
struct internals {
|
||||
#ifdef Py_GIL_DISABLED
|
||||
std::mutex mutex;
|
||||
pymutex mutex;
|
||||
#endif
|
||||
// std::type_index -> pybind11's type information
|
||||
type_map<type_info *> registered_types_cpp;
|
||||
@ -538,7 +553,7 @@ PYBIND11_NOINLINE internals &get_internals() {
|
||||
}
|
||||
#endif
|
||||
internals_ptr->istate = tstate->interp;
|
||||
state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp);
|
||||
state_dict[PYBIND11_INTERNALS_ID] = capsule(reinterpret_cast<void *>(internals_pp));
|
||||
internals_ptr->registered_exception_translators.push_front(&translate_exception);
|
||||
internals_ptr->static_property_type = make_static_property_type();
|
||||
internals_ptr->default_metaclass = make_default_metaclass();
|
||||
@ -614,7 +629,7 @@ inline local_internals &get_local_internals() {
|
||||
}
|
||||
|
||||
#ifdef Py_GIL_DISABLED
|
||||
# define PYBIND11_LOCK_INTERNALS(internals) std::unique_lock<std::mutex> lock((internals).mutex)
|
||||
# define PYBIND11_LOCK_INTERNALS(internals) std::unique_lock<pymutex> lock((internals).mutex)
|
||||
#else
|
||||
# define PYBIND11_LOCK_INTERNALS(internals)
|
||||
#endif
|
||||
@ -651,7 +666,7 @@ inline auto with_instance_map(const void *ptr,
|
||||
auto idx = static_cast<size_t>(hash & internals.instance_shards_mask);
|
||||
|
||||
auto &shard = internals.instance_shards[idx];
|
||||
std::unique_lock<std::mutex> lock(shard.mutex);
|
||||
std::unique_lock<pymutex> lock(shard.mutex);
|
||||
return cb(shard.registered_instances);
|
||||
#else
|
||||
(void) ptr;
|
||||
@ -667,7 +682,7 @@ inline size_t num_registered_instances() {
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i <= internals.instance_shards_mask; ++i) {
|
||||
auto &shard = internals.instance_shards[i];
|
||||
std::unique_lock<std::mutex> lock(shard.mutex);
|
||||
std::unique_lock<pymutex> lock(shard.mutex);
|
||||
count += shard.registered_instances.size();
|
||||
}
|
||||
return count;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "descr.h"
|
||||
#include "internals.h"
|
||||
#include "typeid.h"
|
||||
#include "value_and_holder.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
@ -259,67 +260,6 @@ PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
|
||||
});
|
||||
}
|
||||
|
||||
struct value_and_holder {
|
||||
instance *inst = nullptr;
|
||||
size_t index = 0u;
|
||||
const detail::type_info *type = nullptr;
|
||||
void **vh = nullptr;
|
||||
|
||||
// Main constructor for a found value/holder:
|
||||
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index)
|
||||
: inst{i}, index{index}, type{type},
|
||||
vh{inst->simple_layout ? inst->simple_value_holder
|
||||
: &inst->nonsimple.values_and_holders[vpos]} {}
|
||||
|
||||
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
|
||||
value_and_holder() = default;
|
||||
|
||||
// Used for past-the-end iterator
|
||||
explicit value_and_holder(size_t index) : index{index} {}
|
||||
|
||||
template <typename V = void>
|
||||
V *&value_ptr() const {
|
||||
return reinterpret_cast<V *&>(vh[0]);
|
||||
}
|
||||
// True if this `value_and_holder` has a non-null value pointer
|
||||
explicit operator bool() const { return value_ptr() != nullptr; }
|
||||
|
||||
template <typename H>
|
||||
H &holder() const {
|
||||
return reinterpret_cast<H &>(vh[1]);
|
||||
}
|
||||
bool holder_constructed() const {
|
||||
return inst->simple_layout
|
||||
? inst->simple_holder_constructed
|
||||
: (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u;
|
||||
}
|
||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||
void set_holder_constructed(bool v = true) {
|
||||
if (inst->simple_layout) {
|
||||
inst->simple_holder_constructed = v;
|
||||
} else if (v) {
|
||||
inst->nonsimple.status[index] |= instance::status_holder_constructed;
|
||||
} else {
|
||||
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed;
|
||||
}
|
||||
}
|
||||
bool instance_registered() const {
|
||||
return inst->simple_layout
|
||||
? inst->simple_instance_registered
|
||||
: ((inst->nonsimple.status[index] & instance::status_instance_registered) != 0);
|
||||
}
|
||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||
void set_instance_registered(bool v = true) {
|
||||
if (inst->simple_layout) {
|
||||
inst->simple_instance_registered = v;
|
||||
} else if (v) {
|
||||
inst->nonsimple.status[index] |= instance::status_instance_registered;
|
||||
} else {
|
||||
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Container for accessing and iterating over an instance's values/holders
|
||||
struct values_and_holders {
|
||||
private:
|
||||
@ -488,7 +428,7 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
|
||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||
PYBIND11_NOINLINE void instance::deallocate_layout() {
|
||||
if (!simple_layout) {
|
||||
PyMem_Free(nonsimple.values_and_holders);
|
||||
PyMem_Free(reinterpret_cast<void *>(nonsimple.values_and_holders));
|
||||
}
|
||||
}
|
||||
|
||||
|
77
include/pybind11/detail/value_and_holder.h
Normal file
77
include/pybind11/detail/value_and_holder.h
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2016-2024 The Pybind Development Team.
|
||||
// All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <typeinfo>
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
|
||||
struct value_and_holder {
|
||||
instance *inst = nullptr;
|
||||
size_t index = 0u;
|
||||
const detail::type_info *type = nullptr;
|
||||
void **vh = nullptr;
|
||||
|
||||
// Main constructor for a found value/holder:
|
||||
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index)
|
||||
: inst{i}, index{index}, type{type},
|
||||
vh{inst->simple_layout ? inst->simple_value_holder
|
||||
: &inst->nonsimple.values_and_holders[vpos]} {}
|
||||
|
||||
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
|
||||
value_and_holder() = default;
|
||||
|
||||
// Used for past-the-end iterator
|
||||
explicit value_and_holder(size_t index) : index{index} {}
|
||||
|
||||
template <typename V = void>
|
||||
V *&value_ptr() const {
|
||||
return reinterpret_cast<V *&>(vh[0]);
|
||||
}
|
||||
// True if this `value_and_holder` has a non-null value pointer
|
||||
explicit operator bool() const { return value_ptr() != nullptr; }
|
||||
|
||||
template <typename H>
|
||||
H &holder() const {
|
||||
return reinterpret_cast<H &>(vh[1]);
|
||||
}
|
||||
bool holder_constructed() const {
|
||||
return inst->simple_layout
|
||||
? inst->simple_holder_constructed
|
||||
: (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u;
|
||||
}
|
||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||
void set_holder_constructed(bool v = true) {
|
||||
if (inst->simple_layout) {
|
||||
inst->simple_holder_constructed = v;
|
||||
} else if (v) {
|
||||
inst->nonsimple.status[index] |= instance::status_holder_constructed;
|
||||
} else {
|
||||
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed;
|
||||
}
|
||||
}
|
||||
bool instance_registered() const {
|
||||
return inst->simple_layout
|
||||
? inst->simple_instance_registered
|
||||
: ((inst->nonsimple.status[index] & instance::status_instance_registered) != 0);
|
||||
}
|
||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||
void set_instance_registered(bool v = true) {
|
||||
if (inst->simple_layout) {
|
||||
inst->simple_instance_registered = v;
|
||||
} else if (v) {
|
||||
inst->nonsimple.status[index] |= instance::status_instance_registered;
|
||||
} else {
|
||||
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
@ -469,9 +469,6 @@ struct type_caster<Eigen::TensorMap<Type, Options>,
|
||||
parent_object = reinterpret_borrow<object>(parent);
|
||||
break;
|
||||
|
||||
case return_value_policy::take_ownership:
|
||||
delete src;
|
||||
// fallthrough
|
||||
default:
|
||||
// move, take_ownership don't make any sense for a ref/map:
|
||||
pybind11_fail("Invalid return_value_policy for Eigen Map type, must be either "
|
||||
|
@ -9,12 +9,55 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS
|
||||
|
||||
#include "pybind11.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
PYBIND11_NAMESPACE_BEGIN(type_caster_std_function_specializations)
|
||||
|
||||
// ensure GIL is held during functor destruction
|
||||
struct func_handle {
|
||||
function f;
|
||||
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
|
||||
// This triggers a syntax error under very special conditions (very weird indeed).
|
||||
explicit
|
||||
#endif
|
||||
func_handle(function &&f_) noexcept
|
||||
: f(std::move(f_)) {
|
||||
}
|
||||
func_handle(const func_handle &f_) { operator=(f_); }
|
||||
func_handle &operator=(const func_handle &f_) {
|
||||
gil_scoped_acquire acq;
|
||||
f = f_.f;
|
||||
return *this;
|
||||
}
|
||||
~func_handle() {
|
||||
gil_scoped_acquire acq;
|
||||
function kill_f(std::move(f));
|
||||
}
|
||||
};
|
||||
|
||||
// to emulate 'move initialization capture' in C++11
|
||||
struct func_wrapper_base {
|
||||
func_handle hfunc;
|
||||
explicit func_wrapper_base(func_handle &&hf) noexcept : hfunc(hf) {}
|
||||
};
|
||||
|
||||
template <typename Return, typename... Args>
|
||||
struct func_wrapper : func_wrapper_base {
|
||||
using func_wrapper_base::func_wrapper_base;
|
||||
Return operator()(Args... args) const {
|
||||
gil_scoped_acquire acq;
|
||||
// casts the returned object as a rvalue to the return type
|
||||
return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
|
||||
}
|
||||
};
|
||||
|
||||
PYBIND11_NAMESPACE_END(type_caster_std_function_specializations)
|
||||
|
||||
template <typename Return, typename... Args>
|
||||
struct type_caster<std::function<Return(Args...)>> {
|
||||
@ -77,40 +120,8 @@ public:
|
||||
// See PR #1413 for full details
|
||||
}
|
||||
|
||||
// ensure GIL is held during functor destruction
|
||||
struct func_handle {
|
||||
function f;
|
||||
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
|
||||
// This triggers a syntax error under very special conditions (very weird indeed).
|
||||
explicit
|
||||
#endif
|
||||
func_handle(function &&f_) noexcept
|
||||
: f(std::move(f_)) {
|
||||
}
|
||||
func_handle(const func_handle &f_) { operator=(f_); }
|
||||
func_handle &operator=(const func_handle &f_) {
|
||||
gil_scoped_acquire acq;
|
||||
f = f_.f;
|
||||
return *this;
|
||||
}
|
||||
~func_handle() {
|
||||
gil_scoped_acquire acq;
|
||||
function kill_f(std::move(f));
|
||||
}
|
||||
};
|
||||
|
||||
// to emulate 'move initialization capture' in C++11
|
||||
struct func_wrapper {
|
||||
func_handle hfunc;
|
||||
explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
|
||||
Return operator()(Args... args) const {
|
||||
gil_scoped_acquire acq;
|
||||
// casts the returned object as a rvalue to the return type
|
||||
return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
|
||||
}
|
||||
};
|
||||
|
||||
value = func_wrapper(func_handle(std::move(func)));
|
||||
value = type_caster_std_function_specializations::func_wrapper<Return, Args...>(
|
||||
type_caster_std_function_specializations::func_handle(std::move(func)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,10 @@
|
||||
#include <cassert>
|
||||
#include <mutex>
|
||||
|
||||
#ifdef Py_GIL_DISABLED
|
||||
# include <atomic>
|
||||
#endif
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
|
||||
// Use the `gil_safe_call_once_and_store` class below instead of the naive
|
||||
@ -82,7 +86,12 @@ public:
|
||||
private:
|
||||
alignas(T) char storage_[sizeof(T)] = {};
|
||||
std::once_flag once_flag_ = {};
|
||||
bool is_initialized_ = false;
|
||||
#ifdef Py_GIL_DISABLED
|
||||
std::atomic_bool
|
||||
#else
|
||||
bool
|
||||
#endif
|
||||
is_initialized_{false};
|
||||
// The `is_initialized_`-`storage_` pair is very similar to `std::optional`,
|
||||
// but the latter does not have the triviality properties of former,
|
||||
// therefore `std::optional` is not a viable alternative here.
|
||||
|
@ -901,7 +901,11 @@ public:
|
||||
|
||||
template <typename T>
|
||||
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
|
||||
: array(pybind11::dtype::of<T>(), std::move(shape), std::move(strides), ptr, base) {}
|
||||
: array(pybind11::dtype::of<T>(),
|
||||
std::move(shape),
|
||||
std::move(strides),
|
||||
reinterpret_cast<const void *>(ptr),
|
||||
base) {}
|
||||
|
||||
template <typename T>
|
||||
array(ShapeContainer shape, const T *ptr, handle base = handle())
|
||||
@ -1986,7 +1990,7 @@ private:
|
||||
// Pointers to values the function was called with; the vectorized ones set here will start
|
||||
// out as array_t<T> pointers, but they will be changed them to T pointers before we make
|
||||
// call the wrapped function. Non-vectorized pointers are left as-is.
|
||||
std::array<void *, N> params{{&args...}};
|
||||
std::array<void *, N> params{{reinterpret_cast<void *>(&args)...}};
|
||||
|
||||
// The array of `buffer_info`s of vectorized arguments:
|
||||
std::array<buffer_info, NVectorized> buffers{
|
||||
|
@ -33,6 +33,13 @@
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
|
||||
#ifdef PYPY_VERSION
|
||||
# define PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(...) (__VA_ARGS__)
|
||||
#else
|
||||
# define PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(...) \
|
||||
(reinterpret_cast<void *>(__VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
||||
template <typename T>
|
||||
struct path_caster {
|
||||
@ -72,7 +79,8 @@ public:
|
||||
}
|
||||
PyObject *native = nullptr;
|
||||
if constexpr (std::is_same_v<typename T::value_type, char>) {
|
||||
if (PyUnicode_FSConverter(buf, &native) != 0) {
|
||||
if (PyUnicode_FSConverter(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native))
|
||||
!= 0) {
|
||||
if (auto *c_str = PyBytes_AsString(native)) {
|
||||
// AsString returns a pointer to the internal buffer, which
|
||||
// must not be free'd.
|
||||
@ -80,7 +88,8 @@ public:
|
||||
}
|
||||
}
|
||||
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
|
||||
if (PyUnicode_FSDecoder(buf, &native) != 0) {
|
||||
if (PyUnicode_FSDecoder(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native))
|
||||
!= 0) {
|
||||
if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
|
||||
// AsWideCharString returns a new string that must be free'd.
|
||||
value = c_str; // Copies the string.
|
||||
|
@ -180,7 +180,7 @@ void vector_modifiers(
|
||||
v.end());
|
||||
try {
|
||||
v.shrink_to_fit();
|
||||
} catch (const std::exception &) {
|
||||
} catch (const std::exception &) { // NOLINT(bugprone-empty-catch)
|
||||
// Do nothing
|
||||
}
|
||||
throw;
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "cast.h"
|
||||
#include "pytypes.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
PYBIND11_NAMESPACE_BEGIN(typing)
|
||||
|
||||
@ -98,7 +100,10 @@ class Never : public none {
|
||||
using none::none;
|
||||
};
|
||||
|
||||
#if defined(__cpp_nontype_template_parameter_class)
|
||||
#if defined(__cpp_nontype_template_parameter_class) \
|
||||
&& (/* See #5201 */ !defined(__GNUC__) \
|
||||
|| (__GNUC__ > 10 || (__GNUC__ == 10 && __GNUC_MINOR__ >= 3)))
|
||||
# define PYBIND11_TYPING_H_HAS_STRING_LITERAL
|
||||
template <size_t N>
|
||||
struct StringLiteral {
|
||||
constexpr StringLiteral(const char (&str)[N]) { std::copy_n(str, N, name); }
|
||||
@ -222,7 +227,7 @@ struct handle_type_name<typing::Never> {
|
||||
static constexpr auto name = const_name("Never");
|
||||
};
|
||||
|
||||
#if defined(__cpp_nontype_template_parameter_class)
|
||||
#if defined(PYBIND11_TYPING_H_HAS_STRING_LITERAL)
|
||||
template <typing::StringLiteral... Literals>
|
||||
struct handle_type_name<typing::Literal<Literals...>> {
|
||||
static constexpr auto name = const_name("Literal[")
|
||||
|
@ -2,12 +2,35 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
import sysconfig
|
||||
|
||||
from ._version import __version__
|
||||
from .commands import get_cmake_dir, get_include, get_pkgconfig_dir
|
||||
|
||||
# This is the conditional used for os.path being posixpath
|
||||
if "posix" in sys.builtin_module_names:
|
||||
from shlex import quote
|
||||
elif "nt" in sys.builtin_module_names:
|
||||
# See https://github.com/mesonbuild/meson/blob/db22551ed9d2dd7889abea01cc1c7bba02bf1c75/mesonbuild/utils/universal.py#L1092-L1121
|
||||
# and the original documents:
|
||||
# https://docs.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments and
|
||||
# https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
|
||||
UNSAFE = re.compile("[ \t\n\r]")
|
||||
|
||||
def quote(s: str) -> str:
|
||||
if s and not UNSAFE.search(s):
|
||||
return s
|
||||
|
||||
# Paths cannot contain a '"' on Windows, so we don't need to worry
|
||||
# about nuanced counting here.
|
||||
return f'"{s}\\"' if s.endswith("\\") else f'"{s}"'
|
||||
else:
|
||||
|
||||
def quote(s: str) -> str:
|
||||
return s
|
||||
|
||||
|
||||
def print_includes() -> None:
|
||||
dirs = [
|
||||
@ -22,7 +45,7 @@ def print_includes() -> None:
|
||||
if d and d not in unique_dirs:
|
||||
unique_dirs.append(d)
|
||||
|
||||
print(" ".join("-I" + d for d in unique_dirs))
|
||||
print(" ".join(quote(f"-I{d}") for d in unique_dirs))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
@ -54,9 +77,9 @@ def main() -> None:
|
||||
if args.includes:
|
||||
print_includes()
|
||||
if args.cmakedir:
|
||||
print(get_cmake_dir())
|
||||
print(quote(get_cmake_dir()))
|
||||
if args.pkgconfigdir:
|
||||
print(get_pkgconfig_dir())
|
||||
print(quote(get_pkgconfig_dir()))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -8,5 +8,5 @@ def _to_int(s: str) -> int | str:
|
||||
return s
|
||||
|
||||
|
||||
__version__ = "2.13.1"
|
||||
__version__ = "2.13.4"
|
||||
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
||||
|
@ -88,7 +88,12 @@ set(PYBIND11_TEST_FILTER
|
||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
# We're being loaded directly, i.e. not via add_subdirectory, so make this
|
||||
# work as its own project and load the pybind11Config to get the tools we need
|
||||
find_package(pybind11 REQUIRED CONFIG)
|
||||
|
||||
if(SKBUILD)
|
||||
add_subdirectory(.. pybind11_src)
|
||||
else()
|
||||
find_package(pybind11 REQUIRED CONFIG)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||
@ -153,6 +158,7 @@ set(PYBIND11_TEST_FILES
|
||||
test_tagbased_polymorphic
|
||||
test_thread
|
||||
test_type_caster_pyobject_ptr
|
||||
test_type_caster_std_function_specializations
|
||||
test_union
|
||||
test_unnamed_namespace_a
|
||||
test_unnamed_namespace_b
|
||||
@ -489,6 +495,9 @@ foreach(target ${test_targets})
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
if(SKBUILD)
|
||||
install(TARGETS ${target} LIBRARY DESTINATION .)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Provide nice organisation in IDEs
|
||||
|
@ -190,7 +190,7 @@ public:
|
||||
t1 = &p.first;
|
||||
}
|
||||
}
|
||||
} catch (const std::out_of_range &) {
|
||||
} catch (const std::out_of_range &) { // NOLINT(bugprone-empty-catch)
|
||||
}
|
||||
if (!t1) {
|
||||
throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
|
||||
|
@ -58,6 +58,7 @@ detail_headers = {
|
||||
"include/pybind11/detail/internals.h",
|
||||
"include/pybind11/detail/type_caster_base.h",
|
||||
"include/pybind11/detail/typeid.h",
|
||||
"include/pybind11/detail/value_and_holder.h",
|
||||
}
|
||||
|
||||
eigen_headers = {
|
||||
|
21
tests/pyproject.toml
Normal file
21
tests/pyproject.toml
Normal file
@ -0,0 +1,21 @@
|
||||
# Warning: this is currently used for pyodide, and is not a general out-of-tree
|
||||
# builder for the tests (yet). Specifically, wheels can't be built from SDists.
|
||||
|
||||
[build-system]
|
||||
requires = ["scikit-build-core"]
|
||||
build-backend = "scikit_build_core.build"
|
||||
|
||||
[project]
|
||||
name = "pybind11_tests"
|
||||
version = "0.0.1"
|
||||
dependencies = ["pytest", "pytest-timeout", "numpy", "scipy"]
|
||||
|
||||
[tool.scikit-build]
|
||||
# Hide a warning while we also support CMake < 3.15
|
||||
cmake.version = ">=3.15"
|
||||
|
||||
[tool.scikit-build.cmake.define]
|
||||
PYBIND11_FINDPYTHON = true
|
||||
|
||||
[tool.cibuildwheel]
|
||||
test-command = "pytest -o timeout=0 -p no:cacheprovider {project}/tests/test_*.py"
|
@ -1,10 +1,15 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
asyncio = pytest.importorskip("asyncio")
|
||||
m = pytest.importorskip("pybind11_tests.async_module")
|
||||
|
||||
if sys.platform.startswith("emscripten"):
|
||||
pytest.skip("Can't run a new event_loop in pyodide", allow_module_level=True)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def event_loop():
|
||||
|
@ -368,6 +368,8 @@ def test_tuple(doc):
|
||||
"""
|
||||
)
|
||||
|
||||
assert doc(m.empty_tuple) == """empty_tuple() -> tuple[()]"""
|
||||
|
||||
assert m.rvalue_pair() == ("rvalue", "rvalue")
|
||||
assert m.lvalue_pair() == ("lvalue", "lvalue")
|
||||
assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")
|
||||
|
@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import time
|
||||
from threading import Thread
|
||||
|
||||
@ -153,6 +154,7 @@ def test_python_builtins():
|
||||
assert m.test_sum_builtin(sum, []) == 0
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
def test_async_callbacks():
|
||||
# serves as state for async callback
|
||||
class Item:
|
||||
@ -176,6 +178,7 @@ def test_async_callbacks():
|
||||
assert sum(res) == sum(x + 3 for x in work)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
def test_async_async_callbacks():
|
||||
t = Thread(target=test_async_callbacks)
|
||||
t.start()
|
||||
|
@ -147,33 +147,39 @@ void init_tensor_module(pybind11::module &m) {
|
||||
|
||||
m.def(
|
||||
"take_fixed_tensor",
|
||||
|
||||
[]() {
|
||||
Eigen::aligned_allocator<
|
||||
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>>
|
||||
allocator;
|
||||
return new (allocator.allocate(1))
|
||||
static auto *obj = new (allocator.allocate(1))
|
||||
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>(
|
||||
get_fixed_tensor<Options>());
|
||||
return obj; // take_ownership will fail.
|
||||
},
|
||||
py::return_value_policy::take_ownership);
|
||||
|
||||
m.def(
|
||||
"take_tensor",
|
||||
[]() { return new Eigen::Tensor<double, 3, Options>(get_tensor<Options>()); },
|
||||
[]() {
|
||||
static auto *obj = new Eigen::Tensor<double, 3, Options>(get_tensor<Options>());
|
||||
return obj; // take_ownership will fail.
|
||||
},
|
||||
py::return_value_policy::take_ownership);
|
||||
|
||||
m.def(
|
||||
"take_const_tensor",
|
||||
[]() -> const Eigen::Tensor<double, 3, Options> * {
|
||||
return new Eigen::Tensor<double, 3, Options>(get_tensor<Options>());
|
||||
static auto *obj = new Eigen::Tensor<double, 3, Options>(get_tensor<Options>());
|
||||
return obj; // take_ownership will fail.
|
||||
},
|
||||
py::return_value_policy::take_ownership);
|
||||
|
||||
m.def(
|
||||
"take_view_tensor",
|
||||
[]() -> const Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> * {
|
||||
return new Eigen::TensorMap<Eigen::Tensor<double, 3, Options>>(get_tensor<Options>());
|
||||
static auto *obj
|
||||
= new Eigen::TensorMap<Eigen::Tensor<double, 3, Options>>(get_tensor<Options>());
|
||||
return obj; // take_ownership will fail.
|
||||
},
|
||||
py::return_value_policy::take_ownership);
|
||||
|
||||
|
@ -75,7 +75,7 @@ def test_cross_module_exceptions(msg):
|
||||
|
||||
# TODO: FIXME
|
||||
@pytest.mark.xfail(
|
||||
"env.MACOS and (env.PYPY or pybind11_tests.compiler_info.startswith('Homebrew Clang'))",
|
||||
"env.MACOS and (env.PYPY or pybind11_tests.compiler_info.startswith('Homebrew Clang')) or sys.platform.startswith('emscripten')",
|
||||
raises=RuntimeError,
|
||||
reason="See Issue #2847, PR #2999, PR #4324",
|
||||
)
|
||||
|
@ -71,24 +71,28 @@ def test_cross_module_gil_inner_pybind11_acquired():
|
||||
m.test_cross_module_gil_inner_pybind11_acquired()
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
def test_cross_module_gil_nested_custom_released():
|
||||
"""Makes sure that the GIL can be nested acquired/released by another module
|
||||
from a GIL-released state using custom locking logic."""
|
||||
m.test_cross_module_gil_nested_custom_released()
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
def test_cross_module_gil_nested_custom_acquired():
|
||||
"""Makes sure that the GIL can be nested acquired/acquired by another module
|
||||
from a GIL-acquired state using custom locking logic."""
|
||||
m.test_cross_module_gil_nested_custom_acquired()
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
def test_cross_module_gil_nested_pybind11_released():
|
||||
"""Makes sure that the GIL can be nested acquired/released by another module
|
||||
from a GIL-released state using pybind11 locking logic."""
|
||||
m.test_cross_module_gil_nested_pybind11_released()
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
def test_cross_module_gil_nested_pybind11_acquired():
|
||||
"""Makes sure that the GIL can be nested acquired/acquired by another module
|
||||
from a GIL-acquired state using pybind11 locking logic."""
|
||||
@ -103,6 +107,7 @@ def test_nested_acquire():
|
||||
assert m.test_nested_acquire(0xAB) == "171"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
def test_multi_acquire_release_cross_module():
|
||||
for bits in range(16 * 8):
|
||||
internals_ids = m.test_multi_acquire_release_cross_module(bits)
|
||||
@ -204,7 +209,7 @@ def _run_in_threads(test_fn, num_threads, parallel):
|
||||
thread.join()
|
||||
|
||||
|
||||
# TODO: FIXME, sometimes returns -11 (segfault) instead of 0 on macOS Python 3.9
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
@pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK)
|
||||
def test_run_in_process_one_thread(test_fn):
|
||||
"""Makes sure there is no GIL deadlock when running in a thread.
|
||||
@ -214,7 +219,7 @@ def test_run_in_process_one_thread(test_fn):
|
||||
assert _run_in_process(_run_in_threads, test_fn, num_threads=1, parallel=False) == 0
|
||||
|
||||
|
||||
# TODO: FIXME on macOS Python 3.9
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
@pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK)
|
||||
def test_run_in_process_multiple_threads_parallel(test_fn):
|
||||
"""Makes sure there is no GIL deadlock when running in a thread multiple times in parallel.
|
||||
@ -224,7 +229,7 @@ def test_run_in_process_multiple_threads_parallel(test_fn):
|
||||
assert _run_in_process(_run_in_threads, test_fn, num_threads=8, parallel=True) == 0
|
||||
|
||||
|
||||
# TODO: FIXME on macOS Python 3.9
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
@pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK)
|
||||
def test_run_in_process_multiple_threads_sequential(test_fn):
|
||||
"""Makes sure there is no GIL deadlock when running in a thread multiple times sequentially.
|
||||
@ -234,7 +239,7 @@ def test_run_in_process_multiple_threads_sequential(test_fn):
|
||||
assert _run_in_process(_run_in_threads, test_fn, num_threads=8, parallel=False) == 0
|
||||
|
||||
|
||||
# TODO: FIXME on macOS Python 3.9
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
@pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK)
|
||||
def test_run_in_process_direct(test_fn):
|
||||
"""Makes sure there is no GIL deadlock when using processes.
|
||||
|
@ -1,8 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from contextlib import redirect_stderr, redirect_stdout
|
||||
from io import StringIO
|
||||
|
||||
import pytest
|
||||
|
||||
from pybind11_tests import iostream as m
|
||||
|
||||
|
||||
@ -270,6 +273,7 @@ def test_redirect_both(capfd):
|
||||
assert stream2.getvalue() == msg2
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
def test_threading():
|
||||
with m.ostream_redirect(stdout=True, stderr=False):
|
||||
# start some threads
|
||||
|
@ -90,32 +90,32 @@ TEST_SUBMODULE(modules, m) {
|
||||
try {
|
||||
py::class_<Dupe1>(dm, "Dupe1");
|
||||
failures.append("Dupe1 class");
|
||||
} catch (std::runtime_error &) {
|
||||
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
|
||||
}
|
||||
try {
|
||||
dm.def("Dupe1", []() { return Dupe1(); });
|
||||
failures.append("Dupe1 function");
|
||||
} catch (std::runtime_error &) {
|
||||
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
|
||||
}
|
||||
try {
|
||||
py::class_<Dupe3>(dm, "dupe1_factory");
|
||||
failures.append("dupe1_factory");
|
||||
} catch (std::runtime_error &) {
|
||||
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
|
||||
}
|
||||
try {
|
||||
py::exception<Dupe3>(dm, "Dupe2");
|
||||
failures.append("Dupe2");
|
||||
} catch (std::runtime_error &) {
|
||||
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
|
||||
}
|
||||
try {
|
||||
dm.def("DupeException", []() { return 30; });
|
||||
failures.append("DupeException1");
|
||||
} catch (std::runtime_error &) {
|
||||
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
|
||||
}
|
||||
try {
|
||||
py::class_<DupeException>(dm, "DupeException");
|
||||
failures.append("DupeException2");
|
||||
} catch (std::runtime_error &) {
|
||||
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
|
||||
}
|
||||
|
||||
return failures;
|
||||
|
@ -266,6 +266,8 @@ py::array_t<int32_t, 0> test_array_ctors(int i) {
|
||||
return fill(arr_t(buf_ndim1_null));
|
||||
case 44:
|
||||
return fill(py::array(buf_ndim1_null));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return arr_t();
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ TEST_SUBMODULE(opaque_types, m) {
|
||||
|
||||
m.def("return_unique_ptr", []() -> std::unique_ptr<StringList> {
|
||||
auto *result = new StringList();
|
||||
result->push_back("some value");
|
||||
result->emplace_back("some value");
|
||||
return std::unique_ptr<StringList>(result);
|
||||
});
|
||||
|
||||
|
@ -109,7 +109,7 @@ void m_defs(py::module_ &m) {
|
||||
|
||||
} // namespace handle_from_move_only_type_with_operator_PyObject
|
||||
|
||||
#if defined(__cpp_nontype_template_parameter_class)
|
||||
#if defined(PYBIND11_TYPING_H_HAS_STRING_LITERAL)
|
||||
namespace literals {
|
||||
enum Color { RED = 0, BLUE = 1 };
|
||||
|
||||
@ -905,7 +905,7 @@ TEST_SUBMODULE(pytypes, m) {
|
||||
m.def("annotate_optional_to_object",
|
||||
[](py::typing::Optional<int> &o) -> py::object { return o; });
|
||||
|
||||
#if defined(__cpp_nontype_template_parameter_class)
|
||||
#if defined(PYBIND11_TYPING_H_HAS_STRING_LITERAL)
|
||||
py::enum_<literals::Color>(m, "Color")
|
||||
.value("RED", literals::Color::RED)
|
||||
.value("BLUE", literals::Color::BLUE);
|
||||
@ -919,8 +919,8 @@ TEST_SUBMODULE(pytypes, m) {
|
||||
m.def("annotate_listT_to_T",
|
||||
[](const py::typing::List<typevar::TypeVarT> &l) -> typevar::TypeVarT { return l[0]; });
|
||||
m.def("annotate_object_to_T", [](const py::object &o) -> typevar::TypeVarT { return o; });
|
||||
m.attr("if_defined__cpp_nontype_template_parameter_class") = true;
|
||||
m.attr("defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL") = true;
|
||||
#else
|
||||
m.attr("if_defined__cpp_nontype_template_parameter_class") = false;
|
||||
m.attr("defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL") = false;
|
||||
#endif
|
||||
}
|
||||
|
@ -1025,7 +1025,7 @@ def test_optional_object_annotations(doc):
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not m.if_defined__cpp_nontype_template_parameter_class,
|
||||
not m.defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL,
|
||||
reason="C++20 feature not available.",
|
||||
)
|
||||
def test_literal(doc):
|
||||
@ -1036,7 +1036,7 @@ def test_literal(doc):
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not m.if_defined__cpp_nontype_template_parameter_class,
|
||||
not m.defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL,
|
||||
reason="C++20 feature not available.",
|
||||
)
|
||||
def test_typevar(doc):
|
||||
|
@ -74,6 +74,7 @@ std::vector<std::unique_ptr<Animal>> create_zoo() {
|
||||
// simulate some new type of Dog that the Python bindings
|
||||
// haven't been updated for; it should still be considered
|
||||
// a Dog, not just an Animal.
|
||||
// NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
|
||||
ret.emplace_back(new Dog("Ginger", Dog::Kind(150)));
|
||||
|
||||
ret.emplace_back(new Chihuahua("Hertzl"));
|
||||
|
@ -1,7 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import threading
|
||||
|
||||
import pytest
|
||||
|
||||
from pybind11_tests import thread as m
|
||||
|
||||
|
||||
@ -24,6 +27,7 @@ class Thread(threading.Thread):
|
||||
raise self.e
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
def test_implicit_conversion():
|
||||
a = Thread(m.test)
|
||||
b = Thread(m.test)
|
||||
@ -34,6 +38,7 @@ def test_implicit_conversion():
|
||||
x.join()
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
def test_implicit_conversion_no_gil():
|
||||
a = Thread(m.test_no_gil)
|
||||
b = Thread(m.test_no_gil)
|
||||
|
46
tests/test_type_caster_std_function_specializations.cpp
Normal file
46
tests/test_type_caster_std_function_specializations.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include <pybind11/functional.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
#include "pybind11_tests.h"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
namespace {
|
||||
|
||||
struct SpecialReturn {
|
||||
int value = 99;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace pybind11 {
|
||||
namespace detail {
|
||||
namespace type_caster_std_function_specializations {
|
||||
|
||||
template <typename... Args>
|
||||
struct func_wrapper<SpecialReturn, Args...> : func_wrapper_base {
|
||||
using func_wrapper_base::func_wrapper_base;
|
||||
SpecialReturn operator()(Args... args) const {
|
||||
gil_scoped_acquire acq;
|
||||
SpecialReturn result;
|
||||
try {
|
||||
result = hfunc.f(std::forward<Args>(args)...).template cast<SpecialReturn>();
|
||||
} catch (error_already_set &) {
|
||||
result.value += 1;
|
||||
}
|
||||
result.value += 100;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace type_caster_std_function_specializations
|
||||
} // namespace detail
|
||||
} // namespace pybind11
|
||||
|
||||
TEST_SUBMODULE(type_caster_std_function_specializations, m) {
|
||||
py::class_<SpecialReturn>(m, "SpecialReturn")
|
||||
.def(py::init<>())
|
||||
.def_readwrite("value", &SpecialReturn::value);
|
||||
m.def("call_callback_with_special_return",
|
||||
[](const std::function<SpecialReturn()> &func) { return func(); });
|
||||
}
|
15
tests/test_type_caster_std_function_specializations.py
Normal file
15
tests/test_type_caster_std_function_specializations.py
Normal file
@ -0,0 +1,15 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pybind11_tests import type_caster_std_function_specializations as m
|
||||
|
||||
|
||||
def test_callback_with_special_return():
|
||||
def return_special():
|
||||
return m.SpecialReturn()
|
||||
|
||||
def raise_exception():
|
||||
raise ValueError("called raise_exception.")
|
||||
|
||||
assert return_special().value == 99
|
||||
assert m.call_callback_with_special_return(return_special).value == 199
|
||||
assert m.call_callback_with_special_return(raise_exception).value == 200
|
@ -1,5 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import env # noqa: F401
|
||||
@ -435,6 +437,7 @@ def test_inherited_virtuals():
|
||||
assert obj.say_everything() == "BT -7"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||
def test_issue_1454():
|
||||
# Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
|
||||
m.test_gil()
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
Adds the following targets::
|
||||
|
||||
pybind11::pybind11 - link to headers and pybind11
|
||||
pybind11::pybind11 - link to Python headers and pybind11::headers
|
||||
pybind11::module - Adds module links
|
||||
pybind11::embed - Adds embed links
|
||||
pybind11::lto - Link time optimizations (only if CMAKE_INTERPROCEDURAL_OPTIMIZATION is not set)
|
||||
@ -75,6 +75,32 @@ set_property(
|
||||
APPEND
|
||||
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11)
|
||||
|
||||
# -------------- emscripten requires exceptions enabled -------------
|
||||
# _pybind11_no_exceptions is a private mechanism to disable this addition.
|
||||
# Please open an issue if you need to use it; it will be removed if no one
|
||||
# needs it.
|
||||
if(CMAKE_SYSTEM_NAME MATCHES Emscripten AND NOT _pybind11_no_exceptions)
|
||||
if(CMAKE_VERSION VERSION_LESS 3.13)
|
||||
message(WARNING "CMake 3.13+ is required to build for Emscripten. Some flags will be missing")
|
||||
else()
|
||||
if(is_config)
|
||||
set(_tmp_config_target pybind11::pybind11_headers)
|
||||
else()
|
||||
set(_tmp_config_target pybind11_headers)
|
||||
endif()
|
||||
|
||||
set_property(
|
||||
TARGET ${_tmp_config_target}
|
||||
APPEND
|
||||
PROPERTY INTERFACE_LINK_OPTIONS -fexceptions)
|
||||
set_property(
|
||||
TARGET ${_tmp_config_target}
|
||||
APPEND
|
||||
PROPERTY INTERFACE_COMPILE_OPTIONS -fexceptions)
|
||||
unset(_tmp_config_target)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --------------------------- link helper ---------------------------
|
||||
|
||||
add_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global})
|
||||
@ -329,13 +355,13 @@ function(_pybind11_generate_lto target prefer_thin_lto)
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le" OR CMAKE_SYSTEM_PROCESSOR MATCHES "mips64")
|
||||
# Do nothing
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES emscripten)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES Emscripten)
|
||||
# This compile is very costly when cross-compiling, so set this without checking
|
||||
set(PYBIND11_LTO_CXX_FLAGS "-flto${thin}${cxx_append}")
|
||||
set(PYBIND11_LTO_LINKER_FLAGS "-flto${thin}${linker_append}")
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
_pybind11_return_if_cxx_and_linker_flags_work(
|
||||
HAS_FLTO_THIN "-flto${thin}${cxx_append}" "-flto=${thin}${linker_append}"
|
||||
HAS_FLTO_THIN "-flto${thin}${cxx_append}" "-flto${thin}${linker_append}"
|
||||
PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)
|
||||
endif()
|
||||
if(NOT HAS_FLTO_THIN)
|
||||
|
@ -84,7 +84,7 @@ you can either use the basic targets, or use the FindPython tools:
|
||||
|
||||
# Python method:
|
||||
Python_add_library(MyModule2 src2.cpp)
|
||||
target_link_libraries(MyModule2 pybind11::headers)
|
||||
target_link_libraries(MyModule2 PUBLIC pybind11::headers)
|
||||
set_target_properties(MyModule2 PROPERTIES
|
||||
INTERPROCEDURAL_OPTIMIZATION ON
|
||||
CXX_VISIBILITY_PRESET ON
|
||||
|
Loading…
Reference in New Issue
Block a user