Merge branch 'master' into sh_merge_master

This commit is contained in:
Ralf W. Grosse-Kunstleve 2021-09-20 05:57:17 -07:00
commit 03d409b4a0
10 changed files with 337 additions and 75 deletions

View File

@ -145,6 +145,24 @@ jobs:
if: "!(runner.os == 'Windows' && (matrix.python == 3.8 || matrix.python == 3.9 || matrix.python == '3.10-dev'))" if: "!(runner.os == 'Windows' && (matrix.python == 3.8 || matrix.python == 3.9 || matrix.python == '3.10-dev'))"
run: cmake --build build2 --target cpptest run: cmake --build build2 --target cpptest
# Third build - C++17 mode with unstable ABI
- name: Configure (unstable ABI)
run: >
cmake -S . -B build3
-DPYBIND11_WERROR=ON
-DDOWNLOAD_CATCH=ON
-DDOWNLOAD_EIGEN=ON
-DCMAKE_CXX_STANDARD=17
-DPYBIND11_INTERNALS_VERSION=10000000
"-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp"
${{ matrix.args }}
- name: Build (unstable ABI)
run: cmake --build build3 -j 2
- name: Python tests (unstable ABI)
run: cmake --build build3 --target pytest
- name: Interface test - name: Interface test
run: cmake --build build2 --target test_cmake_build run: cmake --build build2 --target test_cmake_build

View File

@ -32,7 +32,7 @@ repos:
exclude: ^noxfile.py$ exclude: ^noxfile.py$
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: v2.25.0 rev: v2.26.0
hooks: hooks:
- id: pyupgrade - id: pyupgrade

View File

@ -89,6 +89,9 @@ endif()
option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT}) option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT})
option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT}) option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT})
option(PYBIND11_NOPYTHON "Disable search for Python" OFF) option(PYBIND11_NOPYTHON "Disable search for Python" OFF)
set(PYBIND11_INTERNALS_VERSION
""
CACHE STRING "Override the ABI version, may be used to enable the unstable ABI.")
cmake_dependent_option( cmake_dependent_option(
USE_PYTHON_INCLUDE_DIR USE_PYTHON_INCLUDE_DIR
@ -189,6 +192,10 @@ if(NOT TARGET pybind11_headers)
target_compile_features(pybind11_headers INTERFACE cxx_inheriting_constructors cxx_user_literals target_compile_features(pybind11_headers INTERFACE cxx_inheriting_constructors cxx_user_literals
cxx_right_angle_brackets) cxx_right_angle_brackets)
if(NOT "${PYBIND11_INTERNALS_VERSION}" STREQUAL "")
target_compile_definitions(
pybind11_headers INTERFACE "PYBIND11_INTERNALS_VERSION=${PYBIND11_INTERNALS_VERSION}")
endif()
else() else()
# It is invalid to install a target twice, too. # It is invalid to install a target twice, too.
set(PYBIND11_INSTALL OFF) set(PYBIND11_INSTALL OFF)

View File

@ -171,6 +171,31 @@ template parameter, and it ensures that non-conforming arguments are converted
into an array satisfying the specified requirements instead of trying the next into an array satisfying the specified requirements instead of trying the next
function overload. function overload.
There are several methods on arrays; the methods listed below under references
work, as well as the following functions based on the NumPy API:
- ``.dtype()`` returns the type of the contained values.
- ``.strides()`` returns a pointer to the strides of the array (optionally pass
an integer axis to get a number).
- ``.flags()`` returns the flag settings. ``.writable()`` and ``.owndata()``
are directly available.
- ``.offset_at()`` returns the offset (optionally pass indices).
- ``.squeeze()`` returns a view with length-1 axes removed.
- ``.view(dtype)`` returns a view of the array with a different dtype.
- ``.reshape({i, j, ...})`` returns a view of the array with a different shape.
``.resize({...})`` is also available.
- ``.index_at(i, j, ...)`` gets the count from the beginning to a given index.
There are also several methods for getting references (described below).
Structured types Structured types
================ ================
@ -345,21 +370,21 @@ The returned proxy object supports some of the same methods as ``py::array`` so
that it can be used as a drop-in replacement for some existing, index-checked that it can be used as a drop-in replacement for some existing, index-checked
uses of ``py::array``: uses of ``py::array``:
- ``r.ndim()`` returns the number of dimensions - ``.ndim()`` returns the number of dimensions
- ``r.data(1, 2, ...)`` and ``r.mutable_data(1, 2, ...)``` returns a pointer to - ``.data(1, 2, ...)`` and ``r.mutable_data(1, 2, ...)``` returns a pointer to
the ``const T`` or ``T`` data, respectively, at the given indices. The the ``const T`` or ``T`` data, respectively, at the given indices. The
latter is only available to proxies obtained via ``a.mutable_unchecked()``. latter is only available to proxies obtained via ``a.mutable_unchecked()``.
- ``itemsize()`` returns the size of an item in bytes, i.e. ``sizeof(T)``. - ``.itemsize()`` returns the size of an item in bytes, i.e. ``sizeof(T)``.
- ``ndim()`` returns the number of dimensions. - ``.ndim()`` returns the number of dimensions.
- ``shape(n)`` returns the size of dimension ``n`` - ``.shape(n)`` returns the size of dimension ``n``
- ``size()`` returns the total number of elements (i.e. the product of the shapes). - ``.size()`` returns the total number of elements (i.e. the product of the shapes).
- ``nbytes()`` returns the number of bytes used by the referenced elements - ``.nbytes()`` returns the number of bytes used by the referenced elements
(i.e. ``itemsize()`` times ``size()``). (i.e. ``itemsize()`` times ``size()``).
.. seealso:: .. seealso::

View File

@ -9,6 +9,11 @@ Starting with version 1.8.0, pybind11 releases use a `semantic versioning
v2.8.0 (WIP) v2.8.0 (WIP)
------------ ------------
New features:
* Added ``py::raise_from`` to enable chaining exceptions.
`#3215 <https://github.com/pybind/pybind11/pull/3215>`_
* Allow exception translators to be optionally registered local to a module * Allow exception translators to be optionally registered local to a module
instead of applying globally across all pybind11 modules. Use instead of applying globally across all pybind11 modules. Use
``register_local_exception_translator(ExceptionTranslator&& translator)`` ``register_local_exception_translator(ExceptionTranslator&& translator)``
@ -16,6 +21,115 @@ v2.8.0 (WIP)
translator)`` to keep your exception remapping code local to the module. translator)`` to keep your exception remapping code local to the module.
`#2650 <https://github.com/pybind/pybind11/pull/2650>`_ `#2650 <https://github.com/pybind/pybind11/pull/2650>`_
* Add ``make_simple_namespace`` function for instantiating Python
``SimpleNamespace`` objects.
`#2840 <https://github.com/pybind/pybind11/pull/2840>`_
* ``pybind11::scoped_interpreter`` and ``initialize_interpreter`` have new
arguments to allow ``sys.argv`` initialization.
`#2341 <https://github.com/pybind/pybind11/pull/2341>`_
* Allow Python builtins to be used as callbacks in CPython.
`#1413 <https://github.com/pybind/pybind11/pull/1413>`_
* Added ``view`` to view arrays with a different datatype.
`#987 <https://github.com/pybind/pybind11/pull/987>`_
* Implemented ``reshape`` on arrays.
`#984 <https://github.com/pybind/pybind11/pull/984>`_
Changes:
* Set ``__file__`` constant when running ``eval_file`` in an embedded interpreter.
`#3233 <https://github.com/pybind/pybind11/pull/3233>`_
* The pybind11 proxy types ``str``, ``bytes``, ``bytearray``, ``tuple``,
``list`` now consistently support passing ``ssize_t`` values for sizes and
indexes. Previously, only ``size_t`` was accepted in several interfaces.
`#3219 <https://github.com/pybind/pybind11/pull/3219>`_
Fixes:
* Bug fix: enum value's ``__int__`` returning non-int when underlying type is bool or of char type.
`#1334 <https://github.com/pybind/pybind11/pull/1334>`_
* Fixes bug in setting error state in Capsule's pointer methods.
`#3261 <https://github.com/pybind/pybind11/pull/3261>`_
* A long-standing memory leak in ``py::cpp_function::initialize`` was fixed.
`#3229 <https://github.com/pybind/pybind11/pull/3229>`_
* Fixes thread safety for some ``pybind11::type_caster`` which require lifetime extension, such as for ``std::string_view``.
`#3237 <https://github.com/pybind/pybind11/pull/3237>`_
* Restore compatibility with gcc 4.8.4 as distributed by ubuntu-trusty, linuxmint-17.
`#3270 <https://github.com/pybind/pybind11/pull/3270>`_
Build system improvements:
* Fix regression in CMake Python package config: improper use of absolute path.
`#3144 <https://github.com/pybind/pybind11/pull/3144>`_
* Specified UTF8-encoding in setup.py calls of open().
`#3137 <https://github.com/pybind/pybind11/pull/3137>`_
Backend and tidying up:
* Optimize NumPy array construction with additional moves.
`#3183 <https://github.com/pybind/pybind11/pull/3183>`_
* Conversion to ``std::string`` and ``std::string_view`` now avoids making an
extra copy of the data on Python >= 3.3.
`#3257 <https://github.com/pybind/pybind11/pull/3257>`_
* Remove const modifier from certain C++ methods on Python collections
(``list``, ``set``, ``dict``) such as (``clear()``, ``append()``,
``insert()``, etc...) and annotated them with ``py-non-const``.
* Enable readability ``clang-tidy-const-return`` and remove useless consts.
`#3254 <https://github.com/pybind/pybind11/pull/3254>`_
`#3194 <https://github.com/pybind/pybind11/pull/3194>`_
* The clang-tidy ``google-explicit-constructor`` option was enabled.
`#3250 <https://github.com/pybind/pybind11/pull/3250>`_
* Mark a pytype move constructor as noexcept (perf).
`#3236 <https://github.com/pybind/pybind11/pull/3236>`_
* Enable clang-tidy check to guard against inheritance slicing.
`#3210 <https://github.com/pybind/pybind11/pull/3210>`_
* Legacy warning suppression pragma were removed from eigen.h. On Unix
platforms, please use -isystem for Eigen include directories, to suppress
compiler warnings originating from Eigen headers. Note that CMake does this
by default. No adjustments are needed for Windows.
`#3198 <https://github.com/pybind/pybind11/pull/3198>`_
* Format pybind11 with isort consistent ordering of imports
`#3195 <https://github.com/pybind/pybind11/pull/3195>`_
* The warnings-suppression "pragma clamp" at the top/bottom of pybind11 was
removed, clearing the path to refactoring and IWYU cleanup.
`#3186 <https://github.com/pybind/pybind11/pull/3186>`_
* Enable most bugprone checks in clang-tidy and fix the found potential bugs
and poor coding styles.
`#3166 <https://github.com/pybind/pybind11/pull/3166>`_
* Add ``clang-tidy-readability`` rules to make boolean casts explicit improving
code readability. Also enabled other misc and readability clang-tidy checks.
`#3148 <https://github.com/pybind/pybind11/pull/3148>`_
* Move object in ``.pop()`` for list.
`#3116 <https://github.com/pybind/pybind11/pull/3116>`_
v2.7.1 (Aug 3, 2021) v2.7.1 (Aug 3, 2021)
--------------------- ---------------------

View File

@ -12,6 +12,24 @@
#include "../pytypes.h" #include "../pytypes.h"
#include "smart_holder_sfinae_hooks_only.h" #include "smart_holder_sfinae_hooks_only.h"
/// Tracks the `internals` and `type_info` ABI version independent of the main library version.
///
/// Some portions of the code use an ABI that is conditional depending on this
/// version number. That allows ABI-breaking changes to be "pre-implemented".
/// Once the default version number is incremented, the conditional logic that
/// no longer applies can be removed. Additionally, users that need not
/// maintain ABI compatibility can increase the version number in order to take
/// advantage of any functionality/efficiency improvements that depend on the
/// newer ABI.
///
/// WARNING: If you choose to manually increase the ABI version, note that
/// pybind11 may not be tested as thoroughly with a non-default ABI version, and
/// further ABI-incompatible changes may be made before the ABI is officially
/// changed to the new version.
#ifndef PYBIND11_INTERNALS_VERSION
# define PYBIND11_INTERNALS_VERSION 4
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
using ExceptionTranslator = void (*)(std::exception_ptr); using ExceptionTranslator = void (*)(std::exception_ptr);
@ -26,30 +44,58 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new // The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
// Thread Specific Storage (TSS) API. // Thread Specific Storage (TSS) API.
#if PY_VERSION_HEX >= 0x03070000 #if PY_VERSION_HEX >= 0x03070000
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr // Avoid unnecessary allocation of `Py_tss_t`, since we cannot use
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key)) // `Py_LIMITED_API` anyway.
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value)) # if PYBIND11_INTERNALS_VERSION > 4
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr) # define PYBIND11_TLS_KEY_REF Py_tss_t &
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key) # ifdef __GNUC__
#else // Clang on macOS warns due to `Py_tss_NEEDS_INIT` not specifying an initializer
// Usually an int but a long on Cygwin64 with Python 3.x // for every field.
# define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0 # define PYBIND11_TLS_KEY_INIT(var) \
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key)) _Pragma("GCC diagnostic push") /**/ \
# if PY_MAJOR_VERSION < 3 _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
# define PYBIND11_TLS_DELETE_VALUE(key) \ Py_tss_t var \
PyThread_delete_key_value(key) = Py_tss_NEEDS_INIT; \
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \ _Pragma("GCC diagnostic pop")
do { \ # else
PyThread_delete_key_value((key)); \ # define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
PyThread_set_key_value((key), (value)); \ # endif
} while (false) # define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0)
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key))
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set(&(key), (value))
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set(&(key), nullptr)
# define PYBIND11_TLS_FREE(key) PyThread_tss_delete(&(key))
# else # else
# define PYBIND11_TLS_DELETE_VALUE(key) \ # define PYBIND11_TLS_KEY_REF Py_tss_t *
PyThread_set_key_value((key), nullptr) # define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr;
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \ # define PYBIND11_TLS_KEY_CREATE(var) \
PyThread_set_key_value((key), (value)) (((var) = PyThread_tss_alloc()) != nullptr && (PyThread_tss_create((var)) == 0))
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
# endif # endif
# define PYBIND11_TLS_FREE(key) (void)key #else
// Usually an int but a long on Cygwin64 with Python 3.x
# define PYBIND11_TLS_KEY_REF decltype(PyThread_create_key())
# define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0;
# define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1)
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
# if PY_MAJOR_VERSION < 3 || defined(PYPY_VERSION)
// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set
// the value if it has already been set. Instead, it must first be deleted and
// then set again.
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_delete_key_value(key)
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
do { \
PyThread_delete_key_value((key)); \
PyThread_set_key_value((key), (value)); \
} while (false)
# else
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_set_key_value((key), nullptr)
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_set_key_value((key), (value))
# endif
# define PYBIND11_TLS_FREE(key) (void) key
#endif #endif
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly // Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
@ -107,22 +153,31 @@ struct internals {
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients; std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
std::forward_list<ExceptionTranslator> registered_exception_translators; std::forward_list<ExceptionTranslator> registered_exception_translators;
std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across extensions std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across extensions
#if PYBIND11_INTERNALS_VERSION == 4
std::vector<PyObject *> unused_loader_patient_stack_remove_at_v5; std::vector<PyObject *> unused_loader_patient_stack_remove_at_v5;
#endif
std::forward_list<std::string> static_strings; // Stores the std::strings backing detail::c_str() std::forward_list<std::string> static_strings; // Stores the std::strings backing detail::c_str()
PyTypeObject *static_property_type; PyTypeObject *static_property_type;
PyTypeObject *default_metaclass; PyTypeObject *default_metaclass;
PyObject *instance_base; PyObject *instance_base;
#if defined(WITH_THREAD) #if defined(WITH_THREAD)
PYBIND11_TLS_KEY_INIT(tstate); PYBIND11_TLS_KEY_INIT(tstate)
# if PYBIND11_INTERNALS_VERSION > 4
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
# endif // PYBIND11_INTERNALS_VERSION > 4
PyInterpreterState *istate = nullptr; PyInterpreterState *istate = nullptr;
~internals() { ~internals() {
# if PYBIND11_INTERNALS_VERSION > 4
PYBIND11_TLS_FREE(loader_life_support_tls_key);
# endif // PYBIND11_INTERNALS_VERSION > 4
// This destructor is called *after* Py_Finalize() in finalize_interpreter(). // This destructor is called *after* Py_Finalize() in finalize_interpreter().
// That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is called. // That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is
// PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does nothing. // called. PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does
// PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree. // nothing. PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree.
// PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX). Neither // PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX).
// of those have anything to do with CPython internals. // Neither of those have anything to do with CPython internals. PyMem_RawFree *requires*
// PyMem_RawFree *requires* that the `tstate` be allocated with the CPython allocator. // that the `tstate` be allocated with the CPython allocator.
PYBIND11_TLS_FREE(tstate); PYBIND11_TLS_FREE(tstate);
} }
#endif #endif
@ -154,9 +209,6 @@ struct type_info {
bool module_local : 1; bool module_local : 1;
}; };
/// Tracks the `internals` and `type_info` ABI version independent of the main library version
#define PYBIND11_INTERNALS_VERSION 4
/// On MSVC, debug and release builds are not ABI-compatible! /// On MSVC, debug and release builds are not ABI-compatible!
#if defined(_MSC_VER) && defined(_DEBUG) #if defined(_MSC_VER) && defined(_DEBUG)
# define PYBIND11_BUILD_TYPE "_debug" # define PYBIND11_BUILD_TYPE "_debug"
@ -302,21 +354,21 @@ PYBIND11_NOINLINE internals &get_internals() {
internals_ptr = new internals(); internals_ptr = new internals();
#if defined(WITH_THREAD) #if defined(WITH_THREAD)
#if PY_VERSION_HEX < 0x03090000 # if PY_VERSION_HEX < 0x03090000
PyEval_InitThreads(); PyEval_InitThreads();
#endif # endif
PyThreadState *tstate = PyThreadState_Get(); PyThreadState *tstate = PyThreadState_Get();
#if PY_VERSION_HEX >= 0x03070000 if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->tstate)) {
internals_ptr->tstate = PyThread_tss_alloc(); pybind11_fail("get_internals: could not successfully initialize the tstate TSS key!");
if (!internals_ptr->tstate || (PyThread_tss_create(internals_ptr->tstate) != 0)) }
pybind11_fail("get_internals: could not successfully initialize the tstate TSS key!"); PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate);
PyThread_tss_set(internals_ptr->tstate, tstate);
#else # if PYBIND11_INTERNALS_VERSION > 4
internals_ptr->tstate = PyThread_create_key(); if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) {
if (internals_ptr->tstate == -1) pybind11_fail("get_internals: could not successfully initialize the "
pybind11_fail("get_internals: could not successfully initialize the tstate TLS key!"); "loader_life_support TSS key!");
PyThread_set_key_value(internals_ptr->tstate, tstate); }
#endif # endif
internals_ptr->istate = tstate->interp; internals_ptr->istate = tstate->interp;
#endif #endif
builtins[id] = capsule(internals_pp); builtins[id] = capsule(internals_pp);
@ -328,7 +380,6 @@ PYBIND11_NOINLINE internals &get_internals() {
return **internals_pp; return **internals_pp;
} }
// the internals struct (above) is shared between all the modules. local_internals are only // the internals struct (above) is shared between all the modules. local_internals are only
// for a single module. Any changes made to internals may require an update to // for a single module. Any changes made to internals may require an update to
// PYBIND11_INTERNALS_VERSION, breaking backwards compatibility. local_internals is, by design, // PYBIND11_INTERNALS_VERSION, breaking backwards compatibility. local_internals is, by design,
@ -336,8 +387,41 @@ PYBIND11_NOINLINE internals &get_internals() {
// impact any other modules, because the only things accessing the local internals is the // impact any other modules, because the only things accessing the local internals is the
// module that contains them. // module that contains them.
struct local_internals { struct local_internals {
type_map<type_info *> registered_types_cpp; type_map<type_info *> registered_types_cpp;
std::forward_list<ExceptionTranslator> registered_exception_translators; std::forward_list<ExceptionTranslator> registered_exception_translators;
#if defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
// For ABI compatibility, we can't store the loader_life_support TLS key in
// the `internals` struct directly. Instead, we store it in `shared_data` and
// cache a copy in `local_internals`. If we allocated a separate TLS key for
// each instance of `local_internals`, we could end up allocating hundreds of
// TLS keys if hundreds of different pybind11 modules are loaded (which is a
// plausible number).
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
// Holds the shared TLS key for the loader_life_support stack.
struct shared_loader_life_support_data {
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
shared_loader_life_support_data() {
if (!PYBIND11_TLS_KEY_CREATE(loader_life_support_tls_key)) {
pybind11_fail("local_internals: could not successfully initialize the "
"loader_life_support TLS key!");
}
}
// We can't help but leak the TLS key, because Python never unloads extension modules.
};
local_internals() {
auto &internals = get_internals();
// Get or create the `loader_life_support_stack_key`.
auto &ptr = internals.shared_data["_life_support"];
if (!ptr) {
ptr = new shared_loader_life_support_data;
}
loader_life_support_tls_key
= static_cast<shared_loader_life_support_data *>(ptr)->loader_life_support_tls_key;
}
#endif // defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
}; };
/// Works like `get_internals`, but for things which are locally registered. /// Works like `get_internals`, but for things which are locally registered.

View File

@ -35,30 +35,43 @@ private:
loader_life_support* parent = nullptr; loader_life_support* parent = nullptr;
std::unordered_set<PyObject *> keep_alive; std::unordered_set<PyObject *> keep_alive;
static loader_life_support** get_stack_pp() {
#if defined(WITH_THREAD) #if defined(WITH_THREAD)
thread_local static loader_life_support* per_thread_stack = nullptr; // Store stack pointer in thread-local storage.
return &per_thread_stack; static PYBIND11_TLS_KEY_REF get_stack_tls_key() {
#else # if PYBIND11_INTERNALS_VERSION == 4
static loader_life_support* global_stack = nullptr; return get_local_internals().loader_life_support_tls_key;
return &global_stack; # else
#endif return get_internals().loader_life_support_tls_key;
# endif
} }
static loader_life_support *get_stack_top() {
return static_cast<loader_life_support *>(PYBIND11_TLS_GET_VALUE(get_stack_tls_key()));
}
static void set_stack_top(loader_life_support *value) {
PYBIND11_TLS_REPLACE_VALUE(get_stack_tls_key(), value);
}
#else
// Use single global variable for stack.
static loader_life_support **get_stack_pp() {
static loader_life_support *global_stack = nullptr;
return global_stack;
}
static loader_life_support *get_stack_top() { return *get_stack_pp(); }
static void set_stack_top(loader_life_support *value) { *get_stack_pp() = value; }
#endif
public: public:
/// A new patient frame is created when a function is entered /// A new patient frame is created when a function is entered
loader_life_support() { loader_life_support() {
loader_life_support** stack = get_stack_pp(); parent = get_stack_top();
parent = *stack; set_stack_top(this);
*stack = this;
} }
/// ... and destroyed after it returns /// ... and destroyed after it returns
~loader_life_support() { ~loader_life_support() {
loader_life_support** stack = get_stack_pp(); if (get_stack_top() != this)
if (*stack != this)
pybind11_fail("loader_life_support: internal error"); pybind11_fail("loader_life_support: internal error");
*stack = parent; set_stack_top(parent);
for (auto* item : keep_alive) for (auto* item : keep_alive)
Py_DECREF(item); Py_DECREF(item);
} }
@ -66,7 +79,7 @@ public:
/// This can only be used inside a pybind11-bound function, either by `argument_loader` /// This can only be used inside a pybind11-bound function, either by `argument_loader`
/// at argument preparation time or by `py::cast()` at execution time. /// at argument preparation time or by `py::cast()` at execution time.
PYBIND11_NOINLINE static void add_patient(handle h) { PYBIND11_NOINLINE static void add_patient(handle h) {
loader_life_support* frame = *get_stack_pp(); loader_life_support *frame = get_stack_top();
if (!frame) { if (!frame) {
// NOTE: It would be nice to include the stack frames here, as this indicates // NOTE: It would be nice to include the stack frames here, as this indicates
// use of pybind11::cast<> outside the normal call framework, finding such // use of pybind11::cast<> outside the normal call framework, finding such

View File

@ -50,7 +50,7 @@ PYBIND11_NAMESPACE_END(detail)
class gil_scoped_acquire { class gil_scoped_acquire {
public: public:
PYBIND11_NOINLINE gil_scoped_acquire() { PYBIND11_NOINLINE gil_scoped_acquire() {
auto const &internals = detail::get_internals(); auto &internals = detail::get_internals();
tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate); tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate);
if (!tstate) { if (!tstate) {
@ -132,7 +132,7 @@ public:
// `get_internals()` must be called here unconditionally in order to initialize // `get_internals()` must be called here unconditionally in order to initialize
// `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an // `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an
// initialization race could occur as multiple threads try `gil_scoped_acquire`. // initialization race could occur as multiple threads try `gil_scoped_acquire`.
const auto &internals = detail::get_internals(); auto &internals = detail::get_internals();
tstate = PyEval_SaveThread(); tstate = PyEval_SaveThread();
if (disassoc) { if (disassoc) {
auto key = internals.tstate; auto key = internals.tstate;

View File

@ -322,7 +322,7 @@ template <typename T> using remove_all_extents_t = typename array_info<T>::type;
template <typename T> using is_pod_struct = all_of< template <typename T> using is_pod_struct = all_of<
std::is_standard_layout<T>, // since we're accessing directly in memory we need a standard layout type std::is_standard_layout<T>, // since we're accessing directly in memory we need a standard layout type
#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150623 || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803) #if defined(__GLIBCXX__) && (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150426 || __GLIBCXX__ == 20150623 || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803)
// libstdc++ < 5 (including versions 4.8.5, 4.9.3 and 4.9.4 which were released after 5) // libstdc++ < 5 (including versions 4.8.5, 4.9.3 and 4.9.4 which were released after 5)
// don't implement is_trivially_copyable, so approximate it // don't implement is_trivially_copyable, so approximate it
std::is_trivially_destructible<T>, std::is_trivially_destructible<T>,

View File

@ -467,7 +467,8 @@ def test_issue2361():
assert m.issue2361_str_implicit_copy_none() == "None" assert m.issue2361_str_implicit_copy_none() == "None"
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
assert m.issue2361_dict_implicit_copy_none() assert m.issue2361_dict_implicit_copy_none()
assert "'NoneType' object is not iterable" in str(excinfo.value) assert "NoneType" in str(excinfo.value)
assert "iterable" in str(excinfo.value)
@pytest.mark.parametrize( @pytest.mark.parametrize(