From 723307283ed7dc03c901fba1da1127c7b16a4a0d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 30 Jul 2024 23:18:35 +0700 Subject: [PATCH 1/7] feat: remove Python 3.7 support (#5191) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * First pass updating misc files, informed by https://github.com/pybind/pybind11/pull/5177/commits * Remove jobs using silkeh/clang and gcc docker containers that come with Python 3.7 * Add silkeh/clang:17-bookworm * Add job using GCC 7 * Revert "Add job using GCC 7" This reverts commit 518515a761ac37dc2cf5d0980da82d0de39edc28. * Try running in ubuntu-18.04 container under ubuntu-latest (to get GCC 7) * Fix `-` vs `:` mixup. * This reverts commit b1c4304475b8ad129c12330c7ed7eb85d15ba14a. Revert "Try running in ubuntu:18.04 container under ubuntu-latest (to get GCC 7)" This reverts commit b203a294bb444fc6ae57a0100fa91dc91b8d3264. * `git grep 0x03080000` cleanup. * `git grep -I -E '3\.7'` cleanup. Removes two changes made under pybind/pybind11#3702 * Revert "`git grep -I -E '3\.7'` cleanup." This reverts commit bb5b9d187bffbfb61e2977d7eee46b766fa1cce9. * Remove comments that are evidently incorrect: ``` ... -- The CXX compiler identification is Clang 15.0.7 ... - Found Python: /usr/bin/python3.9 (found suitable version "3.9.2", minimum required is "3.7") found components: Interpreter Development.Module Development.Embed ... /__w/pybind11/pybind11/include/pybind11/gil.h:150:13: error: 'auto key' can be declared as 'auto *key' [readability-qualified-auto,-warnings-as-errors] auto key = internals.tstate; ^~~~~ auto * /__w/pybind11/pybind11/include/pybind11/gil.h:174:13: error: 'auto key' can be declared as 'auto *key' [readability-qualified-auto,-warnings-as-errors] auto key = detail::get_internals().tstate; ^~~~~ auto * ``` * .github/workflows/configure.yml: Change from Python 3.7 to 3.8 * Misc cleanup pass * Miscellaneous changes based on manual review of the `git grep` matches below: ``` git_grep_37_38.sh |& sort | uniq -c ``` With git_grep_37_38.sh: ``` set -x git grep 0x0307 git grep 0x0308 git grep PY_MINOR_VERSION git grep PYPY_VERSION git grep -I -E '3\.7' git grep -I -E '3\.8' git grep -I -E '\(3, 7' git grep -I -E '\(3, 8' git grep -I -E '3[^A-Za-z0-9.]+7' git grep -I -E '3[^A-Za-z0-9.]+8' ``` Output: ``` 1 .appveyor.yml: $env:CMAKE_INCLUDE_PATH = "eigen-3.3.7;$env:CMAKE_INCLUDE_PATH" 1 .appveyor.yml: 7z x eigen-3.3.7.zip -y > $null 1 .appveyor.yml: Start-FileDownload 'https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.zip' 1 CMakeLists.txt: # Bug in macOS CMake < 3.7 is unable to download catch 1 CMakeLists.txt: elseif(WINDOWS AND CMAKE_VERSION VERSION_LESS 3.8) 1 CMakeLists.txt: if(OSX AND CMAKE_VERSION VERSION_LESS 3.7) 1 CMakeLists.txt: message(WARNING "CMAKE 3.7+ needed on macOS to download catch, and newer HIGHLY recommended") 1 CMakeLists.txt: message(WARNING "CMAKE 3.8+ tested on Windows, previous versions untested") 1 CMakeLists.txt: # Only tested with 3.8+ in CI. 1 docs/advanced/functions.rst:Python 3.8 introduced a new positional-only argument syntax, using ``/`` in the 1 docs/changelog.rst:* Adapt pybind11 to a C API convention change in Python 3.8. `#1950 1 docs/changelog.rst:* Allow thread termination to be avoided during shutdown for CPython 3.7+ via 1 docs/changelog.rst: considered as conversion, consistent with Python 3.8+. 1 docs/changelog.rst: CPython 3.8 and 3.9 debug builds. 1 docs/changelog.rst:* Enum now has an ``__index__`` method on Python <3.8 too. 1 docs/changelog.rst: on Python 3.8. `#1780 `_. 1 docs/changelog.rst:* PyPy 3.10 support was added, PyPy 3.7 support was dropped. 2 docs/changelog.rst:* Support PyPy 7.3.7 and the PyPy3.8 beta. Test python-3.11 on PRs with the 1 docs/changelog.rst:* Use ``macos-13`` (Intel) for CI jobs for now (will drop Python 3.7 soon). 1 docs/changelog.rst:* Use new Python 3.7 Thread Specific Storage (TSS) implementation if available. 1 docs/compiling.rst: cmake -DPYBIND11_PYTHON_VERSION=3.8 .. 1 docs/compiling.rst: find_package(Python 3.8 COMPONENTS Interpreter Development REQUIRED) 1 docs/limitations.rst:- PyPy3 7.3.1 and 7.3.2 have issues with several tests on 32-bit Windows. 1 docs/requirements.txt:idna==3.7 \ 1 + git grep 0x0307 1 + git grep 0x0308 1 + git grep -I -E '\(3, 7' 1 + git grep -I -E '3\.7' 1 + git grep -I -E '\(3, 8' 1 + git grep -I -E '3\.8' 1 + git grep -I -E '3[^A-Za-z0-9.]+7' 1 + git grep -I -E '3[^A-Za-z0-9.]+8' 1 + git grep PY_MINOR_VERSION 1 + git grep PYPY_VERSION 2 .github/workflows/ci.yml: - '3.8' 1 .github/workflows/ci.yml: - 3.8 1 .github/workflows/ci.yml: - name: Add Python 3.8 1 .github/workflows/ci.yml: - 'pypy-3.8' 2 .github/workflows/ci.yml: python: '3.8' 1 .github/workflows/ci.yml: - python: '3.8' 1 .github/workflows/ci.yml: - python: 3.8 1 .github/workflows/ci.yml: python: 'pypy-3.8' 1 .github/workflows/configure.yml: cmake: "3.8" 1 .github/workflows/configure.yml: name: 🐍 3.8 β€’ CMake ${{ matrix.cmake }} β€’ ${{ matrix.runs-on }} 1 .github/workflows/configure.yml: - name: Setup Python 3.8 1 .github/workflows/configure.yml: python-version: 3.8 1 .github/workflows/pip.yml: name: 🐍 3.8 β€’ πŸ“¦ & πŸ“¦ tests β€’ ubuntu-latest 1 .github/workflows/pip.yml: name: 🐍 3.8 β€’ πŸ“¦ tests β€’ windows-latest 2 .github/workflows/pip.yml: - name: Setup 🐍 3.8 2 .github/workflows/pip.yml: python-version: 3.8 2 include/pybind11/cast.h:#if !defined(PYPY_VERSION) 2 include/pybind11/cast.h:#if defined(PYPY_VERSION) 2 include/pybind11/cast.h: // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls. 5 include/pybind11/detail/class.h:#if !defined(PYPY_VERSION) 1 include/pybind11/detail/class.h:#if defined(PYPY_VERSION) 1 include/pybind11/detail/class.h: // This was not needed before Python 3.8 (Python issue 35810) 1 include/pybind11/detail/common.h: && !defined(PYPY_VERSION) && !defined(PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF) 2 include/pybind11/detail/common.h:# error "PYTHON < 3.8 IS UNSUPPORTED. pybind11 v2.13 was the last to support Python 3.7." 1 include/pybind11/detail/common.h:#if defined(PYPY_VERSION) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) 1 include/pybind11/detail/common.h:#if PY_VERSION_HEX < 0x03080000 1 include/pybind11/detail/common.h: = PYBIND11_TOSTRING(PY_MAJOR_VERSION) "." PYBIND11_TOSTRING(PY_MINOR_VERSION); \ 1 include/pybind11/detail/internals.h: // called. PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does 1 include/pybind11/detail/internals.h:#if PYBIND11_INTERNALS_VERSION <= 4 || defined(PYPY_VERSION) 1 include/pybind11/detail/internals.h:// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new 1 include/pybind11/detail/type_caster_base.h:#if defined(PYPY_VERSION) 1 include/pybind11/embed.h:# define PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX (0x03080000) 1 include/pybind11/embed.h:#if defined(PYPY_VERSION) 1 include/pybind11/eval.h: // globals if not yet present. Python 3.8 made PyRun_String behave 2 include/pybind11/eval.h:#if defined(PYPY_VERSION) 2 include/pybind11/eval.h: // was missing from PyPy3.8 7.3.7. 2 include/pybind11/gil.h: /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and 1 include/pybind11/pybind11.h:#if !defined(PYPY_VERSION) 4 include/pybind11/pybind11.h:#if !defined(PYPY_VERSION) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 9 1 include/pybind11/pytypes.h:#endif //! defined(PYPY_VERSION) 2 include/pybind11/pytypes.h:#if !defined(PYPY_VERSION) 1 include/pybind11/pytypes.h:# if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x07030a00 1 include/pybind11/pytypes.h:#ifdef PYPY_VERSION 1 include/pybind11/stl/filesystem.h:# if !defined(PYPY_VERSION) 2 pybind11/__init__.py:if sys.version_info < (3, 8): 2 pybind11/__init__.py: msg = "pybind11 does not support Python < 3.8. v2.13 was the last release supporting Python 3.7." 1 pyproject.toml:master.py-version = "3.8" 1 pyproject.toml:python_version = "3.8" 1 README.rst:lines of code and depend on Python (3.8+, or PyPy) and the C++ 2 README.rst:- Python 3.8+, and PyPy3 7.3 are supported with an implementation-agnostic 1 setup.cfg: Programming Language :: Python :: 3.8 1 setup.cfg:python_requires = >=3.8 1 setup.py:# TODO: use literals & overload (typing extensions or Python 3.8) 1 tests/CMakeLists.txt:if(NOT CMAKE_VERSION VERSION_LESS 3.8) 2 tests/constructor_stats.h:#if defined(PYPY_VERSION) 1 tests/env.py: doesn't work on CPython 3.8.0 with pytest==3.3.2 on Ubuntu 18.04 (#2922). 1 tests/requirements.txt:build~=1.0; python_version>="3.8" 1 tests/requirements.txt:numpy~=1.21.5; platform_python_implementation!="PyPy" and python_version>="3.8" and python_version<"3.10" 1 tests/requirements.txt:numpy~=1.23.0; python_version=="3.8" and platform_python_implementation=="PyPy" 1 tests/test_buffers.py: env.PYPY, reason="PyPy 7.3.7 doesn't clear this anymore", strict=False 1 tests/test_builtin_casters.py: # Before Python 3.8, `PyLong_AsLong` does not pick up on `obj.__index__`, 2 tests/test_builtin_casters.py: if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON: 4 tests/test_builtin_casters.py: # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7) 1 tests/test_callbacks.py: assert m.test_callback3(z.double) == "func(43) = 86" 2 tests/test_call_policies.cpp:#if !defined(PYPY_VERSION) 1 tests/test_chrono.py: diff = m.test_chrono_float_diff(43.789012, 1.123456) 1 tests/test_constants_and_functions.py: assert m.f3(86) == 89 1 tests/test_eigen_matrix.py: a_copy3[8, 1] = 11 1 tests/test_eigen_matrix.py: assert np.all(cornersc == np.array([[1.0, 3], [7, 9]])) 1 tests/test_eigen_matrix.py: assert np.all(cornersr == np.array([[1.0, 3], [7, 9]])) 1 tests/test_eigen_matrix.py: mymat = chol(np.array([[1.0, 2, 4], [2, 13, 23], [4, 23, 77]])) 1 tests/test_exceptions.py: if hasattr(pytest, unraisable): # Python >= 3.8 and pytest >= 6 2 tests/test_exceptions.py:@pytest.mark.xfail(env.PYPY, reason="Failure on PyPy 3.8 (7.3.7)", strict=False) 1 tests/test_factory_constructors.py: assert [i.alive() for i in cstats] == [13, 7] 1 tests/test_kwargs_and_defaults.cpp:#ifdef PYPY_VERSION 1 tests/test_local_bindings.py: assert i1.get3() == 8 1 tests/test_methods_and_attributes.cpp:#if !defined(PYPY_VERSION) 1 tests/test_numpy_array.py: a = np.arange(3 * 7 * 2) + 1 1 tests/test_numpy_array.py: assert str(excinfo.value) == "cannot reshape array of size 42 into shape (3,7,1)" 2 tests/test_numpy_array.py: assert x.shape == (3, 7, 2) 2 tests/test_numpy_array.py: m.reshape_tuple(a, (3, 7, 1)) 2 tests/test_numpy_array.py: x = m.reshape_tuple(a, (3, 7, 2)) 1 tests/test_numpy_vectorize.py: assert np.isclose(m.vectorized_func3(np.array(3 + 7j)), [6 + 14j]) 1 tests/test_pickling.cpp:#if !defined(PYPY_VERSION) 1 tests/test_pytypes.cpp:#if (defined(__APPLE__) && defined(__clang__)) || defined(PYPY_VERSION) 1 tests/test_smart_ptr.cpp: m.def("make_myobject3_1", []() { return new MyObject3(8); }); 1 tests/test_smart_ptr.py: assert cstats.values() == ["MyObject3[9]", "MyObject3[8]", "MyObject3[9]"] 1 tests/test_stl_binders.py: assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 88]) 1 tests/test_stl_binders.py: assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 88, 4]) 1 tests/test_type_caster_pyobject_ptr.cpp:#if !defined(PYPY_VERSION) // It is not worth the trouble doing something special for PyPy. 1 tools/FindPythonLibsNew.cmake: set(PythonLibsNew_FIND_VERSION "3.8") 1 tools/JoinPaths.cmake:# https://docs.python.org/3.7/library/os.path.html#os.path.join 1 tools/pybind11NewTools.cmake: Python 3.8 REQUIRED COMPONENTS ${_pybind11_interp_component} ${_pybind11_dev_component} 1 tools/pybind11NewTools.cmake:# Python debug libraries expose slightly different objects before 3.8 1 tools/pybind11Tools.cmake: "3.12;3.11;3.10;3.9;3.8" 1 tools/pybind11Tools.cmake: if(NOT DEFINED PYPY_VERSION) 1 tools/pybind11Tools.cmake: message(STATUS "PYPY ${PYPY_VERSION} (Py ${PYTHON_VERSION})") 1 tools/pybind11Tools.cmake:# Python debug libraries expose slightly different objects before 3.8 1 tools/pybind11Tools.cmake: set(PYPY_VERSION ``` * Change `[tool.ruff]` `target-version` to `"py38"`, as suggested by @Skylion007 --- .github/workflows/ci.yml | 18 ++---------------- .github/workflows/configure.yml | 8 ++++---- README.rst | 4 ++-- docs/advanced/classes.rst | 3 +-- docs/advanced/exceptions.rst | 3 +-- docs/compiling.rst | 4 ++-- include/pybind11/cast.h | 4 ++-- include/pybind11/detail/class.h | 10 ---------- include/pybind11/detail/common.h | 4 ++-- include/pybind11/detail/internals.h | 2 +- include/pybind11/embed.h | 12 +----------- include/pybind11/eval.h | 2 +- include/pybind11/gil.h | 8 ++------ pybind11/__init__.py | 4 ++-- pybind11/setup_helpers.py | 2 +- pyproject.toml | 4 ++-- setup.cfg | 3 +-- tests/requirements.txt | 5 ++--- tests/test_builtin_casters.py | 2 +- tests/test_exceptions.py | 28 ++++++++++++---------------- tools/FindPythonLibsNew.cmake | 2 +- tools/pybind11NewTools.cmake | 2 +- tools/pybind11Tools.cmake | 2 +- 23 files changed, 45 insertions(+), 91 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06c53bf1..3a687232 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -311,11 +311,6 @@ jobs: fail-fast: false matrix: clang: - - 3.6 - - 3.7 - - 3.9 - - 7 - - 9 - dev std: - 11 @@ -324,8 +319,6 @@ jobs: include: - clang: 5 std: 14 - - clang: 10 - std: 17 - clang: 11 std: 20 - clang: 12 @@ -503,10 +496,6 @@ jobs: fail-fast: false matrix: include: - - { gcc: 7, std: 11 } - - { gcc: 7, std: 17 } - - { gcc: 8, std: 14 } - - { gcc: 8, std: 17 } - { gcc: 9, std: 20 } - { gcc: 10, std: 17 } - { gcc: 10, std: 20 } @@ -727,9 +716,9 @@ jobs: # This tests an "install" with the CMake tools install-classic: - name: "🐍 3.7 β€’ Debian β€’ x86 β€’ Install" + name: "🐍 3.9 β€’ Debian β€’ x86 β€’ Install" runs-on: ubuntu-latest - container: i386/debian:buster + container: i386/debian:bullseye steps: - uses: actions/checkout@v1 # v1 is required to run inside docker @@ -809,7 +798,6 @@ jobs: fail-fast: false matrix: python: - - '3.7' - '3.8' - '3.9' - '3.10' @@ -827,8 +815,6 @@ jobs: args: -DCMAKE_CXX_STANDARD=20 - python: '3.8' args: -DCMAKE_CXX_STANDARD=17 - - python: '3.7' - args: -DCMAKE_CXX_STANDARD=14 name: "🐍 ${{ matrix.python }} β€’ MSVC 2019 β€’ x86 ${{ matrix.args }}" diff --git a/.github/workflows/configure.yml b/.github/workflows/configure.yml index 0e55a079..0583aa06 100644 --- a/.github/workflows/configure.yml +++ b/.github/workflows/configure.yml @@ -39,22 +39,22 @@ jobs: - runs-on: macos-13 arch: x64 - cmake: "3.7" + cmake: "3.8" - runs-on: windows-2019 arch: x64 # x86 compilers seem to be missing on 2019 image cmake: "3.18" - name: 🐍 3.7 β€’ CMake ${{ matrix.cmake }} β€’ ${{ matrix.runs-on }} + name: 🐍 3.8 β€’ CMake ${{ matrix.cmake }} β€’ ${{ matrix.runs-on }} runs-on: ${{ matrix.runs-on }} steps: - uses: actions/checkout@v4 - - name: Setup Python 3.7 + - name: Setup Python 3.8 uses: actions/setup-python@v5 with: - python-version: 3.7 + python-version: 3.8 architecture: ${{ matrix.arch }} - name: Prepare env diff --git a/README.rst b/README.rst index 0d1e1d29..8e0c3917 100644 --- a/README.rst +++ b/README.rst @@ -34,7 +34,7 @@ dependency. Think of this library as a tiny self-contained version of Boost.Python with everything stripped away that isn't relevant for binding generation. Without comments, the core header files only require ~4K -lines of code and depend on Python (3.7+, or PyPy) and the C++ +lines of code and depend on Python (3.8+, or PyPy) and the C++ standard library. This compact implementation was possible thanks to some C++11 language features (specifically: tuples, lambda functions and variadic templates). Since its creation, this library has grown beyond @@ -79,7 +79,7 @@ Goodies In addition to the core functionality, pybind11 provides some extra goodies: -- Python 3.7+, and PyPy3 7.3 are supported with an implementation-agnostic +- Python 3.8+, and PyPy3 7.3 are supported with an implementation-agnostic interface (pybind11 2.9 was the last version to support Python 2 and 3.5). - It is possible to bind C++11 lambda functions with captured diff --git a/docs/advanced/classes.rst b/docs/advanced/classes.rst index 01a490b7..1e221072 100644 --- a/docs/advanced/classes.rst +++ b/docs/advanced/classes.rst @@ -826,8 +826,7 @@ An instance can now be pickled as follows: always use the latest available version. Beware: failure to follow these instructions will cause important pybind11 memory allocation routines to be skipped during unpickling, which will likely lead to memory corruption - and/or segmentation faults. Python defaults to version 3 (Python 3-3.7) and - version 4 for Python 3.8+. + and/or segmentation faults. .. seealso:: diff --git a/docs/advanced/exceptions.rst b/docs/advanced/exceptions.rst index e20f42b5..8f0e9c93 100644 --- a/docs/advanced/exceptions.rst +++ b/docs/advanced/exceptions.rst @@ -368,8 +368,7 @@ Should they throw or fail to catch any exceptions in their call graph, the C++ runtime calls ``std::terminate()`` to abort immediately. Similarly, Python exceptions raised in a class's ``__del__`` method do not -propagate, but are logged by Python as an unraisable error. In Python 3.8+, a -`system hook is triggered +propagate, but ``sys.unraisablehook()`` `is triggered `_ and an auditing event is logged. diff --git a/docs/compiling.rst b/docs/compiling.rst index 0b7c178b..234f53fb 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -426,7 +426,7 @@ with ``PYTHON_EXECUTABLE``. For example: .. code-block:: bash - cmake -DPYBIND11_PYTHON_VERSION=3.7 .. + cmake -DPYBIND11_PYTHON_VERSION=3.8 .. # Another method: cmake -DPYTHON_EXECUTABLE=/path/to/python .. @@ -493,7 +493,7 @@ existing targets instead: cmake_minimum_required(VERSION 3.15...3.22) project(example LANGUAGES CXX) - find_package(Python 3.7 COMPONENTS Interpreter Development REQUIRED) + find_package(Python 3.8 COMPONENTS Interpreter Development REQUIRED) find_package(pybind11 CONFIG REQUIRED) # or add_subdirectory(pybind11) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 0f3091f6..0c862e4b 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -158,7 +158,7 @@ struct type_caster::value && !is_std_char_t } else { handle src_or_index = src; // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls. -#if PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION) +#if defined(PYPY_VERSION) object index; if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr()) index = reinterpret_steal(PyNumber_Index(src.ptr())); @@ -1503,7 +1503,7 @@ struct kw_only {}; /// \ingroup annotations /// Annotation indicating that all previous arguments are positional-only; the is the equivalent of -/// an unnamed '/' argument (in Python 3.8) +/// an unnamed '/' argument struct pos_only {}; template diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index d30621c8..485f7ac6 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -466,19 +466,9 @@ extern "C" inline void pybind11_object_dealloc(PyObject *self) { type->tp_free(self); -#if PY_VERSION_HEX < 0x03080000 - // `type->tp_dealloc != pybind11_object_dealloc` means that we're being called - // as part of a derived type's dealloc, in which case we're not allowed to decref - // the type here. For cross-module compatibility, we shouldn't compare directly - // with `pybind11_object_dealloc`, but with the common one stashed in internals. - auto pybind11_object_type = (PyTypeObject *) get_internals().instance_base; - if (type->tp_dealloc == pybind11_object_type->tp_dealloc) - Py_DECREF(type); -#else // This was not needed before Python 3.8 (Python issue 35810) // https://github.com/pybind/pybind11/issues/1946 Py_DECREF(type); -#endif } std::string error_string(); diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 9418334c..71a98f06 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -272,8 +272,8 @@ PYBIND11_WARNING_DISABLE_MSVC(4505) #endif #include -#if PY_VERSION_HEX < 0x03070000 -# error "PYTHON < 3.7 IS UNSUPPORTED. pybind11 v2.12 was the last to support Python 3.6." +#if PY_VERSION_HEX < 0x03080000 +# error "PYTHON < 3.8 IS UNSUPPORTED. pybind11 v2.13 was the last to support Python 3.7." #endif #include #include diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 692e8d39..329d89b9 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -447,7 +447,7 @@ inline void translate_local_exception(std::exception_ptr p) { inline object get_python_state_dict() { object state_dict; -#if PYBIND11_INTERNALS_VERSION <= 4 || PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION) +#if PYBIND11_INTERNALS_VERSION <= 4 || defined(PYPY_VERSION) state_dict = reinterpret_borrow(PyEval_GetBuiltins()); #else # if PY_VERSION_HEX < 0x03090000 diff --git a/include/pybind11/embed.h b/include/pybind11/embed.h index 9d29eb82..0af77703 100644 --- a/include/pybind11/embed.h +++ b/include/pybind11/embed.h @@ -104,23 +104,13 @@ inline void initialize_interpreter_pre_pyconfig(bool init_signal_handlers, detail::precheck_interpreter(); Py_InitializeEx(init_signal_handlers ? 1 : 0); - // Before it was special-cased in python 3.8, passing an empty or null argv - // caused a segfault, so we have to reimplement the special case ourselves. - bool special_case = (argv == nullptr || argc <= 0); - - const char *const empty_argv[]{"\0"}; - const char *const *safe_argv = special_case ? empty_argv : argv; - if (special_case) { - argc = 1; - } - auto argv_size = static_cast(argc); // SetArgv* on python 3 takes wchar_t, so we have to convert. std::unique_ptr widened_argv(new wchar_t *[argv_size]); std::vector> widened_argv_entries; widened_argv_entries.reserve(argv_size); for (size_t ii = 0; ii < argv_size; ++ii) { - widened_argv_entries.emplace_back(detail::widen_chars(safe_argv[ii])); + widened_argv_entries.emplace_back(detail::widen_chars(argv[ii])); if (!widened_argv_entries.back()) { // A null here indicates a character-encoding failure or the python // interpreter out of memory. Give up. diff --git a/include/pybind11/eval.h b/include/pybind11/eval.h index bd5f981f..74d9b96b 100644 --- a/include/pybind11/eval.h +++ b/include/pybind11/eval.h @@ -19,7 +19,7 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) inline void ensure_builtins_in_globals(object &global) { -#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000 +#if defined(PYPY_VERSION) // Running exec and eval adds `builtins` module under `__builtins__` key to // globals if not yet present. Python 3.8 made PyRun_String behave // similarly. Let's also do that for older versions, for consistency. This diff --git a/include/pybind11/gil.h b/include/pybind11/gil.h index 6b0edaee..88881049 100644 --- a/include/pybind11/gil.h +++ b/include/pybind11/gil.h @@ -147,9 +147,7 @@ class gil_scoped_release { // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) tstate = PyEval_SaveThread(); if (disassoc) { - // Python >= 3.7 can remove this, it's an int before 3.7 - // NOLINTNEXTLINE(readability-qualified-auto) - auto key = internals.tstate; + auto key = internals.tstate; // NOLINT(readability-qualified-auto) PYBIND11_TLS_DELETE_VALUE(key); } } @@ -173,9 +171,7 @@ class gil_scoped_release { PyEval_RestoreThread(tstate); } if (disassoc) { - // Python >= 3.7 can remove this, it's an int before 3.7 - // NOLINTNEXTLINE(readability-qualified-auto) - auto key = detail::get_internals().tstate; + auto key = detail::get_internals().tstate; // NOLINT(readability-qualified-auto) PYBIND11_TLS_REPLACE_VALUE(key, tstate); } } diff --git a/pybind11/__init__.py b/pybind11/__init__.py index b14660ca..e9d033c4 100644 --- a/pybind11/__init__.py +++ b/pybind11/__init__.py @@ -2,8 +2,8 @@ import sys -if sys.version_info < (3, 7): # noqa: UP036 - msg = "pybind11 does not support Python < 3.7. v2.12 was the last release supporting Python 3.6." +if sys.version_info < (3, 8): # noqa: UP036 + msg = "pybind11 does not support Python < 3.8. v2.13 was the last release supporting Python 3.7." raise ImportError(msg) diff --git a/pybind11/setup_helpers.py b/pybind11/setup_helpers.py index ced506f8..f2429181 100644 --- a/pybind11/setup_helpers.py +++ b/pybind11/setup_helpers.py @@ -249,7 +249,7 @@ def has_flag(compiler: Any, flag: str) -> bool: cpp_flag_cache = None -@lru_cache() +@lru_cache def auto_cpp_level(compiler: Any) -> str | int: """ Return the max supported C++ std level (17, 14, or 11). Returns latest on Windows. diff --git a/pyproject.toml b/pyproject.toml index 71e7f561..c5e2651d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ ignore_missing_imports = true [tool.pylint] -master.py-version = "3.7" +master.py-version = "3.8" reports.output-format = "colorized" messages_control.disable = [ "design", @@ -45,7 +45,7 @@ messages_control.disable = [ ] [tool.ruff] -target-version = "py37" +target-version = "py38" src = ["src"] [tool.ruff.lint] diff --git a/setup.cfg b/setup.cfg index 2beca780..bb5b744a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -14,7 +14,6 @@ classifiers = Topic :: Utilities Programming Language :: C++ Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 @@ -39,5 +38,5 @@ project_urls = Chat = https://gitter.im/pybind/Lobby [options] -python_requires = >=3.7 +python_requires = >=3.8 zip_safe = False diff --git a/tests/requirements.txt b/tests/requirements.txt index 337897bd..f4f838ec 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,9 +1,8 @@ --only-binary=:all: -build~=1.0; python_version>="3.7" -numpy~=1.20.0; python_version=="3.7" and platform_python_implementation=="PyPy" +build~=1.0; python_version>="3.8" numpy~=1.23.0; python_version=="3.8" and platform_python_implementation=="PyPy" numpy~=1.25.0; python_version=="3.9" and platform_python_implementation=='PyPy' -numpy~=1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10" +numpy~=1.21.5; platform_python_implementation!="PyPy" and python_version>="3.8" and python_version<"3.10" numpy~=1.22.2; platform_python_implementation!="PyPy" and python_version=="3.10" numpy~=1.26.0; platform_python_implementation!="PyPy" and python_version>="3.11" and python_version<"3.13" pytest~=7.0 diff --git a/tests/test_builtin_casters.py b/tests/test_builtin_casters.py index b37aacff..240be85e 100644 --- a/tests/test_builtin_casters.py +++ b/tests/test_builtin_casters.py @@ -297,7 +297,7 @@ def cant_convert(v): cant_convert(3.14159) # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar) # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7) - if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON: + if sys.version_info < (3, 10) and env.CPYTHON: with env.deprecated_call(): assert convert(Int()) == 42 else: diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index db2a551e..ba5063a7 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -103,28 +103,24 @@ def ignore_pytest_unraisable_warning(f): @pytest.mark.xfail(env.PYPY, reason="Failure on PyPy 3.8 (7.3.7)", strict=False) @ignore_pytest_unraisable_warning def test_python_alreadyset_in_destructor(monkeypatch, capsys): - hooked = False triggered = False - if hasattr(sys, "unraisablehook"): # Python 3.8+ - hooked = True - # Don't take `sys.unraisablehook`, as that's overwritten by pytest - default_hook = sys.__unraisablehook__ + # Don't take `sys.unraisablehook`, as that's overwritten by pytest + default_hook = sys.__unraisablehook__ - def hook(unraisable_hook_args): - exc_type, exc_value, exc_tb, err_msg, obj = unraisable_hook_args - if obj == "already_set demo": - nonlocal triggered - triggered = True - default_hook(unraisable_hook_args) - return + def hook(unraisable_hook_args): + exc_type, exc_value, exc_tb, err_msg, obj = unraisable_hook_args + if obj == "already_set demo": + nonlocal triggered + triggered = True + default_hook(unraisable_hook_args) + return - # Use monkeypatch so pytest can apply and remove the patch as appropriate - monkeypatch.setattr(sys, "unraisablehook", hook) + # Use monkeypatch so pytest can apply and remove the patch as appropriate + monkeypatch.setattr(sys, "unraisablehook", hook) assert m.python_alreadyset_in_destructor("already_set demo") is True - if hooked: - assert triggered is True + assert triggered is True _, captured_stderr = capsys.readouterr() assert captured_stderr.startswith("Exception ignored in: 'already_set demo'") diff --git a/tools/FindPythonLibsNew.cmake b/tools/FindPythonLibsNew.cmake index 283b4e29..014f68fb 100644 --- a/tools/FindPythonLibsNew.cmake +++ b/tools/FindPythonLibsNew.cmake @@ -92,7 +92,7 @@ endif() # Use the Python interpreter to find the libs. if(NOT PythonLibsNew_FIND_VERSION) - set(PythonLibsNew_FIND_VERSION "3.7") + set(PythonLibsNew_FIND_VERSION "3.8") endif() if(NOT CMAKE_VERSION VERSION_LESS "3.27") diff --git a/tools/pybind11NewTools.cmake b/tools/pybind11NewTools.cmake index a8b0800b..444f3aaf 100644 --- a/tools/pybind11NewTools.cmake +++ b/tools/pybind11NewTools.cmake @@ -56,7 +56,7 @@ if(NOT Python_FOUND AND NOT Python3_FOUND) endif() find_package( - Python 3.7 REQUIRED COMPONENTS ${_pybind11_interp_component} ${_pybind11_dev_component} + Python 3.8 REQUIRED COMPONENTS ${_pybind11_interp_component} ${_pybind11_dev_component} ${_pybind11_quiet} ${_pybind11_global_keyword}) # If we are in submodule mode, export the Python targets to global targets. diff --git a/tools/pybind11Tools.cmake b/tools/pybind11Tools.cmake index bed5e080..021038d9 100644 --- a/tools/pybind11Tools.cmake +++ b/tools/pybind11Tools.cmake @@ -43,7 +43,7 @@ endif() # A user can set versions manually too set(Python_ADDITIONAL_VERSIONS - "3.12;3.11;3.10;3.9;3.8;3.7" + "3.12;3.11;3.10;3.9;3.8" CACHE INTERNAL "") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") From 6765d4e8144eb0b73aa5d20ff738cd462f274ef4 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 30 Jul 2024 11:21:50 -0700 Subject: [PATCH 2/7] Tracking ci.yml changes from master. --- .github/workflows/ci_sh_def.yml | 18 ++---------- .github/workflows/ci_sh_def.yml.patch | 42 +++++++++++++-------------- 2 files changed, 23 insertions(+), 37 deletions(-) diff --git a/.github/workflows/ci_sh_def.yml b/.github/workflows/ci_sh_def.yml index f37f7516..68a73985 100644 --- a/.github/workflows/ci_sh_def.yml +++ b/.github/workflows/ci_sh_def.yml @@ -329,11 +329,6 @@ jobs: fail-fast: false matrix: clang: - - 3.6 - - 3.7 - - 3.9 - - 7 - - 9 - dev std: - 11 @@ -342,8 +337,6 @@ jobs: include: - clang: 5 std: 14 - - clang: 10 - std: 17 - clang: 11 std: 20 - clang: 12 @@ -522,10 +515,6 @@ jobs: fail-fast: false matrix: include: - - { gcc: 7, std: 11 } - - { gcc: 7, std: 17 } - - { gcc: 8, std: 14 } - - { gcc: 8, std: 17 } - { gcc: 9, std: 20 } - { gcc: 10, std: 17 } - { gcc: 10, std: 20 } @@ -751,9 +740,9 @@ jobs: # This tests an "install" with the CMake tools install-classic: - name: "🐍 3.7 β€’ Debian β€’ x86 β€’ Install" + name: "🐍 3.9 β€’ Debian β€’ x86 β€’ Install" runs-on: ubuntu-latest - container: i386/debian:buster + container: i386/debian:bullseye steps: - uses: actions/checkout@v1 # v1 is required to run inside docker @@ -834,7 +823,6 @@ jobs: fail-fast: false matrix: python: - - '3.7' - '3.8' - '3.9' - '3.10' @@ -852,8 +840,6 @@ jobs: args: -DCMAKE_CXX_STANDARD=20 - python: '3.8' args: -DCMAKE_CXX_STANDARD=17 - - python: '3.7' - args: -DCMAKE_CXX_STANDARD=14 name: "🐍 ${{ matrix.python }} β€’ MSVC 2019 β€’ x86 ${{ matrix.args }}" diff --git a/.github/workflows/ci_sh_def.yml.patch b/.github/workflows/ci_sh_def.yml.patch index 456ca736..ecfd7639 100644 --- a/.github/workflows/ci_sh_def.yml.patch +++ b/.github/workflows/ci_sh_def.yml.patch @@ -1,5 +1,5 @@ ---- ci.yml 2024-07-29 11:18:11.967568957 -0700 -+++ ci_sh_def.yml 2024-07-29 11:18:42.087538968 -0700 +--- ci.yml 2024-07-30 11:20:28.997003056 -0700 ++++ ci_sh_def.yml 2024-07-30 11:21:39.724969167 -0700 @@ -1,4 +1,16 @@ -name: CI +# PLEASE KEEP THIS GROUP OF FILES IN SYNC AT ALL TIMES: @@ -67,7 +67,7 @@ - name: Build run: cmake --build build -j 2 -@@ -364,6 +381,7 @@ +@@ -357,6 +374,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} @@ -75,7 +75,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build -@@ -393,7 +411,7 @@ +@@ -386,7 +404,7 @@ run: apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y cmake git python3-dev python3-pytest python3-numpy - name: Configure @@ -84,7 +84,7 @@ - name: Build run: cmake --build build -j2 --verbose -@@ -481,7 +499,7 @@ +@@ -474,7 +492,7 @@ cmake -S . -B build -DDOWNLOAD_CATCH=ON \ -DCMAKE_CXX_STANDARD=17 \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \ @@ -93,7 +93,7 @@ -DPYBIND11_TEST_FILTER="test_smart_ptr.cpp" - name: Build -@@ -537,6 +555,7 @@ +@@ -526,6 +544,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} @@ -101,7 +101,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build -@@ -559,6 +578,7 @@ +@@ -548,6 +567,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} @@ -109,7 +109,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp" -@@ -608,6 +628,7 @@ +@@ -597,6 +617,7 @@ -DDOWNLOAD_CATCH=ON \ -DDOWNLOAD_EIGEN=OFF \ -DCMAKE_CXX_STANDARD=11 \ @@ -117,7 +117,7 @@ -DCMAKE_CXX_COMPILER=$(which icpc) \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") -@@ -640,6 +661,7 @@ +@@ -629,6 +650,7 @@ -DDOWNLOAD_CATCH=ON \ -DDOWNLOAD_EIGEN=OFF \ -DCMAKE_CXX_STANDARD=17 \ @@ -125,7 +125,7 @@ -DCMAKE_CXX_COMPILER=$(which icpc) \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") -@@ -711,6 +733,7 @@ +@@ -700,6 +722,7 @@ -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=11 @@ -133,7 +133,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build -@@ -761,6 +784,7 @@ +@@ -750,6 +773,7 @@ cmake ../pybind11-tests -DDOWNLOAD_CATCH=ON -DPYBIND11_WERROR=ON @@ -141,7 +141,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") working-directory: /build-tests -@@ -864,6 +888,7 @@ +@@ -850,6 +874,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON @@ -149,7 +149,7 @@ ${{ matrix.args }} - name: Build C++11 run: cmake --build build -j 2 -@@ -918,6 +943,7 @@ +@@ -904,6 +929,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON @@ -157,7 +157,7 @@ ${{ matrix.args }} - name: Build C++11 run: cmake --build build --config Debug -j 2 -@@ -960,6 +986,7 @@ +@@ -946,6 +972,7 @@ -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=20 @@ -165,7 +165,7 @@ - name: Build C++20 run: cmake --build build -j 2 -@@ -980,6 +1007,7 @@ +@@ -966,6 +993,7 @@ -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=20 @@ -173,7 +173,7 @@ "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp" - name: Build C++20 - Exercise cmake -DPYBIND11_TEST_OVERRIDE -@@ -1032,6 +1060,7 @@ +@@ -1018,6 +1046,7 @@ run: >- cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=11 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") @@ -181,7 +181,7 @@ -S . -B build - name: Build C++11 -@@ -1053,6 +1082,7 @@ +@@ -1039,6 +1068,7 @@ run: >- cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=14 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") @@ -189,7 +189,7 @@ -S . -B build2 - name: Build C++14 -@@ -1074,6 +1104,7 @@ +@@ -1060,6 +1090,7 @@ run: >- cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") @@ -197,7 +197,7 @@ -S . -B build3 - name: Build C++17 -@@ -1141,6 +1172,7 @@ +@@ -1127,6 +1158,7 @@ -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_STANDARD=17 @@ -205,7 +205,7 @@ - name: Build run: cmake --build . -j 2 -@@ -1206,6 +1238,7 @@ +@@ -1192,6 +1224,7 @@ -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_STANDARD=17 @@ -213,7 +213,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build -@@ -1229,6 +1262,7 @@ +@@ -1215,6 +1248,7 @@ -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_STANDARD=17 From 48f25275c44d52d0ceade122e328dc1f2e48ef44 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 31 Jul 2024 20:17:31 +0700 Subject: [PATCH 3/7] [smart_holder] Bake smart_holder functionality into `class_` and `type_caster_base` (#5257) * Put bakein branch @ 18b72c0ffa6ff2747ed6c4b869a80adfb8e762c9 on top of smart_holder branch: Commands used: ``` git checkout bakein git diff smart_holder > ~/zd git checkout smart_holder git checkout -b bakein_sh patch -p 1 < ~/zd git checkout smart_holder \ MANIFEST.in \ README.rst \ README_smart_holder.rst \ docs/advanced/smart_ptrs.rst \ ubench/holder_comparison.cpp \ ubench/holder_comparison.py \ ubench/holder_comparison_extract_sheet_data.py \ ubench/number_bucket.h \ ubench/python/number_bucket.clif git add -A ``` * Add back README_smart_holder.rst in tests/extra_python_package/test_files.py * Restore smart_holder_poc.h as-is on smart_holder branch (i.e. undo `PYBIND11_SMART_HOLDER_PADDING`, which was meant for stress-testing only). * Insert `std::move()` as suggested by @laramiel * `property_cpp_function_sh_*` named specializations, as suggested by @laramiel (https://github.com/pybind/pybind11/pull/5257#discussion_r1688346807) * Call `property_cpp_function_classic` member functions, rather than inlining the implementations. * Use `PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT` in holder_comparison.cpp (holder_comparison.py is NOT changed accordingly in this commit, i.e. can still only be run if the smart_holder functionality is available). * Systematically rename `loaded_as` to `load_as` (`shared_ptr`, `unique_ptr`) as suggested by @laramiel * Make change as suggested by @laramiel. This makes it much more obvious that the latest implementation of `smart_holder_from_unique_ptr()` accepts all existing `return_value_policy` enum values except `copy`. * Resolve `BAKEIN_WIP: Rewrite comment.` for `property_cpp_function_*` specializations. * Resolve `BAKEIN_WIP: Add comment to explain: This is meant for stress-testing only.` * Resolve all remaining BAKEIN_WIP (in pybind11/cast.h). Leave only two pairs of SMART_HOLDER_BAKEIN_FOLLOW_ON comments: refactoring of copyable_holder_caster, move_only_holder_caster. This is best left until after the smart_holder branch is merged into the master branch. * Remove obsolete `using holder_type = smart_holder;` in `load_helper` * Add SMART_HOLDER_BAKEIN_FOLLOW_ON comment for `internals::default_holder` * README_smart_holder.rst update (line count reduced from 356 to 123). --- CMakeLists.txt | 3 +- README_smart_holder.rst | 341 +----- include/pybind11/attr.h | 4 + include/pybind11/cast.h | 281 ++++- include/pybind11/detail/common.h | 6 +- include/pybind11/detail/init.h | 41 +- include/pybind11/detail/internals.h | 42 +- .../detail/smart_holder_sfinae_hooks_only.h | 46 - .../detail/smart_holder_type_casters.h | 1046 ----------------- include/pybind11/detail/type_caster_base.h | 368 ++++++ include/pybind11/detail/using_smart_holder.h | 33 + include/pybind11/pybind11.h | 409 ++++--- include/pybind11/smart_holder.h | 29 +- include/pybind11/stl.h | 3 - .../pybind11/trampoline_self_life_support.h | 14 +- pybind11/_version.py | 2 +- tests/class_sh_module_local_0.cpp | 7 + tests/class_sh_module_local_1.cpp | 7 + tests/class_sh_module_local_2.cpp | 7 + tests/extra_python_package/test_files.py | 3 +- tests/test_class.cpp | 44 +- tests/test_class.py | 12 + tests/test_class_sh_basic.cpp | 9 + tests/test_class_sh_basic.py | 17 +- tests/test_class_sh_disowning.cpp | 7 + tests/test_class_sh_disowning.py | 3 + tests/test_class_sh_disowning_mi.cpp | 7 + tests/test_class_sh_disowning_mi.py | 3 + tests/test_class_sh_factory_constructors.cpp | 7 + tests/test_class_sh_factory_constructors.py | 3 + tests/test_class_sh_inheritance.cpp | 7 + tests/test_class_sh_inheritance.py | 5 + tests/test_class_sh_mi_thunks.cpp | 7 + tests/test_class_sh_mi_thunks.py | 6 +- tests/test_class_sh_module_local.py | 3 + tests/test_class_sh_property.cpp | 7 + tests/test_class_sh_property.py | 5 +- tests/test_class_sh_property_non_owning.cpp | 7 + tests/test_class_sh_property_non_owning.py | 3 + tests/test_class_sh_shared_ptr_copy_move.cpp | 9 +- tests/test_class_sh_shared_ptr_copy_move.py | 5 + tests/test_class_sh_trampoline_basic.cpp | 11 + tests/test_class_sh_trampoline_basic.py | 3 + ..._class_sh_trampoline_self_life_support.cpp | 9 + ...t_class_sh_trampoline_self_life_support.py | 3 + ...t_class_sh_trampoline_shared_from_this.cpp | 9 + ...st_class_sh_trampoline_shared_from_this.py | 5 +- ...class_sh_trampoline_shared_ptr_cpp_arg.cpp | 7 + ..._class_sh_trampoline_shared_ptr_cpp_arg.py | 3 + tests/test_class_sh_trampoline_unique_ptr.cpp | 9 + tests/test_class_sh_trampoline_unique_ptr.py | 5 + ...est_class_sh_unique_ptr_custom_deleter.cpp | 7 + ...test_class_sh_unique_ptr_custom_deleter.py | 5 + tests/test_class_sh_unique_ptr_member.cpp | 7 + tests/test_class_sh_unique_ptr_member.py | 3 + tests/test_class_sh_virtual_py_cpp_mix.cpp | 11 + tests/test_class_sh_virtual_py_cpp_mix.py | 3 + tests/test_classh_mock.cpp | 14 +- tests/test_embed/test_interpreter.cpp | 2 +- tests/test_factory_constructors.cpp | 8 +- tests/test_factory_constructors.py | 9 +- tests/test_methods_and_attributes.cpp | 12 +- tests/test_methods_and_attributes.py | 14 +- tests/test_multiple_inheritance.cpp | 14 +- tests/test_smart_ptr.cpp | 36 - tests/test_smart_ptr.py | 6 +- tests/test_virtual_functions.cpp | 2 +- ubench/holder_comparison.cpp | 17 +- 68 files changed, 1334 insertions(+), 1768 deletions(-) delete mode 100644 include/pybind11/detail/smart_holder_sfinae_hooks_only.h delete mode 100644 include/pybind11/detail/smart_holder_type_casters.h create mode 100644 include/pybind11/detail/using_smart_holder.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b82f4570..0964e2ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,10 +154,9 @@ set(PYBIND11_HEADERS include/pybind11/detail/init.h include/pybind11/detail/internals.h include/pybind11/detail/smart_holder_poc.h - include/pybind11/detail/smart_holder_sfinae_hooks_only.h - include/pybind11/detail/smart_holder_type_casters.h include/pybind11/detail/type_caster_base.h include/pybind11/detail/typeid.h + include/pybind11/detail/using_smart_holder.h include/pybind11/detail/value_and_holder.h include/pybind11/attr.h include/pybind11/buffer_info.h diff --git a/README_smart_holder.rst b/README_smart_holder.rst index 7943d5c6..05b1ab56 100644 --- a/README_smart_holder.rst +++ b/README_smart_holder.rst @@ -6,58 +6,71 @@ pybind11 β€” smart_holder branch Overview ======== -- The smart_holder git branch is a strict superset of the master - branch. Everything that works on master is expected to work exactly the same - with the smart_holder branch. - -- **Smart-pointer interoperability** (``std::unique_ptr``, ``std::shared_ptr``) - is implemented as an **add-on**. - -- The add-on also supports - * passing a Python object back to C++ via ``std::unique_ptr``, safely - **disowning** the Python object. - * safely passing `"trampoline" - `_ - objects (objects with C++ virtual function overrides implemented in - Python) via ``std::unique_ptr`` or ``std::shared_ptr`` back to C++: - associated Python objects are automatically kept alive for the lifetime - of the smart-pointer. - -- The smart_holder branch can be used in two modes: - * **Conservative mode**: ``py::class_`` works exactly as on master. - ``py::classh`` uses ``py::smart_holder``. - * **Progressive mode**: ``py::class_`` uses ``py::smart_holder`` - (i.e. ``py::smart_holder`` is the default holder). +- The smart_holder branch is a strict superset of the pybind11 master branch. + Everything that works with the master branch is expected to work exactly the + same with the smart_holder branch. + +- Activating the smart_holder functionality for a given C++ type ``T`` is as + easy as changing ``py::class_`` to ``py::classh`` in client code. + +- The ``py::classh`` functionality includes + + * support for **two-way** Python/C++ conversions for both + ``std::unique_ptr`` and ``std::shared_ptr`` **simultaneously**. + β€” In contrast, ``py::class_`` only supports one-way C++-to-Python + conversions for ``std::unique_ptr``, or alternatively two-way + Python/C++ conversions for ``std::shared_ptr``, which then excludes + the one-way C++-to-Python ``std::unique_ptr`` conversions (this + manifests itself through undefined runtime behavior). + + * passing a Python object back to C++ via ``std::unique_ptr``, safely + **disowning** the Python object. + + * safely passing `"trampoline" + `_ + objects (objects with C++ virtual function overrides implemented in + Python) via ``std::unique_ptr`` or ``std::shared_ptr`` back to C++: + associated Python objects are automatically kept alive for the lifetime + of the smart-pointer. + +Note: As of `PR #5257 `_ +the smart_holder functionality is fully baked into pybind11. +Prior to PR #5257 the smart_holder implementation was an "add-on", which made +it necessary to use a ``PYBIND11_SMART_HOLDER_TYPE_CASTERS`` macro. This macro +still exists for backward compatibility, but is now a no-op. The trade-off +for this convenience is that the ``PYBIND11_INTERNALS_VERSION`` needed to be +changed. Consequently, Python extension modules built with the smart_holder +branch no longer interoperate with extension modules built with the pybind11 +master branch. If cross-extension-module interoperability is required, all +extension modules involved must be built with the smart_holder branch. +β€” Probably, most extension modules do not require cross-extension-module +interoperability, but exceptions to this are quite common. What is fundamentally different? -------------------------------- - Classic pybind11 has the concept of "smart-pointer is holder". - Interoperability between smart-pointers is completely missing. For - example, when using ``std::shared_ptr`` as holder, ``return``-ing - a ``std::unique_ptr`` leads to undefined runtime behavior - (`#1138 `_). A - `systematic analysis is here `_. + Interoperability between smart-pointers is completely missing. For example, + with ``py::class_>``, ``return``-ing a + ``std::unique_ptr`` leads to undefined runtime behavior + (`#1138 `_). + A `systematic analysis can be found here + `_. - ``py::smart_holder`` has a richer concept in comparison, with well-defined - runtime behavior. The holder "knows" about both ``std::unique_ptr`` and - ``std::shared_ptr`` and how they interoperate. - -- Caveat (#HelpAppreciated): currently the ``smart_holder`` branch does - not have a well-lit path for including interoperability with custom - smart-pointers. It is expected to be a fairly obvious extension of the - ``smart_holder`` implementation, but will depend on the exact specifications - of each custom smart-pointer type (generalizations are very likely possible). + runtime behavior in all situations. ``py::smart_holder`` "knows" about both + ``std::unique_ptr`` and ``std::shared_ptr``, and how they interoperate. What motivated the development of the smart_holder code? -------------------------------------------------------- -- Necessity is the mother. The bigger context is the ongoing retooling of - `PyCLIF `_, to use pybind11 underneath - instead of directly targeting the Python C API. Essentially, the smart_holder - branch is porting established PyCLIF functionality into pybind11. +- The original context was retooling of `PyCLIF + `_, to use pybind11 underneath, + instead of directly targeting the Python C API. Essentially the smart_holder + branch is porting established PyCLIF functionality into pybind11. (However, + this work also led to bug fixes in PyCLIF.) Installation @@ -72,225 +85,6 @@ Currently ``git clone`` is the only option. We do not have released packages. Everything else is exactly identical to using the default (master) branch. -Conservative or Progressive mode? -================================= - -It depends. To a first approximation, for a stand-alone, new project, the -Progressive mode will be easiest to use. For larger projects or projects -that integrate with third-party pybind11-based projects, the Conservative -mode may be more practical, at least initially, although it comes with the -disadvantage of having to use the ``PYBIND11_SMART_HOLDER_TYPE_CASTERS`` macro. - - -Conservative mode ------------------ - -Here is a minimal example for wrapping a C++ type with ``py::smart_holder`` as -holder: - -.. code-block:: cpp - - #include - - struct Foo {}; - - PYBIND11_SMART_HOLDER_TYPE_CASTERS(Foo) - - PYBIND11_MODULE(example_bindings, m) { - namespace py = pybind11; - py::classh(m, "Foo"); - } - -There are three small differences compared to Classic pybind11: - -- ``#include `` is used instead of - ``#include ``. - -- The ``PYBIND11_SMART_HOLDER_TYPE_CASTERS(Foo)`` macro is needed. - β€” NOTE: This macro needs to be in the global namespace. - -- ``py::classh`` is used instead of ``py::class_``. - -To the 2nd bullet point, the ``PYBIND11_SMART_HOLDER_TYPE_CASTERS`` macro -needs to appear in all translation units with pybind11 bindings that involve -Python⇄C++ conversions for ``Foo``. This is the biggest inconvenience of the -Conservative mode. Practically, at a larger scale it is best to work with a -pair of ``.h`` and ``.cpp`` files for the bindings code, with the macros in -the ``.h`` files. - -To the 3rd bullet point, ``py::classh`` is simply a shortcut for -``py::class_``. The shortcut makes it possible to -switch to using ``py::smart_holder`` without disturbing the indentation of -existing code. - -When migrating code that uses ``py::class_>`` -there are two alternatives. The first one is to use ``py::classh``: - -.. code-block:: diff - - - py::class_>(m, "Bar"); - + py::classh(m, "Bar"); - -This is clean and simple, but makes it difficult to fall back to Classic -mode if needed. The second alternative is to replace ``std::shared_ptr`` -with ``PYBIND11_SH_AVL(Bar)``: - -.. code-block:: diff - - - py::class_>(m, "Bar"); - + py::class_(m, "Bar"); - -The ``PYBIND11_SH_AVL`` macro substitutes ``py::smart_holder`` -in Conservative mode, or ``std::shared_ptr`` in Classic mode. -See tests/test_classh_mock.cpp for an example. Note that the macro is also -designed to not disturb the indentation of existing code. - - -Progressive mode ----------------- - -To work in Progressive mode: - -- Add ``-DPYBIND11_USE_SMART_HOLDER_AS_DEFAULT`` to the compilation commands. - -- Remove or replace (see below) ``std::shared_ptr<...>`` holders. - -- Only if custom smart-pointers are used: the - ``PYBIND11_TYPE_CASTER_BASE_HOLDER`` macro is needed (see - tests/test_smart_ptr.cpp for examples). - -Overall this is probably easier to work with than the Conservative mode, but - -- the macro inconvenience is shifted from ``py::smart_holder`` to custom - smart-pointer holders (which are probably much more rare). - -- it will not interoperate with other extensions built against master or - stable, or extensions built in Conservative mode (see the cross-module - compatibility section below). - -When migrating code that uses ``py::class_>`` there -are the same alternatives as for the Conservative mode (see previous section). -An additional alternative is to use the ``PYBIND11_SH_DEF(...)`` macro: - -.. code-block:: diff - - - py::class_>(m, "Bar"); - + py::class_(m, "Bar"); - -The ``PYBIND11_SH_DEF`` macro substitutes ``py::smart_holder`` only in -Progressive mode, or ``std::shared_ptr`` in Classic or Conservative -mode. See tests/test_classh_mock.cpp for an example. Note that the -``PYBIND11_SMART_HOLDER_TYPE_CASTERS`` macro is never needed in combination -with the ``PYBIND11_SH_DEF`` macro, which is an advantage compared to the -``PYBIND11_SH_AVL`` macro. Please review tests/test_classh_mock.cpp for a -concise overview of all available options. - - -Transition from Classic to Progressive mode -------------------------------------------- - -This still has to be tried out more in practice, but in small-scale situations -it may be feasible to switch directly to Progressive mode in a break-fix -fashion. In large-scale situations it seems more likely that an incremental -approach is needed, which could mean incrementally converting ``py::class_`` -to ``py::classh`` and using the family of related macros, then flip the switch -to Progressive mode, and convert ``py::classh`` back to ``py:class_`` combined -with removal of the macros if desired (at that point it will work equivalently -either way). It may be smart to delay the final cleanup step until all -third-party projects of interest have made the switch, because then the code -will continue to work in all modes. - - -Using py::smart_holder but with fallback to Classic pybind11 ------------------------------------------------------------- - -For situations in which compatibility with Classic pybind11 -(without smart_holder) is needed for some period of time, fallback -to Classic mode can be enabled by copying the ``BOILERPLATE`` code -block from tests/test_classh_mock.cpp. This code block provides mock -implementations of ``py::classh`` and the family of related macros -(e.g. ``PYBIND11_SMART_HOLDER_TYPE_CASTERS``). - - -Classic / Conservative / Progressive cross-module compatibility ---------------------------------------------------------------- - -Currently there are essentially three modes for building a pybind11 extension -module: - -- Classic: pybind11 stable (e.g. v2.6.2) or current master branch. - -- Conservative: pybind11 smart_holder branch. - -- Progressive: pybind11 smart_holder branch with - ``-DPYBIND11_USE_SMART_HOLDER_AS_DEFAULT``. - -In environments that mix extension modules built with different modes, -this is the compatibility matrix for ``py::class_``-wrapped types: - -.. list-table:: Compatibility matrix - :widths: auto - :header-rows: 2 - - * - - - - - - - Module 2 - - - * - - - - - Classic - - Conservative - - Progressive - * - - - **Classic** - - full - - one-and-a-half-way - - isolated - * - **Module 1** - - **Conservative** - - one-and-a-half-way - - full - - isolated - * - - - **Progressive** - - isolated - - isolated - - full - -Mixing Classic+Progressive or Conservative+Progressive is very easy to -understand: the extension modules are essentially completely isolated from -each other. This is in fact just the same as using pybind11 versions with -differing `"internals version" -`_ -in the past. While this is easy to understand, there is also no incremental -transition path between Classic and Progressive. - -The Conservative mode enables incremental transitions, but at the cost of -more complexity. Types wrapped in a Classic module are fully compatible with -a Conservative module. However, a type wrapped in a Conservative module is -compatible with a Classic module only if ``py::smart_holder`` is **not** used -(for that type). A type wrapped with ``py::smart_holder`` is incompatible with -a Classic module. This is an important pitfall to keep in mind: attempts to use -``py::smart_holder``-wrapped types in a Classic module will lead to undefined -runtime behavior, such as a SEGFAULT. This is a more general flavor of the -long-standing issue `#1138 `_, -often referred to as "holder mismatch". It is important to note that the -pybind11 smart_holder branch solves the smart-pointer interoperability issue, -but not the more general holder mismatch issue. β€” Unfortunately the existing -pybind11 internals do not track holder runtime type information, therefore -the holder mismatch issue cannot be solved in a fashion that would allow -an incremental transition, which is the whole point of the Conservative -mode. Please proceed with caution. (See `PR #2644 -`_ for background, which is -labeled with "abi break".) - -Another pitfall worth pointing out specifically, although it follows -from the previous: mixing base and derived classes between Classic and -Conservative modules means that neither the base nor the derived class can -use ``py::smart_holder``. - - Trampolines and std::unique_ptr ------------------------------- @@ -307,37 +101,10 @@ inherit from ``py::trampoline_self_life_support``, for example: ... }; -This is the only difference compared to Classic pybind11. A fairly +This is the only difference compared to classic pybind11. A fairly minimal but complete example is tests/test_class_sh_trampoline_unique_ptr.cpp. -Ideas for the long-term ------------------------ - -The macros are clearly an inconvenience in many situations. Highly -speculative: to avoid the need for the macros, a potential approach would -be to combine the Classic implementation (``type_caster_base``) with -the ``smart_holder_type_caster``, but this will probably be very messy and -not great as a long-term solution. The ``type_caster_base`` code is very -complex already. A more maintainable approach long-term could be to work -out and document a smart_holder-based solution for custom smart-pointers -in pybind11 version ``N``, then purge ``type_caster_base`` in version -``N+1``. #HelpAppreciated. - - -Testing of PRs against the smart_holder branch ----------------------------------------------- - -In the pybind11 GitHub Actions, PRs against the smart_holder branch are -automatically tested in both modes (Conservative, Progressive), with the -only difference that ``PYBIND11_USE_SMART_HOLDER_AS_DEFAULT`` is defined -for Progressive mode testing. - -For interactive testing, the ``PYBIND11_USE_SMART_HOLDER_AS_DEFAULT`` -define needs to be manually added to the cmake command. See -.github/workflows/ci_sh.yml for examples. - - Related links ============= @@ -353,4 +120,4 @@ Related links * Small `slide deck `_ presented in meeting with pybind11 maintainers on Feb 22, 2021. Slides 5 - and 6 show performance comparisons. + and 6 show performance comparisons. (These are outdated but probably not far off.) diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index 1044db94..74dc361e 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -331,6 +331,10 @@ struct type_record { /// Is the class inheritable from python classes? bool is_final : 1; +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + holder_enum_t holder_enum_v = holder_enum_t::undefined; +#endif + PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *) ) { auto *base_info = detail::get_type_info(base, false); if (!base_info) { diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 06dcfc37..656b7666 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -12,7 +12,6 @@ #include "detail/common.h" #include "detail/descr.h" -#include "detail/smart_holder_sfinae_hooks_only.h" #include "detail/type_caster_base.h" #include "detail/typeid.h" #include "pytypes.h" @@ -29,33 +28,17 @@ #include #include -#ifdef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT -# include "detail/smart_holder_type_casters.h" -#endif - PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_WARNING_DISABLE_MSVC(4127) PYBIND11_NAMESPACE_BEGIN(detail) -#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT -template -class type_caster_for_class_ : public type_caster_base {}; -#endif - template -class type_caster : public type_caster_for_class_ {}; - +class type_caster : public type_caster_base {}; template using make_caster = type_caster>; -template -struct type_uses_smart_holder_type_caster { - static constexpr bool value - = std::is_base_of>::value; -}; - // Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T template typename make_caster::template cast_op_type cast_op(make_caster &caster) { @@ -771,6 +754,7 @@ struct holder_helper { static auto get(const T &p) -> decltype(p.get()) { return p.get(); } }; +// SMART_HOLDER_BAKEIN_FOLLOW_ON: Rewrite comment, with reference to shared_ptr specialization. /// Type caster for holder types like std::shared_ptr, etc. /// The SFINAE hook is provided to help work around the current lack of support /// for smart-pointer interoperability. Please consider it an implementation @@ -852,12 +836,140 @@ struct copyable_holder_caster : public type_caster_base { holder_type holder; }; -#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + +template +struct copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled : std::true_type {}; + +// SMART_HOLDER_BAKEIN_FOLLOW_ON: Refactor copyable_holder_caster to reduce code duplication. +template +struct copyable_holder_caster< + type, + std::shared_ptr, + enable_if_t::value>> + : public type_caster_base { +public: + using base = type_caster_base; + static_assert(std::is_base_of>::value, + "Holder classes are only supported for custom types"); + using base::base; + using base::cast; + using base::typeinfo; + using base::value; + + bool load(handle src, bool convert) { + return base::template load_impl>>( + src, convert); + } + + explicit operator std::shared_ptr *() { + if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { + pybind11_fail("Passing `std::shared_ptr *` from Python to C++ is not supported " + "(inherently unsafe)."); + } + return std::addressof(shared_ptr_holder); + } + + explicit operator std::shared_ptr &() { + if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { + shared_ptr_holder = sh_load_helper.load_as_shared_ptr(value); + } + return shared_ptr_holder; + } + + static handle + cast(const std::shared_ptr &src, return_value_policy policy, handle parent) { + const auto *ptr = src.get(); + auto st = type_caster_base::src_and_type(ptr); + if (st.second == nullptr) { + return handle(); // no type info: error will be set already + } + if (st.second->holder_enum_v == detail::holder_enum_t::smart_holder) { + return smart_holder_type_caster_support::smart_holder_from_shared_ptr( + src, policy, parent, st); + } + return type_caster_base::cast_holder(ptr, &src); + } + + // This function will succeed even if the `responsible_parent` does not own the + // wrapped C++ object directly. + // It is the responsibility of the caller to ensure that the `responsible_parent` + // has a `keep_alive` relationship with the owner of the wrapped C++ object, or + // that the wrapped C++ object lives for the duration of the process. + static std::shared_ptr shared_ptr_with_responsible_parent(handle responsible_parent) { + copyable_holder_caster loader; + loader.load(responsible_parent, /*convert=*/false); + assert(loader.typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder); + return loader.sh_load_helper.load_as_shared_ptr(loader.value, responsible_parent); + } + +protected: + friend class type_caster_generic; + void check_holder_compat() { + if (typeinfo->default_holder) { + throw cast_error("Unable to load a custom holder type from a default-holder instance"); + } + } + + void load_value(value_and_holder &&v_h) { + if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { + sh_load_helper.loaded_v_h = v_h; + value = sh_load_helper.get_void_ptr_or_nullptr(); + return; + } + if (v_h.holder_constructed()) { + value = v_h.value_ptr(); + shared_ptr_holder = v_h.template holder>(); + return; + } + throw cast_error("Unable to cast from non-held to held instance (T& to Holder) " +# if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) + "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for " + "type information)"); +# else + "of type '" + + type_id>() + "''"); +# endif + } + + template , + detail::enable_if_t::value, int> = 0> + bool try_implicit_casts(handle, bool) { + return false; + } + + template , + detail::enable_if_t::value, int> = 0> + bool try_implicit_casts(handle src, bool convert) { + for (auto &cast : typeinfo->implicit_casts) { + copyable_holder_caster sub_caster(*cast.first); + if (sub_caster.load(src, convert)) { + value = cast.second(sub_caster.value); + if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { + sh_load_helper.loaded_v_h = sub_caster.sh_load_helper.loaded_v_h; + } else { + shared_ptr_holder + = std::shared_ptr(sub_caster.shared_ptr_holder, (type *) value); + } + return true; + } + } + return false; + } + + static bool try_direct_conversions(handle) { return false; } + + std::shared_ptr shared_ptr_holder; + smart_holder_type_caster_support::load_helper> sh_load_helper; // Const2Mutbl +}; + +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + /// Specialize for the common std::shared_ptr, so users don't need to template class type_caster> : public copyable_holder_caster> {}; -#endif +// SMART_HOLDER_BAKEIN_FOLLOW_ON: Rewrite comment, with reference to unique_ptr specialization. /// Type caster for holder types like std::unique_ptr. /// Please consider the SFINAE hook an implementation detail, as explained /// in the comment for the copyable_holder_caster. @@ -873,11 +985,115 @@ struct move_only_holder_caster { static constexpr auto name = type_caster_base::name; }; -#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + +template +struct move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled : std::true_type {}; + +// SMART_HOLDER_BAKEIN_FOLLOW_ON: Refactor move_only_holder_caster to reduce code duplication. +template +struct move_only_holder_caster< + type, + std::unique_ptr, + enable_if_t::value>> + : public type_caster_base { +public: + using base = type_caster_base; + static_assert(std::is_base_of>::value, + "Holder classes are only supported for custom types"); + using base::base; + using base::cast; + using base::typeinfo; + using base::value; + + static handle + cast(std::unique_ptr &&src, return_value_policy policy, handle parent) { + auto *ptr = src.get(); + auto st = type_caster_base::src_and_type(ptr); + if (st.second == nullptr) { + return handle(); // no type info: error will be set already + } + if (st.second->holder_enum_v == detail::holder_enum_t::smart_holder) { + return smart_holder_type_caster_support::smart_holder_from_unique_ptr( + std::move(src), policy, parent, st); + } + return type_caster_generic::cast(st.first, + return_value_policy::take_ownership, + {}, + st.second, + nullptr, + nullptr, + std::addressof(src)); + } + + static handle + cast(const std::unique_ptr &src, return_value_policy policy, handle parent) { + if (!src) { + return none().release(); + } + if (policy == return_value_policy::automatic) { + policy = return_value_policy::reference_internal; + } + if (policy != return_value_policy::reference_internal) { + throw cast_error("Invalid return_value_policy for unique_ptr&"); + } + return type_caster_base::cast(src.get(), policy, parent); + } + + bool load(handle src, bool convert) { + return base::template load_impl< + move_only_holder_caster>>(src, convert); + } + + void load_value(value_and_holder &&v_h) { + if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { + sh_load_helper.loaded_v_h = v_h; + sh_load_helper.loaded_v_h.type = typeinfo; + value = sh_load_helper.get_void_ptr_or_nullptr(); + return; + } + pybind11_fail( + "Passing `std::unique_ptr` from Python to C++ requires `py::classh` (with T = " + + clean_type_id(typeinfo->cpptype->name()) + ")"); + } + + template + using cast_op_type = std::unique_ptr; + + explicit operator std::unique_ptr() { + if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { + return sh_load_helper.template load_as_unique_ptr(value); + } + pybind11_fail("Expected to be UNREACHABLE: " __FILE__ ":" PYBIND11_TOSTRING(__LINE__)); + } + + bool try_implicit_casts(handle src, bool convert) { + for (auto &cast : typeinfo->implicit_casts) { + move_only_holder_caster sub_caster(*cast.first); + if (sub_caster.load(src, convert)) { + value = cast.second(sub_caster.value); + if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { + sh_load_helper.loaded_v_h = sub_caster.sh_load_helper.loaded_v_h; + } else { + pybind11_fail("Expected to be UNREACHABLE: " __FILE__ + ":" PYBIND11_TOSTRING(__LINE__)); + } + return true; + } + } + return false; + } + + static bool try_direct_conversions(handle) { return false; } + + smart_holder_type_caster_support::load_helper> sh_load_helper; // Const2Mutbl +}; + +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + template class type_caster> : public move_only_holder_caster> {}; -#endif template using type_caster_holder = conditional_t::value, @@ -906,10 +1122,16 @@ struct always_construct_holder { template struct is_holder_type : std::is_base_of, detail::type_caster> {}; -// Specialization for always-supported unique_ptr holders: + +// Specializations for always-supported holders: template struct is_holder_type> : std::true_type {}; +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +template +struct is_holder_type : std::true_type {}; +#endif + #ifdef PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION // See PR #4888 // This leads to compilation errors if a specialization is missing. @@ -1141,7 +1363,6 @@ template using cast_is_temporary_value_reference = bool_constant<(std::is_reference::value || std::is_pointer::value) && !std::is_base_of>::value - && !type_uses_smart_holder_type_caster>::value && !std::is_same, void>::value>; // When a value returned from a C++ function is being cast back to Python, we almost always want to @@ -1155,9 +1376,7 @@ struct return_value_policy_override { template struct return_value_policy_override< Return, - detail::enable_if_t>::value - || type_uses_smart_holder_type_caster>::value, - void>> { + detail::enable_if_t>::value, void>> { static return_value_policy policy(return_value_policy p) { return !std::is_lvalue_reference::value && !std::is_pointer::value ? return_value_policy::move @@ -1857,10 +2076,8 @@ PYBIND11_NAMESPACE_END(detail) template handle type::handle_of() { - static_assert( - detail::any_of>, - detail::type_uses_smart_holder_type_caster>::value, - "py::type::of only supports the case where T is a registered C++ types."); + static_assert(std::is_base_of>::value, + "py::type::of only supports the case where T is a registered C++ types."); return detail::get_type_handle(typeid(T), true); } @@ -1869,7 +2086,7 @@ handle type::handle_of() { PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) \ namespace detail { \ template <> \ - class type_caster<__VA_ARGS__> : public type_caster_for_class_<__VA_ARGS__> {}; \ + class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> {}; \ } \ PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 71a98f06..b18dc850 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -9,13 +9,13 @@ #pragma once -#define PYBIND11_VERSION_MAJOR 2 -#define PYBIND11_VERSION_MINOR 14 +#define PYBIND11_VERSION_MAJOR 3 +#define PYBIND11_VERSION_MINOR 0 #define PYBIND11_VERSION_PATCH 0.dev1 // Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html // Additional convention: 0xD = dev -#define PYBIND11_VERSION_HEX 0x020E00D1 +#define PYBIND11_VERSION_HEX 0x030000D1 // Define some generic pybind11 helper macros for warning management. // diff --git a/include/pybind11/detail/init.h b/include/pybind11/detail/init.h index 72caf1c1..af8ec6dd 100644 --- a/include/pybind11/detail/init.h +++ b/include/pybind11/detail/init.h @@ -10,7 +10,7 @@ #pragma once #include "class.h" -#include "smart_holder_sfinae_hooks_only.h" +#include "using_smart_holder.h" PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) @@ -156,9 +156,7 @@ void construct(value_and_holder &v_h, Alias *alias_ptr, bool) { // holder. This also handles types like std::shared_ptr and std::unique_ptr where T is a // derived type (through those holder's implicit conversion from derived class holder // constructors). -template >::value, int> - = 0> +template >::value, int> = 0> void construct(value_and_holder &v_h, Holder holder, bool need_alias) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias); auto *ptr = holder_helper>::get(holder); @@ -200,10 +198,18 @@ void construct(value_and_holder &v_h, Alias &&result, bool) { v_h.value_ptr() = new Alias(std::move(result)); } +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + +template +smart_holder init_smart_holder_from_unique_ptr(std::unique_ptr &&unq_ptr, + bool void_cast_raw_ptr) { + void *void_ptr = void_cast_raw_ptr ? static_cast(unq_ptr.get()) : nullptr; + return smart_holder::from_unique_ptr(std::move(unq_ptr), void_ptr); +} + template >, - detail::enable_if_t>::value, int> - = 0> + detail::enable_if_t>::value, int> = 0> void construct(value_and_holder &v_h, std::unique_ptr, D> &&unq_ptr, bool need_alias) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias); auto *ptr = unq_ptr.get(); @@ -217,7 +223,7 @@ void construct(value_and_holder &v_h, std::unique_ptr, D> &&unq_ptr, // trampoline Python object alive. For types that don't inherit from enable_shared_from_this // it does not matter if void_cast_raw_ptr is true or false, therefore it's not necessary // to also inspect the type. - auto smhldr = type_caster>::smart_holder_from_unique_ptr( + auto smhldr = init_smart_holder_from_unique_ptr( std::move(unq_ptr), /*void_cast_raw_ptr*/ Class::has_alias && is_alias(ptr)); v_h.value_ptr() = ptr; v_h.type->init_instance(v_h.inst, &smhldr); @@ -225,22 +231,19 @@ void construct(value_and_holder &v_h, std::unique_ptr, D> &&unq_ptr, template >, - detail::enable_if_t>::value, int> - = 0> + detail::enable_if_t>::value, int> = 0> void construct(value_and_holder &v_h, std::unique_ptr, D> &&unq_ptr, bool /*need_alias*/) { auto *ptr = unq_ptr.get(); no_nullptr(ptr); - auto smhldr = type_caster>::smart_holder_from_unique_ptr( - std::move(unq_ptr), /*void_cast_raw_ptr*/ true); + auto smhldr + = init_smart_holder_from_unique_ptr(std::move(unq_ptr), /*void_cast_raw_ptr*/ true); v_h.value_ptr() = ptr; v_h.type->init_instance(v_h.inst, &smhldr); } -template >::value, int> - = 0> +template >::value, int> = 0> void construct(value_and_holder &v_h, std::shared_ptr> &&shd_ptr, bool need_alias) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias); auto *ptr = shd_ptr.get(); @@ -249,24 +252,24 @@ void construct(value_and_holder &v_h, std::shared_ptr> &&shd_ptr, boo throw type_error("pybind11::init(): construction failed: returned std::shared_ptr pointee " "is not an alias instance"); } - auto smhldr = type_caster>::smart_holder_from_shared_ptr(shd_ptr); + auto smhldr = smart_holder::from_shared_ptr(shd_ptr); v_h.value_ptr() = ptr; v_h.type->init_instance(v_h.inst, &smhldr); } -template >::value, int> - = 0> +template >::value, int> = 0> void construct(value_and_holder &v_h, std::shared_ptr> &&shd_ptr, bool /*need_alias*/) { auto *ptr = shd_ptr.get(); no_nullptr(ptr); - auto smhldr = type_caster>::smart_holder_from_shared_ptr(shd_ptr); + auto smhldr = smart_holder::from_shared_ptr(shd_ptr); v_h.value_ptr() = ptr; v_h.type->init_instance(v_h.inst, &smhldr); } +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + // Implementing class for py::init<...>() template struct constructor { diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index a72e7c0e..d8b5c6b3 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -16,7 +16,6 @@ #endif #include "../pytypes.h" -#include "smart_holder_sfinae_hooks_only.h" #include #include @@ -37,7 +36,9 @@ /// further ABI-incompatible changes may be made before the ABI is officially /// changed to the new version. #ifndef PYBIND11_INTERNALS_VERSION -# if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER) +# if PYBIND11_VERSION_MAJOR >= 3 +# define PYBIND11_INTERNALS_VERSION 6 +# elif PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER) // Version bump for Python 3.12+, before first 3.12 beta release. // Version bump for MSVC piggy-backed on PR #4779. See comments there. # define PYBIND11_INTERNALS_VERSION 5 @@ -237,6 +238,20 @@ struct internals { } }; +#if PYBIND11_INTERNALS_VERSION >= 6 + +# define PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + +enum class holder_enum_t : uint8_t { + undefined, + std_unique_ptr, // Default, lacking interop with std::shared_ptr. + std_shared_ptr, // Lacking interop with std::unique_ptr. + smart_holder, // Full std::unique_ptr / std::shared_ptr interop. + custom_holder, +}; + +#endif + /// Additional type information which does not fit into the PyTypeObject. /// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`. struct type_info { @@ -260,9 +275,14 @@ struct type_info { /* True if there is no multiple inheritance in this type's inheritance tree */ bool simple_ancestors : 1; /* for base vs derived holder_type checks */ + // SMART_HOLDER_BAKEIN_FOLLOW_ON: Remove default_holder member here and + // produce better error messages in the places where it is currently used. bool default_holder : 1; /* true if this is a type registered with py::module_local */ bool module_local : 1; +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + holder_enum_t holder_enum_v = holder_enum_t::undefined; +#endif }; /// On MSVC, debug and release builds are not ABI-compatible! @@ -322,25 +342,15 @@ struct type_info { # define PYBIND11_INTERNALS_KIND "" #endif -/// See README_smart_holder.rst: -/// Classic / Conservative / Progressive cross-module compatibility -#ifndef PYBIND11_INTERNALS_SH_DEF -# if defined(PYBIND11_USE_SMART_HOLDER_AS_DEFAULT) -# define PYBIND11_INTERNALS_SH_DEF "_sh_def" -# else -# define PYBIND11_INTERNALS_SH_DEF "" -# endif -#endif - #define PYBIND11_INTERNALS_ID \ "__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \ - PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \ - PYBIND11_BUILD_TYPE PYBIND11_INTERNALS_SH_DEF "__" + PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB \ + PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" #define PYBIND11_MODULE_LOCAL_ID \ "__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \ - PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \ - PYBIND11_BUILD_TYPE PYBIND11_INTERNALS_SH_DEF "__" + PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB \ + PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" /// Each module locally stores a pointer to the `internals` data. The data /// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`. diff --git a/include/pybind11/detail/smart_holder_sfinae_hooks_only.h b/include/pybind11/detail/smart_holder_sfinae_hooks_only.h deleted file mode 100644 index ca57cb61..00000000 --- a/include/pybind11/detail/smart_holder_sfinae_hooks_only.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2021 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 -#include - -#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT -// #define PYBIND11_USE_SMART_HOLDER_AS_DEFAULT -// Currently the main purpose of this switch is to enable non-intrusive comprehensive testing. If -// and when `smart_holder` will actually become the released default is currently open. In the -// meantime, the full functionality is easily available by using `py::classh`, which is just a -// handy shortcut for `py::class_` (see `pybind11/smart_holder.h`). Classes -// wrapped in this way are fully compatible with everything existing. -#endif - -PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) -PYBIND11_NAMESPACE_BEGIN(detail) - -template -struct is_smart_holder_type : std::false_type {}; - -// Tag to be used as base class, inspected by type_uses_smart_holder_type_caster test. -struct smart_holder_type_caster_base_tag {}; - -template -struct type_uses_smart_holder_type_caster; - -// Simple helpers that may eventually be a better fit for another header file: - -template -struct is_std_unique_ptr : std::false_type {}; -template -struct is_std_unique_ptr> : std::true_type {}; - -template -struct is_std_shared_ptr : std::false_type {}; -template -struct is_std_shared_ptr> : std::true_type {}; - -PYBIND11_NAMESPACE_END(detail) -PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/include/pybind11/detail/smart_holder_type_casters.h b/include/pybind11/detail/smart_holder_type_casters.h deleted file mode 100644 index 98eab589..00000000 --- a/include/pybind11/detail/smart_holder_type_casters.h +++ /dev/null @@ -1,1046 +0,0 @@ -// Copyright (c) 2021 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 "../gil.h" -#include "../pytypes.h" -#include "../trampoline_self_life_support.h" -#include "common.h" -#include "descr.h" -#include "dynamic_raw_ptr_cast_if_possible.h" -#include "internals.h" -#include "smart_holder_poc.h" -#include "smart_holder_sfinae_hooks_only.h" -#include "type_caster_base.h" -#include "typeid.h" - -#include -#include -#include -#include -#include -#include -#include - -PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) - -using pybindit::memory::smart_holder; - -PYBIND11_NAMESPACE_BEGIN(detail) - -template <> -struct is_smart_holder_type : std::true_type {}; - -// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code. -inline void register_instance(instance *self, void *valptr, const type_info *tinfo); -inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo); - -// The modified_type_caster_generic_load_impl could replace type_caster_generic::load_impl but not -// vice versa. The main difference is that the original code only propagates a reference to the -// held value, while the modified implementation propagates value_and_holder. -class modified_type_caster_generic_load_impl { -public: - PYBIND11_NOINLINE explicit modified_type_caster_generic_load_impl( - const std::type_info &type_info) - : typeinfo(get_type_info(type_info)), cpptype(&type_info) {} - - explicit modified_type_caster_generic_load_impl(const type_info *typeinfo = nullptr) - : typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) {} - - bool load(handle src, bool convert) { - return load_impl(src, convert); - } - - // Base methods for generic caster; there are overridden in copyable_holder_caster - void load_value_and_holder(value_and_holder &&v_h) { - if (!v_h.holder_constructed()) { - // This is needed for old-style __init__. - // type_caster_generic::load_value BEGIN - auto *&vptr = v_h.value_ptr(); - // Lazy allocation for unallocated values: - if (vptr == nullptr) { - // Lazy allocation for unallocated values: - const auto *type = v_h.type ? v_h.type : typeinfo; - if (type->operator_new) { - vptr = type->operator_new(type->type_size); - } else { -#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912) - if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) { - vptr = ::operator new(type->type_size, std::align_val_t(type->type_align)); - } else { - vptr = ::operator new(type->type_size); - } -#else - vptr = ::operator new(type->type_size); -#endif - } - } - // type_caster_generic::load_value END - } - loaded_v_h = v_h; - loaded_v_h.type = typeinfo; - } - - bool try_implicit_casts(handle src, bool convert) { - for (const auto &cast : typeinfo->implicit_casts) { - modified_type_caster_generic_load_impl sub_caster(*cast.first); - if (sub_caster.load(src, convert)) { - if (loaded_v_h_cpptype != nullptr) { - pybind11_fail("smart_holder_type_casters: try_implicit_casts failure."); - } - loaded_v_h = sub_caster.loaded_v_h; - loaded_v_h_cpptype = cast.first; - // the sub_caster is being discarded, so steal its vector - implicit_casts = std::move(sub_caster.implicit_casts); - implicit_casts.emplace_back(cast.second); - return true; - } - } - return false; - } - - bool try_direct_conversions(handle src) { - for (auto &converter : *typeinfo->direct_conversions) { - if (converter(src.ptr(), unowned_void_ptr_from_direct_conversion)) { - return true; - } - } - return false; - } - - PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) { - std::unique_ptr loader( - new modified_type_caster_generic_load_impl(ti)); - if (loader->load(src, false)) { - // Trick to work with the existing pybind11 internals. - // The void pointer is immediately captured in a new unique_ptr in - // try_load_foreign_module_local. If this assumption is violated sanitizers - // will most likely flag a leak (verified to be the case with ASAN). - return static_cast(loader.release()); - } - return nullptr; - } - - /// Try to load with foreign typeinfo, if available. Used when there is no - /// native typeinfo, or when the native one wasn't able to produce a value. - PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) { - constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID; - const auto pytype = type::handle_of(src); - if (!hasattr(pytype, local_key)) { - return false; - } - - type_info *foreign_typeinfo = reinterpret_borrow(getattr(pytype, local_key)); - // Only consider this foreign loader if actually foreign and is a loader of the correct cpp - // type - if (foreign_typeinfo->module_local_load == &local_load - || (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype))) { - return false; - } - - void *foreign_loader_void_ptr - = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo); - if (foreign_loader_void_ptr != nullptr) { - auto foreign_loader = std::unique_ptr( - static_cast(foreign_loader_void_ptr)); - // Magic number intentionally hard-coded for simplicity and maximum robustness. - if (foreign_loader->local_load_safety_guard != 1887406645) { - pybind11_fail("smart_holder_type_casters: Unexpected local_load_safety_guard," - " possibly due to py::class_ holder mixup."); - } - if (loaded_v_h_cpptype != nullptr) { - pybind11_fail("smart_holder_type_casters: try_load_foreign_module_local failure."); - } - loaded_v_h = foreign_loader->loaded_v_h; - loaded_v_h_cpptype = foreign_loader->loaded_v_h_cpptype; - // SMART_HOLDER_WIP: should this be a copy or move? - implicit_casts = foreign_loader->implicit_casts; - return true; - } - return false; - } - - // Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant - // bits of code between here and copyable_holder_caster where the two classes need different - // logic (without having to resort to virtual inheritance). - template - PYBIND11_NOINLINE bool load_impl(handle src, bool convert) { - if (!src) { - return false; - } - if (!typeinfo) { - return try_load_foreign_module_local(src); - } - - auto &this_ = static_cast(*this); - - PyTypeObject *srctype = Py_TYPE(src.ptr()); - - // Case 1: If src is an exact type match for the target type then we can reinterpret_cast - // the instance's value pointer to the target type: - if (srctype == typeinfo->type) { - this_.load_value_and_holder( - reinterpret_cast(src.ptr())->get_value_and_holder()); - return true; - } - // Case 2: We have a derived class - if (PyType_IsSubtype(srctype, typeinfo->type)) { - const auto &bases = all_type_info(srctype); // subtype bases - bool no_cpp_mi = typeinfo->simple_type; - - // Case 2a: the python type is a Python-inherited derived class that inherits from just - // one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of - // the right type and we can use reinterpret_cast. - // (This is essentially the same as case 2b, but because not using multiple inheritance - // is extremely common, we handle it specially to avoid the loop iterator and type - // pointer lookup overhead) - if (bases.size() == 1 && (no_cpp_mi || bases.front()->type == typeinfo->type)) { - this_.load_value_and_holder( - reinterpret_cast(src.ptr())->get_value_and_holder()); - loaded_v_h_cpptype = bases.front()->cpptype; - reinterpret_cast_deemed_ok = true; - return true; - } - // Case 2b: the python type inherits from multiple C++ bases. Check the bases to see - // if we can find an exact match (or, for a simple C++ type, an inherited match); if - // so, we can safely reinterpret_cast to the relevant pointer. - if (bases.size() > 1) { - for (auto *base : bases) { - if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type) - : base->type == typeinfo->type) { - this_.load_value_and_holder( - reinterpret_cast(src.ptr())->get_value_and_holder(base)); - loaded_v_h_cpptype = base->cpptype; - reinterpret_cast_deemed_ok = true; - return true; - } - } - } - - // Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type - // match in the registered bases, above, so try implicit casting (needed for proper C++ - // casting when MI is involved). - if (this_.try_implicit_casts(src, convert)) { - return true; - } - } - - // Perform an implicit conversion - if (convert) { - for (const auto &converter : typeinfo->implicit_conversions) { - auto temp = reinterpret_steal(converter(src.ptr(), typeinfo->type)); - if (load_impl(temp, false)) { - loader_life_support::add_patient(temp); - return true; - } - } - if (this_.try_direct_conversions(src)) { - return true; - } - } - - // Failed to match local typeinfo. Try again with global. - if (typeinfo->module_local) { - if (auto *gtype = get_global_type_info(*typeinfo->cpptype)) { - typeinfo = gtype; - return load(src, false); - } - } - - // Global typeinfo has precedence over foreign module_local - if (try_load_foreign_module_local(src)) { - return true; - } - - if (src.is_none()) { - // Defer accepting None to other overloads (if we aren't in convert mode): - if (!convert) { - return false; - } - loaded_v_h = value_and_holder(); - return true; - } - return false; - } - - const type_info *typeinfo = nullptr; - const std::type_info *cpptype = nullptr; - void *unowned_void_ptr_from_direct_conversion = nullptr; - const std::type_info *loaded_v_h_cpptype = nullptr; - std::vector implicit_casts; - value_and_holder loaded_v_h; - bool reinterpret_cast_deemed_ok = false; - // Magic number intentionally hard-coded, to guard against class_ holder mixups. - // Ideally type_caster_generic would have a similar guard, but this requires a change there. - // SMART_HOLDER_WIP: If it is decided that this guard is useful long term, potentially - // set/reset this value in ctor/dtor, mark volatile. - std::size_t local_load_safety_guard = 1887406645; // 32-bit compatible value for portability. -}; - -struct smart_holder_type_caster_class_hooks : smart_holder_type_caster_base_tag { - static decltype(&modified_type_caster_generic_load_impl::local_load) - get_local_load_function_ptr() { - return &modified_type_caster_generic_load_impl::local_load; - } - - using holder_type = pybindit::memory::smart_holder; - - template - static bool try_initialization_using_shared_from_this(holder_type *, WrappedType *, ...) { - return false; - } - - // Adopting existing approach used by type_caster_base, although it leads to somewhat fuzzy - // ownership semantics: if we detected via shared_from_this that a shared_ptr exists already, - // it is reused, irrespective of the return_value_policy in effect. - // "SomeBaseOfWrappedType" is needed because std::enable_shared_from_this is not necessarily a - // direct base of WrappedType. - template - static bool try_initialization_using_shared_from_this( - holder_type *uninitialized_location, - WrappedType *value_ptr_w_t, - const std::enable_shared_from_this *) { - auto shd_ptr = std::dynamic_pointer_cast( - detail::try_get_shared_from_this(value_ptr_w_t)); - if (!shd_ptr) { - return false; - } - // Note: inst->owned ignored. - new (uninitialized_location) holder_type(holder_type::from_shared_ptr(shd_ptr)); - return true; - } - - template - static void init_instance_for_type(detail::instance *inst, const void *holder_const_void_ptr) { - // Need for const_cast is a consequence of the type_info::init_instance type: - // void (*init_instance)(instance *, const void *); - auto *holder_void_ptr = const_cast(holder_const_void_ptr); - - auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(WrappedType))); - if (!v_h.instance_registered()) { - register_instance(inst, v_h.value_ptr(), v_h.type); - v_h.set_instance_registered(); - } - auto *uninitialized_location = std::addressof(v_h.holder()); - auto *value_ptr_w_t = v_h.value_ptr(); - bool pointee_depends_on_holder_owner - = dynamic_raw_ptr_cast_if_possible(value_ptr_w_t) != nullptr; - if (holder_void_ptr) { - // Note: inst->owned ignored. - auto *holder_ptr = static_cast(holder_void_ptr); - new (uninitialized_location) holder_type(std::move(*holder_ptr)); - } else if (!try_initialization_using_shared_from_this( - uninitialized_location, value_ptr_w_t, value_ptr_w_t)) { - if (inst->owned) { - new (uninitialized_location) holder_type(holder_type::from_raw_ptr_take_ownership( - value_ptr_w_t, /*void_cast_raw_ptr*/ pointee_depends_on_holder_owner)); - } else { - new (uninitialized_location) - holder_type(holder_type::from_raw_ptr_unowned(value_ptr_w_t)); - } - } - v_h.holder().pointee_depends_on_holder_owner - = pointee_depends_on_holder_owner; - v_h.set_holder_constructed(); - } - - template - static smart_holder smart_holder_from_unique_ptr(std::unique_ptr &&unq_ptr, - bool void_cast_raw_ptr) { - void *void_ptr = void_cast_raw_ptr ? static_cast(unq_ptr.get()) : nullptr; - return pybindit::memory::smart_holder::from_unique_ptr(std::move(unq_ptr), void_ptr); - } - - template - static smart_holder smart_holder_from_shared_ptr(std::shared_ptr shd_ptr) { - return pybindit::memory::smart_holder::from_shared_ptr(shd_ptr); - } -}; - -struct shared_ptr_parent_life_support { - PyObject *parent; - explicit shared_ptr_parent_life_support(PyObject *parent) : parent{parent} { - Py_INCREF(parent); - } - // NOLINTNEXTLINE(readability-make-member-function-const) - void operator()(void *) { - gil_scoped_acquire gil; - Py_DECREF(parent); - } -}; - -struct shared_ptr_trampoline_self_life_support { - PyObject *self; - explicit shared_ptr_trampoline_self_life_support(instance *inst) - : self{reinterpret_cast(inst)} { - gil_scoped_acquire gil; - Py_INCREF(self); - } - // NOLINTNEXTLINE(readability-make-member-function-const) - void operator()(void *) { - gil_scoped_acquire gil; - Py_DECREF(self); - } -}; - -template ::value, int>::type = 0> -inline std::unique_ptr unique_with_deleter(T *raw_ptr, std::unique_ptr &&deleter) { - if (deleter == nullptr) { - return std::unique_ptr(raw_ptr); - } - return std::unique_ptr(raw_ptr, std::move(*deleter)); -} - -template ::value, int>::type = 0> -inline std::unique_ptr unique_with_deleter(T *raw_ptr, std::unique_ptr &&deleter) { - if (deleter == nullptr) { - pybind11_fail("smart_holder_type_casters: deleter is not default constructible and no" - " instance available to return."); - } - return std::unique_ptr(raw_ptr, std::move(*deleter)); -} - -template -struct smart_holder_type_caster_load { - using holder_type = pybindit::memory::smart_holder; - - bool load(handle src, bool convert) { - static_assert(type_uses_smart_holder_type_caster::value, "Internal consistency error."); - load_impl = modified_type_caster_generic_load_impl(typeid(T)); - if (!load_impl.load(src, convert)) { - return false; - } - return true; - } - - T *loaded_as_raw_ptr_unowned() const { - void *void_ptr = load_impl.unowned_void_ptr_from_direct_conversion; - if (void_ptr == nullptr) { - if (have_holder()) { - throw_if_uninitialized_or_disowned_holder(typeid(T)); - void_ptr = holder().template as_raw_ptr_unowned(); - } else if (load_impl.loaded_v_h.vh != nullptr) { - void_ptr = load_impl.loaded_v_h.value_ptr(); - } - if (void_ptr == nullptr) { - return nullptr; - } - } - return convert_type(void_ptr); - } - - T &loaded_as_lvalue_ref() const { - T *raw_ptr = loaded_as_raw_ptr_unowned(); - if (raw_ptr == nullptr) { - throw reference_cast_error(); - } - return *raw_ptr; - } - - std::shared_ptr make_shared_ptr_with_responsible_parent(handle parent) const { - return std::shared_ptr(loaded_as_raw_ptr_unowned(), - shared_ptr_parent_life_support(parent.ptr())); - } - - std::shared_ptr loaded_as_shared_ptr(handle responsible_parent = nullptr) const { - if (load_impl.unowned_void_ptr_from_direct_conversion != nullptr) { - if (responsible_parent) { - return make_shared_ptr_with_responsible_parent(responsible_parent); - } - throw cast_error("Unowned pointer from direct conversion cannot be converted to a" - " std::shared_ptr."); - } - if (!have_holder()) { - return nullptr; - } - throw_if_uninitialized_or_disowned_holder(typeid(T)); - holder_type &hld = holder(); - hld.ensure_is_not_disowned("loaded_as_shared_ptr"); - if (hld.vptr_is_using_noop_deleter) { - if (responsible_parent) { - return make_shared_ptr_with_responsible_parent(responsible_parent); - } - throw std::runtime_error("Non-owning holder (loaded_as_shared_ptr)."); - } - auto *void_raw_ptr = hld.template as_raw_ptr_unowned(); - auto *type_raw_ptr = convert_type(void_raw_ptr); - if (hld.pointee_depends_on_holder_owner) { - auto *vptr_gd_ptr = std::get_deleter(hld.vptr); - if (vptr_gd_ptr != nullptr) { - std::shared_ptr released_ptr = vptr_gd_ptr->released_ptr.lock(); - if (released_ptr) { - return std::shared_ptr(released_ptr, type_raw_ptr); - } - std::shared_ptr to_be_released( - type_raw_ptr, - shared_ptr_trampoline_self_life_support(load_impl.loaded_v_h.inst)); - vptr_gd_ptr->released_ptr = to_be_released; - return to_be_released; - } - auto *sptsls_ptr = std::get_deleter(hld.vptr); - if (sptsls_ptr != nullptr) { - // This code is reachable only if there are multiple registered_instances for the - // same pointee. - if (reinterpret_cast(load_impl.loaded_v_h.inst) == sptsls_ptr->self) { - pybind11_fail("smart_holder_type_casters loaded_as_shared_ptr failure: " - "load_impl.loaded_v_h.inst == sptsls_ptr->self"); - } - } - if (sptsls_ptr != nullptr - || !pybindit::memory::type_has_shared_from_this(type_raw_ptr)) { - return std::shared_ptr( - type_raw_ptr, - shared_ptr_trampoline_self_life_support(load_impl.loaded_v_h.inst)); - } - if (hld.vptr_is_external_shared_ptr) { - pybind11_fail("smart_holder_type_casters loaded_as_shared_ptr failure: not " - "implemented: trampoline-self-life-support for external shared_ptr " - "to type inheriting from std::enable_shared_from_this."); - } - pybind11_fail("smart_holder_type_casters: loaded_as_shared_ptr failure: internal " - "inconsistency."); - } - std::shared_ptr void_shd_ptr = hld.template as_shared_ptr(); - return std::shared_ptr(void_shd_ptr, type_raw_ptr); - } - - template - std::unique_ptr loaded_as_unique_ptr(const char *context = "loaded_as_unique_ptr") { - if (load_impl.unowned_void_ptr_from_direct_conversion != nullptr) { - throw cast_error("Unowned pointer from direct conversion cannot be converted to a" - " std::unique_ptr."); - } - if (!have_holder()) { - return unique_with_deleter(nullptr, std::unique_ptr()); - } - throw_if_uninitialized_or_disowned_holder(typeid(T)); - throw_if_instance_is_currently_owned_by_shared_ptr(); - holder().ensure_is_not_disowned(context); - holder().template ensure_compatible_rtti_uqp_del(context); - holder().ensure_use_count_1(context); - auto raw_void_ptr = holder().template as_raw_ptr_unowned(); - - void *value_void_ptr = load_impl.loaded_v_h.value_ptr(); - if (value_void_ptr != raw_void_ptr) { - pybind11_fail("smart_holder_type_casters: loaded_as_unique_ptr failure:" - " value_void_ptr != raw_void_ptr"); - } - - // SMART_HOLDER_WIP: MISSING: Safety checks for type conversions - // (T must be polymorphic or meet certain other conditions). - T *raw_type_ptr = convert_type(raw_void_ptr); - - auto *self_life_support - = dynamic_raw_ptr_cast_if_possible(raw_type_ptr); - if (self_life_support == nullptr && holder().pointee_depends_on_holder_owner) { - throw value_error("Alias class (also known as trampoline) does not inherit from " - "py::trampoline_self_life_support, therefore the ownership of this " - "instance cannot safely be transferred to C++."); - } - - // Temporary variable to store the extracted deleter in. - std::unique_ptr extracted_deleter; - - auto *gd = std::get_deleter(holder().vptr); - if (gd && gd->use_del_fun) { // Note the ensure_compatible_rtti_uqp_del() call above. - // In smart_holder_poc, a custom deleter is always stored in a guarded delete. - // The guarded delete's std::function actually points at the - // custom_deleter type, so we can verify it is of the custom deleter type and - // finally extract its deleter. - using custom_deleter_D = pybindit::memory::custom_deleter; - const auto &custom_deleter_ptr = gd->del_fun.template target(); - assert(custom_deleter_ptr != nullptr); - // Now that we have confirmed the type of the deleter matches the desired return - // value we can extract the function. - extracted_deleter = std::unique_ptr(new D(std::move(custom_deleter_ptr->deleter))); - } - - // Critical transfer-of-ownership section. This must stay together. - if (self_life_support != nullptr) { - holder().disown(); - } else { - holder().release_ownership(); - } - auto result = unique_with_deleter(raw_type_ptr, std::move(extracted_deleter)); - if (self_life_support != nullptr) { - self_life_support->activate_life_support(load_impl.loaded_v_h); - } else { - load_impl.loaded_v_h.value_ptr() = nullptr; - deregister_instance( - load_impl.loaded_v_h.inst, value_void_ptr, load_impl.loaded_v_h.type); - } - // Critical section end. - - return result; - } - - // This function will succeed even if the `responsible_parent` does not own the - // wrapped C++ object directly. - // It is the responsibility of the caller to ensure that the `responsible_parent` - // has a `keep_alive` relationship with the owner of the wrapped C++ object, or - // that the wrapped C++ object lives for the duration of the process. - static std::shared_ptr shared_ptr_from_python(handle responsible_parent) { - smart_holder_type_caster_load loader; - loader.load(responsible_parent, false); - return loader.loaded_as_shared_ptr(responsible_parent); - } - -private: - modified_type_caster_generic_load_impl load_impl; - - bool have_holder() const { - return load_impl.loaded_v_h.vh != nullptr && load_impl.loaded_v_h.holder_constructed(); - } - - holder_type &holder() const { return load_impl.loaded_v_h.holder(); } - - // have_holder() must be true or this function will fail. - void throw_if_uninitialized_or_disowned_holder(const char *typeid_name) const { - static const std::string missing_value_msg = "Missing value for wrapped C++ type `"; - if (!holder().is_populated) { - throw value_error(missing_value_msg + clean_type_id(typeid_name) - + "`: Python instance is uninitialized."); - } - if (!holder().has_pointee()) { - throw value_error(missing_value_msg + clean_type_id(typeid_name) - + "`: Python instance was disowned."); - } - } - - void throw_if_uninitialized_or_disowned_holder(const std::type_info &type_info) const { - throw_if_uninitialized_or_disowned_holder(type_info.name()); - } - - // have_holder() must be true or this function will fail. - void throw_if_instance_is_currently_owned_by_shared_ptr() const { - auto vptr_gd_ptr = std::get_deleter(holder().vptr); - if (vptr_gd_ptr != nullptr && !vptr_gd_ptr->released_ptr.expired()) { - throw value_error("Python instance is currently owned by a std::shared_ptr."); - } - } - - T *convert_type(void *void_ptr) const { - if (void_ptr != nullptr && load_impl.loaded_v_h_cpptype != nullptr - && !load_impl.reinterpret_cast_deemed_ok && !load_impl.implicit_casts.empty()) { - for (auto implicit_cast : load_impl.implicit_casts) { - void_ptr = implicit_cast(void_ptr); - } - } - return static_cast(void_ptr); - } -}; - -// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code. -struct make_constructor : private type_caster_base { // Any type, nothing special about int. - using type_caster_base::Constructor; - using type_caster_base::make_copy_constructor; - using type_caster_base::make_move_constructor; -}; - -template -struct smart_holder_type_caster : smart_holder_type_caster_load, - smart_holder_type_caster_class_hooks { - static constexpr auto name = const_name(); - - // static handle cast(T, ...) - // is redundant (leads to ambiguous overloads). - - static handle cast(T &&src, return_value_policy /*policy*/, handle parent) { - // type_caster_base BEGIN - return cast(std::addressof(src), return_value_policy::move, parent); - // type_caster_base END - } - - static handle cast(T const &src, return_value_policy policy, handle parent) { - // type_caster_base BEGIN - if (policy == return_value_policy::automatic - || policy == return_value_policy::automatic_reference) { - policy = return_value_policy::copy; - } - return cast(std::addressof(src), policy, parent); - // type_caster_base END - } - - static handle cast(T &src, return_value_policy policy, handle parent) { - return cast(const_cast(src), policy, parent); // Mutbl2Const - } - - static handle cast(T const *src, return_value_policy policy, handle parent) { - auto st = type_caster_base::src_and_type(src); - return cast_const_raw_ptr( // Originally type_caster_generic::cast. - st.first, - policy, - parent, - st.second, - make_constructor::make_copy_constructor(src), - make_constructor::make_move_constructor(src)); - } - - static handle cast(T *src, return_value_policy policy, handle parent) { - return cast(const_cast(src), policy, parent); // Mutbl2Const - } - - template - using cast_op_type = conditional_t< - std::is_same, T const *>::value, - T const *, - conditional_t, T *>::value, - T *, - conditional_t::value, T const &, T &>>>; - - // The const operators here prove that the existing type_caster mechanism already supports - // const-correctness. However, fully implementing const-correctness inside this type_caster - // is still a major project. - // NOLINTNEXTLINE(google-explicit-constructor) - operator T const &() const { - return const_cast(this)->loaded_as_lvalue_ref(); - } - // NOLINTNEXTLINE(google-explicit-constructor) - operator T const *() const { - return const_cast(this)->loaded_as_raw_ptr_unowned(); - } - // NOLINTNEXTLINE(google-explicit-constructor) - operator T &() { return this->loaded_as_lvalue_ref(); } - // NOLINTNEXTLINE(google-explicit-constructor) - operator T *() { return this->loaded_as_raw_ptr_unowned(); } - - // Originally type_caster_generic::cast. - PYBIND11_NOINLINE static handle cast_const_raw_ptr(const void *_src, - return_value_policy policy, - handle parent, - const detail::type_info *tinfo, - void *(*copy_constructor)(const void *), - void *(*move_constructor)(const void *), - const void *existing_holder = nullptr) { - if (!tinfo) { // no type info: error will be set already - return handle(); - } - - void *src = const_cast(_src); - if (src == nullptr) { - return none().release(); - } - - if (handle existing_inst = find_registered_python_instance(src, tinfo)) { - return existing_inst; - } - - auto inst = reinterpret_steal(make_new_instance(tinfo->type)); - auto *wrapper = reinterpret_cast(inst.ptr()); - wrapper->owned = false; - void *&valueptr = values_and_holders(wrapper).begin()->value_ptr(); - - switch (policy) { - case return_value_policy::automatic: - case return_value_policy::take_ownership: - valueptr = src; - wrapper->owned = true; - break; - - case return_value_policy::automatic_reference: - case return_value_policy::reference: - valueptr = src; - wrapper->owned = false; - break; - - case return_value_policy::copy: - if (copy_constructor) { - valueptr = copy_constructor(src); - } else { -#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) - throw cast_error("return_value_policy = copy, but type is " - "non-copyable! (#define PYBIND11_DETAILED_ERROR_MESSAGES or " - "compile in debug mode for details)"); -#else - std::string type_name(tinfo->cpptype->name()); - detail::clean_type_id(type_name); - throw cast_error("return_value_policy = copy, but type " + type_name - + " is non-copyable!"); -#endif - } - wrapper->owned = true; - break; - - case return_value_policy::move: - if (move_constructor) { - valueptr = move_constructor(src); - } else if (copy_constructor) { - valueptr = copy_constructor(src); - } else { -#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) - throw cast_error("return_value_policy = move, but type is neither " - "movable nor copyable! " - "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in " - "debug mode for details)"); -#else - std::string type_name(tinfo->cpptype->name()); - detail::clean_type_id(type_name); - throw cast_error("return_value_policy = move, but type " + type_name - + " is neither movable nor copyable!"); -#endif - } - wrapper->owned = true; - break; - - case return_value_policy::reference_internal: - valueptr = src; - wrapper->owned = false; - keep_alive_impl(inst, parent); - break; - - default: - throw cast_error("unhandled return_value_policy: should not happen!"); - } - - tinfo->init_instance(wrapper, existing_holder); - - return inst.release(); - } -}; - -template -struct smart_holder_type_caster> : smart_holder_type_caster_load, - smart_holder_type_caster_class_hooks { - static constexpr auto name = const_name(); - - static handle cast(const std::shared_ptr &src, return_value_policy policy, handle parent) { - switch (policy) { - case return_value_policy::automatic: - case return_value_policy::automatic_reference: - break; - case return_value_policy::take_ownership: - throw cast_error("Invalid return_value_policy for shared_ptr (take_ownership)."); - case return_value_policy::copy: - case return_value_policy::move: - break; - case return_value_policy::reference: - throw cast_error("Invalid return_value_policy for shared_ptr (reference)."); - case return_value_policy::reference_internal: - break; - } - if (!src) { - return none().release(); - } - - auto src_raw_ptr = src.get(); - auto st = type_caster_base::src_and_type(src_raw_ptr); - if (st.second == nullptr) { - return handle(); // no type info: error will be set already - } - - void *src_raw_void_ptr = static_cast(src_raw_ptr); - const detail::type_info *tinfo = st.second; - if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) { - // SMART_HOLDER_WIP: MISSING: Enforcement of consistency with existing smart_holder. - // SMART_HOLDER_WIP: MISSING: keep_alive. - return existing_inst; - } - - auto inst = reinterpret_steal(make_new_instance(tinfo->type)); - auto *inst_raw_ptr = reinterpret_cast(inst.ptr()); - inst_raw_ptr->owned = true; - void *&valueptr = values_and_holders(inst_raw_ptr).begin()->value_ptr(); - valueptr = src_raw_void_ptr; - - auto smhldr = pybindit::memory::smart_holder::from_shared_ptr( - std::shared_ptr(src, const_cast(st.first))); - tinfo->init_instance(inst_raw_ptr, static_cast(&smhldr)); - - if (policy == return_value_policy::reference_internal) { - keep_alive_impl(inst, parent); - } - - return inst.release(); - } - - template - using cast_op_type = std::shared_ptr; - - // NOLINTNEXTLINE(google-explicit-constructor) - operator std::shared_ptr() { return this->loaded_as_shared_ptr(); } -}; - -template -struct smart_holder_type_caster> : smart_holder_type_caster_load, - smart_holder_type_caster_class_hooks { - static constexpr auto name = const_name(); - - static handle - cast(const std::shared_ptr &src, return_value_policy policy, handle parent) { - return smart_holder_type_caster>::cast( - std::const_pointer_cast(src), // Const2Mutbl - policy, - parent); - } - - template - using cast_op_type = std::shared_ptr; - - // NOLINTNEXTLINE(google-explicit-constructor) - operator std::shared_ptr() { return this->loaded_as_shared_ptr(); } // Mutbl2Const -}; - -template -struct smart_holder_type_caster> : smart_holder_type_caster_load, - smart_holder_type_caster_class_hooks { - static constexpr auto name = const_name(); - - static handle cast(std::unique_ptr &&src, return_value_policy policy, handle parent) { - if (policy != return_value_policy::automatic - && policy != return_value_policy::automatic_reference - && policy != return_value_policy::reference_internal - && policy != return_value_policy::move) { - // SMART_HOLDER_WIP: IMPROVABLE: Error message. - throw cast_error("Invalid return_value_policy for unique_ptr."); - } - if (!src) { - return none().release(); - } - - auto st = type_caster_base::src_and_type(src.get()); - if (st.second == nullptr) { - return handle(); // no type info: error will be set already - } - - void *src_raw_void_ptr = const_cast(st.first); - const detail::type_info *tinfo = st.second; - if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) { - auto *self_life_support - = dynamic_raw_ptr_cast_if_possible(src.get()); - if (self_life_support != nullptr) { - value_and_holder &v_h = self_life_support->v_h; - if (v_h.inst != nullptr && v_h.vh != nullptr) { - auto &holder = v_h.holder(); - if (!holder.is_disowned) { - pybind11_fail("smart_holder_type_casters: unexpected " - "smart_holder.is_disowned failure."); - } - // Critical transfer-of-ownership section. This must stay together. - self_life_support->deactivate_life_support(); - holder.reclaim_disowned(); - (void) src.release(); - // Critical section end. - return existing_inst; - } - } - throw cast_error("Invalid unique_ptr: another instance owns this pointer already."); - } - - auto inst = reinterpret_steal(make_new_instance(tinfo->type)); - auto *inst_raw_ptr = reinterpret_cast(inst.ptr()); - inst_raw_ptr->owned = true; - void *&valueptr = values_and_holders(inst_raw_ptr).begin()->value_ptr(); - valueptr = src_raw_void_ptr; - - if (static_cast(src.get()) == src_raw_void_ptr) { - // This is a multiple-inheritance situation that is incompatible with the current - // shared_from_this handling (see PR #3023). - // SMART_HOLDER_WIP: IMPROVABLE: Is there a better solution? - src_raw_void_ptr = nullptr; - } - auto smhldr - = pybindit::memory::smart_holder::from_unique_ptr(std::move(src), src_raw_void_ptr); - tinfo->init_instance(inst_raw_ptr, static_cast(&smhldr)); - - if (policy == return_value_policy::reference_internal) { - keep_alive_impl(inst, parent); - } - - return inst.release(); - } - static handle - cast(const std::unique_ptr &src, return_value_policy policy, handle parent) { - if (!src) { - return none().release(); - } - if (policy == return_value_policy::automatic) { - policy = return_value_policy::reference_internal; - } - if (policy != return_value_policy::reference_internal) { - throw cast_error("Invalid return_value_policy for unique_ptr&"); - } - return smart_holder_type_caster::cast(src.get(), policy, parent); - } - - template - using cast_op_type = std::unique_ptr; - - // NOLINTNEXTLINE(google-explicit-constructor) - operator std::unique_ptr() { return this->template loaded_as_unique_ptr(); } -}; - -template -struct smart_holder_type_caster> - : smart_holder_type_caster_load, smart_holder_type_caster_class_hooks { - static constexpr auto name = const_name(); - - static handle - cast(std::unique_ptr &&src, return_value_policy policy, handle parent) { - return smart_holder_type_caster>::cast( - std::unique_ptr(const_cast(src.release()), - std::move(src.get_deleter())), // Const2Mutbl - policy, - parent); - } - - template - using cast_op_type = std::unique_ptr; - - // NOLINTNEXTLINE(google-explicit-constructor) - operator std::unique_ptr() { return this->template loaded_as_unique_ptr(); } -}; - -#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT - -# define PYBIND11_SMART_HOLDER_TYPE_CASTERS(...) \ - namespace pybind11 { \ - namespace detail { \ - template <> \ - class type_caster<__VA_ARGS__> : public smart_holder_type_caster<__VA_ARGS__> {}; \ - template <> \ - class type_caster> \ - : public smart_holder_type_caster> {}; \ - template <> \ - class type_caster> \ - : public smart_holder_type_caster> {}; \ - template \ - class type_caster> \ - : public smart_holder_type_caster> {}; \ - template \ - class type_caster> \ - : public smart_holder_type_caster> {}; \ - } \ - } -#else - -# define PYBIND11_SMART_HOLDER_TYPE_CASTERS(...) - -template -class type_caster_for_class_ : public smart_holder_type_caster {}; - -template -class type_caster_for_class_> - : public smart_holder_type_caster> {}; - -template -class type_caster_for_class_> - : public smart_holder_type_caster> {}; - -template -class type_caster_for_class_> - : public smart_holder_type_caster> {}; - -template -class type_caster_for_class_> - : public smart_holder_type_caster> {}; - -#endif - -PYBIND11_NAMESPACE_END(detail) -PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 481b7c78..c2706878 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -9,11 +9,15 @@ #pragma once +#include "../gil.h" #include "../pytypes.h" +#include "../trampoline_self_life_support.h" #include "common.h" #include "descr.h" +#include "dynamic_raw_ptr_cast_if_possible.h" #include "internals.h" #include "typeid.h" +#include "using_smart_holder.h" #include "value_and_holder.h" #include @@ -468,6 +472,359 @@ inline PyThreadState *get_thread_state_unchecked() { void keep_alive_impl(handle nurse, handle patient); inline PyObject *make_new_instance(PyTypeObject *type); +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + +// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code. +inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo); + +PYBIND11_NAMESPACE_BEGIN(smart_holder_type_caster_support) + +struct value_and_holder_helper { + value_and_holder loaded_v_h; + + bool have_holder() const { + return loaded_v_h.vh != nullptr && loaded_v_h.holder_constructed(); + } + + smart_holder &holder() const { return loaded_v_h.holder(); } + + void throw_if_uninitialized_or_disowned_holder(const char *typeid_name) const { + static const std::string missing_value_msg = "Missing value for wrapped C++ type `"; + if (!holder().is_populated) { + throw value_error(missing_value_msg + clean_type_id(typeid_name) + + "`: Python instance is uninitialized."); + } + if (!holder().has_pointee()) { + throw value_error(missing_value_msg + clean_type_id(typeid_name) + + "`: Python instance was disowned."); + } + } + + void throw_if_uninitialized_or_disowned_holder(const std::type_info &type_info) const { + throw_if_uninitialized_or_disowned_holder(type_info.name()); + } + + // have_holder() must be true or this function will fail. + void throw_if_instance_is_currently_owned_by_shared_ptr() const { + auto *vptr_gd_ptr = std::get_deleter(holder().vptr); + if (vptr_gd_ptr != nullptr && !vptr_gd_ptr->released_ptr.expired()) { + throw value_error("Python instance is currently owned by a std::shared_ptr."); + } + } + + void *get_void_ptr_or_nullptr() const { + if (have_holder()) { + auto &hld = holder(); + if (hld.is_populated && hld.has_pointee()) { + return hld.template as_raw_ptr_unowned(); + } + } + return nullptr; + } +}; + +template +handle smart_holder_from_unique_ptr(std::unique_ptr &&src, + return_value_policy policy, + handle parent, + const std::pair &st) { + if (policy == return_value_policy::copy) { + throw cast_error("return_value_policy::copy is invalid for unique_ptr."); + } + if (!src) { + return none().release(); + } + void *src_raw_void_ptr = const_cast(st.first); + assert(st.second != nullptr); + const detail::type_info *tinfo = st.second; + if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) { + auto *self_life_support + = dynamic_raw_ptr_cast_if_possible(src.get()); + if (self_life_support != nullptr) { + value_and_holder &v_h = self_life_support->v_h; + if (v_h.inst != nullptr && v_h.vh != nullptr) { + auto &holder = v_h.holder(); + if (!holder.is_disowned) { + pybind11_fail("smart_holder_from_unique_ptr: unexpected " + "smart_holder.is_disowned failure."); + } + // Critical transfer-of-ownership section. This must stay together. + self_life_support->deactivate_life_support(); + holder.reclaim_disowned(); + (void) src.release(); + // Critical section end. + return existing_inst; + } + } + throw cast_error("Invalid unique_ptr: another instance owns this pointer already."); + } + + auto inst = reinterpret_steal(make_new_instance(tinfo->type)); + auto *inst_raw_ptr = reinterpret_cast(inst.ptr()); + inst_raw_ptr->owned = true; + void *&valueptr = values_and_holders(inst_raw_ptr).begin()->value_ptr(); + valueptr = src_raw_void_ptr; + + if (static_cast(src.get()) == src_raw_void_ptr) { + // This is a multiple-inheritance situation that is incompatible with the current + // shared_from_this handling (see PR #3023). + // SMART_HOLDER_WIP: IMPROVABLE: Is there a better solution? + src_raw_void_ptr = nullptr; + } + auto smhldr = smart_holder::from_unique_ptr(std::move(src), src_raw_void_ptr); + tinfo->init_instance(inst_raw_ptr, static_cast(&smhldr)); + + if (policy == return_value_policy::reference_internal) { + keep_alive_impl(inst, parent); + } + + return inst.release(); +} + +template +handle smart_holder_from_unique_ptr(std::unique_ptr &&src, + return_value_policy policy, + handle parent, + const std::pair &st) { + return smart_holder_from_unique_ptr( + std::unique_ptr(const_cast(src.release()), + std::move(src.get_deleter())), // Const2Mutbl + policy, + parent, + st); +} + +template +handle smart_holder_from_shared_ptr(const std::shared_ptr &src, + return_value_policy policy, + handle parent, + const std::pair &st) { + switch (policy) { + case return_value_policy::automatic: + case return_value_policy::automatic_reference: + break; + case return_value_policy::take_ownership: + throw cast_error("Invalid return_value_policy for shared_ptr (take_ownership)."); + case return_value_policy::copy: + case return_value_policy::move: + break; + case return_value_policy::reference: + throw cast_error("Invalid return_value_policy for shared_ptr (reference)."); + case return_value_policy::reference_internal: + break; + } + if (!src) { + return none().release(); + } + + auto src_raw_ptr = src.get(); + assert(st.second != nullptr); + void *src_raw_void_ptr = static_cast(src_raw_ptr); + const detail::type_info *tinfo = st.second; + if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) { + // SMART_HOLDER_WIP: MISSING: Enforcement of consistency with existing smart_holder. + // SMART_HOLDER_WIP: MISSING: keep_alive. + return existing_inst; + } + + auto inst = reinterpret_steal(make_new_instance(tinfo->type)); + auto *inst_raw_ptr = reinterpret_cast(inst.ptr()); + inst_raw_ptr->owned = true; + void *&valueptr = values_and_holders(inst_raw_ptr).begin()->value_ptr(); + valueptr = src_raw_void_ptr; + + auto smhldr + = smart_holder::from_shared_ptr(std::shared_ptr(src, const_cast(st.first))); + tinfo->init_instance(inst_raw_ptr, static_cast(&smhldr)); + + if (policy == return_value_policy::reference_internal) { + keep_alive_impl(inst, parent); + } + + return inst.release(); +} + +template +handle smart_holder_from_shared_ptr(const std::shared_ptr &src, + return_value_policy policy, + handle parent, + const std::pair &st) { + return smart_holder_from_shared_ptr(std::const_pointer_cast(src), // Const2Mutbl + policy, + parent, + st); +} + +struct shared_ptr_parent_life_support { + PyObject *parent; + explicit shared_ptr_parent_life_support(PyObject *parent) : parent{parent} { + Py_INCREF(parent); + } + // NOLINTNEXTLINE(readability-make-member-function-const) + void operator()(void *) { + gil_scoped_acquire gil; + Py_DECREF(parent); + } +}; + +struct shared_ptr_trampoline_self_life_support { + PyObject *self; + explicit shared_ptr_trampoline_self_life_support(instance *inst) + : self{reinterpret_cast(inst)} { + gil_scoped_acquire gil; + Py_INCREF(self); + } + // NOLINTNEXTLINE(readability-make-member-function-const) + void operator()(void *) { + gil_scoped_acquire gil; + Py_DECREF(self); + } +}; + +template ::value, int>::type = 0> +inline std::unique_ptr unique_with_deleter(T *raw_ptr, std::unique_ptr &&deleter) { + if (deleter == nullptr) { + return std::unique_ptr(raw_ptr); + } + return std::unique_ptr(raw_ptr, std::move(*deleter)); +} + +template ::value, int>::type = 0> +inline std::unique_ptr unique_with_deleter(T *raw_ptr, std::unique_ptr &&deleter) { + if (deleter == nullptr) { + pybind11_fail("smart_holder_type_casters: deleter is not default constructible and no" + " instance available to return."); + } + return std::unique_ptr(raw_ptr, std::move(*deleter)); +} + +template +struct load_helper : value_and_holder_helper { + static std::shared_ptr make_shared_ptr_with_responsible_parent(T *raw_ptr, handle parent) { + return std::shared_ptr(raw_ptr, shared_ptr_parent_life_support(parent.ptr())); + } + + std::shared_ptr load_as_shared_ptr(void *void_raw_ptr, + handle responsible_parent = nullptr) const { + if (!have_holder()) { + return nullptr; + } + throw_if_uninitialized_or_disowned_holder(typeid(T)); + smart_holder &hld = holder(); + hld.ensure_is_not_disowned("load_as_shared_ptr"); + if (hld.vptr_is_using_noop_deleter) { + if (responsible_parent) { + return make_shared_ptr_with_responsible_parent(static_cast(void_raw_ptr), + responsible_parent); + } + throw std::runtime_error("Non-owning holder (load_as_shared_ptr)."); + } + auto *type_raw_ptr = static_cast(void_raw_ptr); + if (hld.pointee_depends_on_holder_owner) { + auto *vptr_gd_ptr = std::get_deleter(hld.vptr); + if (vptr_gd_ptr != nullptr) { + std::shared_ptr released_ptr = vptr_gd_ptr->released_ptr.lock(); + if (released_ptr) { + return std::shared_ptr(released_ptr, type_raw_ptr); + } + std::shared_ptr to_be_released( + type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst)); + vptr_gd_ptr->released_ptr = to_be_released; + return to_be_released; + } + auto *sptsls_ptr = std::get_deleter(hld.vptr); + if (sptsls_ptr != nullptr) { + // This code is reachable only if there are multiple registered_instances for the + // same pointee. + if (reinterpret_cast(loaded_v_h.inst) == sptsls_ptr->self) { + pybind11_fail("smart_holder_type_caster_support load_as_shared_ptr failure: " + "loaded_v_h.inst == sptsls_ptr->self"); + } + } + if (sptsls_ptr != nullptr + || !pybindit::memory::type_has_shared_from_this(type_raw_ptr)) { + return std::shared_ptr( + type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst)); + } + if (hld.vptr_is_external_shared_ptr) { + pybind11_fail("smart_holder_type_casters load_as_shared_ptr failure: not " + "implemented: trampoline-self-life-support for external shared_ptr " + "to type inheriting from std::enable_shared_from_this."); + } + pybind11_fail( + "smart_holder_type_casters: load_as_shared_ptr failure: internal inconsistency."); + } + std::shared_ptr void_shd_ptr = hld.template as_shared_ptr(); + return std::shared_ptr(void_shd_ptr, type_raw_ptr); + } + + template + std::unique_ptr load_as_unique_ptr(void *raw_void_ptr, + const char *context = "load_as_unique_ptr") { + if (!have_holder()) { + return unique_with_deleter(nullptr, std::unique_ptr()); + } + throw_if_uninitialized_or_disowned_holder(typeid(T)); + throw_if_instance_is_currently_owned_by_shared_ptr(); + holder().ensure_is_not_disowned(context); + holder().template ensure_compatible_rtti_uqp_del(context); + holder().ensure_use_count_1(context); + + T *raw_type_ptr = static_cast(raw_void_ptr); + + auto *self_life_support + = dynamic_raw_ptr_cast_if_possible(raw_type_ptr); + if (self_life_support == nullptr && holder().pointee_depends_on_holder_owner) { + throw value_error("Alias class (also known as trampoline) does not inherit from " + "py::trampoline_self_life_support, therefore the ownership of this " + "instance cannot safely be transferred to C++."); + } + + // Temporary variable to store the extracted deleter in. + std::unique_ptr extracted_deleter; + + auto *gd = std::get_deleter(holder().vptr); + if (gd && gd->use_del_fun) { // Note the ensure_compatible_rtti_uqp_del() call above. + // In smart_holder_poc, a custom deleter is always stored in a guarded delete. + // The guarded delete's std::function actually points at the + // custom_deleter type, so we can verify it is of the custom deleter type and + // finally extract its deleter. + using custom_deleter_D = pybindit::memory::custom_deleter; + const auto &custom_deleter_ptr = gd->del_fun.template target(); + assert(custom_deleter_ptr != nullptr); + // Now that we have confirmed the type of the deleter matches the desired return + // value we can extract the function. + extracted_deleter = std::unique_ptr(new D(std::move(custom_deleter_ptr->deleter))); + } + + // Critical transfer-of-ownership section. This must stay together. + if (self_life_support != nullptr) { + holder().disown(); + } else { + holder().release_ownership(); + } + auto result = unique_with_deleter(raw_type_ptr, std::move(extracted_deleter)); + if (self_life_support != nullptr) { + self_life_support->activate_life_support(loaded_v_h); + } else { + void *value_void_ptr = loaded_v_h.value_ptr(); + loaded_v_h.value_ptr() = nullptr; + deregister_instance(loaded_v_h.inst, value_void_ptr, loaded_v_h.type); + } + // Critical section end. + + return result; + } +}; + +PYBIND11_NAMESPACE_END(smart_holder_type_caster_support) + +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + class type_caster_generic { public: PYBIND11_NOINLINE explicit type_caster_generic(const std::type_info &type_info) @@ -572,6 +929,17 @@ class type_caster_generic { // Base methods for generic caster; there are overridden in copyable_holder_caster void load_value(value_and_holder &&v_h) { +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { + smart_holder_type_caster_support::value_and_holder_helper v_h_helper; + v_h_helper.loaded_v_h = v_h; + if (v_h_helper.have_holder()) { + v_h_helper.throw_if_uninitialized_or_disowned_holder(cpptype->name()); + value = v_h_helper.holder().template as_raw_ptr_unowned(); + return; + } + } +#endif auto *&vptr = v_h.value_ptr(); // Lazy allocation for unallocated values: if (vptr == nullptr) { diff --git a/include/pybind11/detail/using_smart_holder.h b/include/pybind11/detail/using_smart_holder.h new file mode 100644 index 00000000..c47b691d --- /dev/null +++ b/include/pybind11/detail/using_smart_holder.h @@ -0,0 +1,33 @@ +// Copyright (c) 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 "internals.h" + +#include + +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +# include "smart_holder_poc.h" +#endif + +PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +using pybindit::memory::smart_holder; +#endif + +PYBIND11_NAMESPACE_BEGIN(detail) + +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +template +using is_smart_holder = std::is_same; +#else +template +struct is_smart_holder : std::false_type {}; +#endif + +PYBIND11_NAMESPACE_END(detail) +PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index b7c0e281..0f2b72cf 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -11,8 +11,9 @@ #pragma once #include "detail/class.h" +#include "detail/dynamic_raw_ptr_cast_if_possible.h" #include "detail/init.h" -#include "detail/smart_holder_sfinae_hooks_only.h" +#include "detail/using_smart_holder.h" #include "attr.h" #include "gil.h" #include "gil_safe_call_once.h" @@ -1394,8 +1395,7 @@ class generic_type : public object { public: PYBIND11_OBJECT_DEFAULT(generic_type, object, PyType_Check) protected: - void initialize(const type_record &rec, - void *(*type_caster_module_local_load)(PyObject *, const type_info *) ) { + void initialize(const type_record &rec) { if (rec.scope && hasattr(rec.scope, "__dict__") && rec.scope.attr("__dict__").contains(rec.name)) { pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec.name) @@ -1424,6 +1424,9 @@ class generic_type : public object { tinfo->simple_ancestors = true; tinfo->default_holder = rec.default_holder; tinfo->module_local = rec.module_local; +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + tinfo->holder_enum_v = rec.holder_enum_v; +#endif with_internals([&](internals &internals) { auto tindex = std::type_index(*rec.type); @@ -1450,7 +1453,7 @@ class generic_type : public object { if (rec.module_local) { // Stash the local typeinfo and loader so that external modules can access it. - tinfo->module_local_load = type_caster_module_local_load; + tinfo->module_local_load = &type_caster_generic::local_load; setattr(m_ptr, PYBIND11_MODULE_LOCAL_ID, capsule(tinfo)); } } @@ -1586,49 +1589,7 @@ auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)( return pmf; } -#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT - -template -using default_holder_type = std::unique_ptr; - -# ifndef PYBIND11_SH_AVL -# define PYBIND11_SH_AVL(...) std::shared_ptr<__VA_ARGS__> // "Smart_Holder if AVaiLable" -// -------- std::shared_ptr(...) -- same length by design, to not disturb the indentation -// of existing code. -# endif - -# define PYBIND11_SH_DEF(...) std::shared_ptr<__VA_ARGS__> // "Smart_Holder if DEFault" -// -------- std::shared_ptr(...) -- same length by design, to not disturb the indentation -// of existing code. - -# define PYBIND11_TYPE_CASTER_BASE_HOLDER(T, ...) - -#else - -template -using default_holder_type = smart_holder; - -# ifndef PYBIND11_SH_AVL -# define PYBIND11_SH_AVL(...) ::pybind11::smart_holder // "Smart_Holder if AVaiLable" -// -------- std::shared_ptr(...) -- same length by design, to not disturb the indentation -// of existing code. -# endif - -# define PYBIND11_SH_DEF(...) ::pybind11::smart_holder // "Smart_Holder if DEFault" - -// This define could be hidden away inside detail/smart_holder_type_casters.h, but is kept here -// for clarity. -# define PYBIND11_TYPE_CASTER_BASE_HOLDER(T, ...) \ - namespace pybind11 { \ - namespace detail { \ - template <> \ - class type_caster : public type_caster_base {}; \ - template <> \ - class type_caster<__VA_ARGS__> : public type_caster_holder {}; \ - } \ - } - -#endif +PYBIND11_NAMESPACE_BEGIN(detail) // Helper for the property_cpp_function static member functions below. // The only purpose of these functions is to support .def_readonly & .def_readwrite. @@ -1637,8 +1598,7 @@ using default_holder_type = smart_holder; // against accidents. As a side-effect, it also explains why the syntactical overhead for // perfect forwarding is not needed. template -using must_be_member_function_pointer - = detail::enable_if_t::value, int>; +using must_be_member_function_pointer = enable_if_t::value, int>; // Note that property_cpp_function is intentionally in the main pybind11 namespace, // because user-defined specializations could be useful. @@ -1647,9 +1607,9 @@ using must_be_member_function_pointer // getter and setter functions. // WARNING: This classic implementation can lead to dangling pointers for raw pointer members. // See test_ptr() in tests/test_class_sh_property.py -// This implementation works as-is (and safely) for smart_holder std::shared_ptr members. -template -struct property_cpp_function { +// However, this implementation works as-is (and safely) for smart_holder std::shared_ptr members. +template +struct property_cpp_function_classic { template = 0> static cpp_function readonly(PM pm, const handle &hdl) { return cpp_function([pm](const T &c) -> const D & { return c.*pm; }, is_method(hdl)); @@ -1666,31 +1626,54 @@ struct property_cpp_function { } }; -// smart_holder specializations for raw pointer members. +PYBIND11_NAMESPACE_END(detail) + +template +struct property_cpp_function : detail::property_cpp_function_classic {}; + +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + +PYBIND11_NAMESPACE_BEGIN(detail) + +template +struct both_t_and_d_use_type_caster_base : std::false_type {}; + +// `T` is assumed to be equivalent to `intrinsic_t`. +// `D` is may or may not be equivalent to `intrinsic_t`. +template +struct both_t_and_d_use_type_caster_base< + T, + D, + enable_if_t, type_caster>, + std::is_base_of>, make_caster>>::value>> + : std::true_type {}; + +// Specialization for raw pointer members, using smart_holder if that is the class_ holder, +// or falling back to the classic implementation if not. // WARNING: Like the classic implementation, this implementation can lead to dangling pointers. // See test_ptr() in tests/test_class_sh_property.py // However, the read functions return a shared_ptr to the member, emulating the PyCLIF approach: // https://github.com/google/clif/blob/c371a6d4b28d25d53a16e6d2a6d97305fb1be25a/clif/python/instance.h#L233 // This prevents disowning of the Python object owning the raw pointer member. template -struct property_cpp_function< - T, - D, - detail::enable_if_t, - detail::type_uses_smart_holder_type_caster, - std::is_pointer>::value>> { - +struct property_cpp_function_sh_raw_ptr_member { using drp = typename std::remove_pointer::type; template = 0> static cpp_function readonly(PM pm, const handle &hdl) { - return cpp_function( - [pm](handle c_hdl) -> std::shared_ptr { - std::shared_ptr c_sp = detail::type_caster::shared_ptr_from_python(c_hdl); - D ptr = (*c_sp).*pm; - return std::shared_ptr(c_sp, ptr); - }, - is_method(hdl)); + type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true); + if (tinfo->holder_enum_v == holder_enum_t::smart_holder) { + return cpp_function( + [pm](handle c_hdl) -> std::shared_ptr { + std::shared_ptr c_sp + = type_caster>::shared_ptr_with_responsible_parent( + c_hdl); + D ptr = (*c_sp).*pm; + return std::shared_ptr(c_sp, ptr); + }, + is_method(hdl)); + } + return property_cpp_function_classic::readonly(pm, hdl); } template = 0> @@ -1700,81 +1683,95 @@ struct property_cpp_function< template = 0> static cpp_function write(PM pm, const handle &hdl) { - return cpp_function([pm](T &c, D value) { c.*pm = std::forward(value); }, - is_method(hdl)); + type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true); + if (tinfo->holder_enum_v == holder_enum_t::smart_holder) { + return cpp_function([pm](T &c, D value) { c.*pm = std::forward(std::move(value)); }, + is_method(hdl)); + } + return property_cpp_function_classic::write(pm, hdl); } }; -// smart_holder specializations for members held by-value. +// Specialization for members held by-value, using smart_holder if that is the class_ holder, +// or falling back to the classic implementation if not. // The read functions return a shared_ptr to the member, emulating the PyCLIF approach: // https://github.com/google/clif/blob/c371a6d4b28d25d53a16e6d2a6d97305fb1be25a/clif/python/instance.h#L233 // This prevents disowning of the Python object owning the member. template -struct property_cpp_function< - T, - D, - detail::enable_if_t, - detail::type_uses_smart_holder_type_caster, - detail::none_of, - detail::is_std_unique_ptr, - detail::is_std_shared_ptr>>::value>> { - +struct property_cpp_function_sh_member_held_by_value { template = 0> static cpp_function readonly(PM pm, const handle &hdl) { - return cpp_function( - [pm](handle c_hdl) -> std::shared_ptr::type> { - std::shared_ptr c_sp = detail::type_caster::shared_ptr_from_python(c_hdl); - return std::shared_ptr::type>(c_sp, &(c_sp.get()->*pm)); - }, - is_method(hdl)); + type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true); + if (tinfo->holder_enum_v == holder_enum_t::smart_holder) { + return cpp_function( + [pm](handle c_hdl) -> std::shared_ptr::type> { + std::shared_ptr c_sp + = type_caster>::shared_ptr_with_responsible_parent( + c_hdl); + return std::shared_ptr::type>(c_sp, + &(c_sp.get()->*pm)); + }, + is_method(hdl)); + } + return property_cpp_function_classic::readonly(pm, hdl); } template = 0> static cpp_function read(PM pm, const handle &hdl) { - return cpp_function( - [pm](handle c_hdl) -> std::shared_ptr { - std::shared_ptr c_sp = detail::type_caster::shared_ptr_from_python(c_hdl); - return std::shared_ptr(c_sp, &(c_sp.get()->*pm)); - }, - is_method(hdl)); + type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true); + if (tinfo->holder_enum_v == holder_enum_t::smart_holder) { + return cpp_function( + [pm](handle c_hdl) -> std::shared_ptr { + std::shared_ptr c_sp + = type_caster>::shared_ptr_with_responsible_parent( + c_hdl); + return std::shared_ptr(c_sp, &(c_sp.get()->*pm)); + }, + is_method(hdl)); + } + return property_cpp_function_classic::read(pm, hdl); } template = 0> static cpp_function write(PM pm, const handle &hdl) { - return cpp_function([pm](T &c, const D &value) { c.*pm = value; }, is_method(hdl)); + type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true); + if (tinfo->holder_enum_v == holder_enum_t::smart_holder) { + return cpp_function([pm](T &c, const D &value) { c.*pm = value; }, is_method(hdl)); + } + return property_cpp_function_classic::write(pm, hdl); } }; -// smart_holder specializations for std::unique_ptr members. +// Specialization for std::unique_ptr members, using smart_holder if that is the class_ holder, +// or falling back to the classic implementation if not. // read disowns the member unique_ptr. // write disowns the passed Python object. // readonly is disabled (static_assert) because there is no safe & intuitive way to make the member // accessible as a Python object without disowning the member unique_ptr. A .def_readonly disowning // the unique_ptr member is deemed highly prone to misunderstandings. template -struct property_cpp_function< - T, - D, - detail::enable_if_t, - detail::is_std_unique_ptr, - detail::type_uses_smart_holder_type_caster>::value>> { - +struct property_cpp_function_sh_unique_ptr_member { template = 0> static cpp_function readonly(PM, const handle &) { - static_assert(!detail::is_std_unique_ptr::value, + static_assert(!is_instantiation::value, "def_readonly cannot be used for std::unique_ptr members."); return cpp_function{}; // Unreachable. } template = 0> static cpp_function read(PM pm, const handle &hdl) { - return cpp_function( - [pm](handle c_hdl) -> D { - std::shared_ptr c_sp = detail::type_caster::shared_ptr_from_python(c_hdl); - return D{std::move(c_sp.get()->*pm)}; - }, - is_method(hdl)); + type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true); + if (tinfo->holder_enum_v == holder_enum_t::smart_holder) { + return cpp_function( + [pm](handle c_hdl) -> D { + std::shared_ptr c_sp + = type_caster>::shared_ptr_with_responsible_parent( + c_hdl); + return D{std::move(c_sp.get()->*pm)}; + }, + is_method(hdl)); + } + return property_cpp_function_classic::read(pm, hdl); } template = 0> @@ -1783,18 +1780,63 @@ struct property_cpp_function< } }; +PYBIND11_NAMESPACE_END(detail) + +template +struct property_cpp_function< + T, + D, + detail::enable_if_t, + detail::both_t_and_d_use_type_caster_base>::value>> + : detail::property_cpp_function_sh_raw_ptr_member {}; + +template +struct property_cpp_function, + std::is_array, + detail::is_instantiation, + detail::is_instantiation>, + detail::both_t_and_d_use_type_caster_base>::value>> + : detail::property_cpp_function_sh_member_held_by_value {}; + +template +struct property_cpp_function< + T, + D, + detail::enable_if_t, + detail::both_t_and_d_use_type_caster_base>::value>> + : detail::property_cpp_function_sh_unique_ptr_member {}; + +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + +#if defined(PYBIND11_USE_SMART_HOLDER_AS_DEFAULT) \ + && defined(PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT) +// NOTE: THIS IS MEANT FOR STRESS-TESTING ONLY! +// As of PR #5257, for production use, there is no longer a strong reason to make +// smart_holder the default holder: +// Simply use `py::classh` (see below) instead of `py::class_` as needed. +// Running the pybind11 unit tests with smart_holder as the default holder is to ensure +// that `py::smart_holder` / `py::classh` is backward-compatible with all pre-existing +// functionality. +# define PYBIND11_ACTUALLY_USING_SMART_HOLDER_AS_DEFAULT +template +using default_holder_type = smart_holder; +#else +template +using default_holder_type = std::unique_ptr; +#endif + template class class_ : public detail::generic_type { + template + using is_holder = detail::is_holder_type; template using is_subtype = detail::is_strict_base_of; template using is_base = detail::is_strict_base_of; - template - using is_holder - = detail::any_of, - detail::all_of>, - detail::negation>, - detail::type_uses_smart_holder_type_caster>>; // struct instead of using here to help MSVC: template struct is_valid_class_option : detail::any_of, is_subtype, is_base> {}; @@ -1826,36 +1868,6 @@ class class_ : public detail::generic_type { none_of...>::value), "Error: multiple inheritance bases must be specified via class_ template options"); - static constexpr bool holder_is_smart_holder - = detail::is_smart_holder_type::value; - static constexpr bool wrapped_type_uses_smart_holder_type_caster - = detail::type_uses_smart_holder_type_caster::value; - static constexpr bool type_caster_type_is_type_caster_base_subtype - = std::is_base_of, detail::type_caster>::value; - // Necessary conditions, but not strict. - static_assert(!(detail::is_instantiation::value - && wrapped_type_uses_smart_holder_type_caster), - "py::class_ holder vs type_caster mismatch:" - " missing PYBIND11_TYPE_CASTER_BASE_HOLDER(T, std::unique_ptr)?"); - static_assert(!(detail::is_instantiation::value - && wrapped_type_uses_smart_holder_type_caster), - "py::class_ holder vs type_caster mismatch:" - " missing PYBIND11_TYPE_CASTER_BASE_HOLDER(T, std::shared_ptr)?"); - static_assert(!(holder_is_smart_holder && type_caster_type_is_type_caster_base_subtype), - "py::class_ holder vs type_caster mismatch:" - " missing PYBIND11_SMART_HOLDER_TYPE_CASTERS(T)?"); -#ifdef PYBIND11_STRICT_ASSERTS_CLASS_HOLDER_VS_TYPE_CASTER_MIX - // Strict conditions cannot be enforced universally at the moment (PR #2836). - static_assert(holder_is_smart_holder == wrapped_type_uses_smart_holder_type_caster, - "py::class_ holder vs type_caster mismatch:" - " missing PYBIND11_SMART_HOLDER_TYPE_CASTERS(T)" - " or collision with custom py::detail::type_caster?"); - static_assert(!holder_is_smart_holder == type_caster_type_is_type_caster_base_subtype, - "py::class_ holder vs type_caster mismatch:" - " missing PYBIND11_TYPE_CASTER_BASE_HOLDER(T, ...)" - " or collision with custom py::detail::type_caster?"); -#endif - type_record record; record.scope = scope; record.name = name; @@ -1869,6 +1881,18 @@ class class_ : public detail::generic_type { // A more fitting name would be uses_unique_ptr_holder. record.default_holder = detail::is_instantiation::value; +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + if (detail::is_instantiation::value) { + record.holder_enum_v = detail::holder_enum_t::std_unique_ptr; + } else if (detail::is_instantiation::value) { + record.holder_enum_v = detail::holder_enum_t::std_shared_ptr; + } else if (std::is_same::value) { + record.holder_enum_v = detail::holder_enum_t::smart_holder; + } else { + record.holder_enum_v = detail::holder_enum_t::custom_holder; + } +#endif + set_operator_new(&record); /* Register base classes specified via template arguments to class_, if any */ @@ -1877,7 +1901,7 @@ class class_ : public detail::generic_type { /* Process optional arguments, if any */ process_attributes::init(extra..., &record); - generic_type_initialize(record); + generic_type::initialize(record); if (has_alias) { with_internals([&](internals &internals) { @@ -2138,18 +2162,6 @@ class class_ : public detail::generic_type { } private: - template ::value, int> = 0> - void generic_type_initialize(const detail::type_record &record) { - generic_type::initialize(record, &detail::type_caster_generic::local_load); - } - - template ::value, int> = 0> - void generic_type_initialize(const detail::type_record &record) { - generic_type::initialize(record, detail::type_caster::get_local_load_function_ptr()); - } - /// Initialize holder object, variant 1: object derives from enable_shared_from_this template static void init_holder(detail::instance *inst, @@ -2203,8 +2215,8 @@ class class_ : public detail::generic_type { /// instance. Should be called as soon as the `type` value_ptr is set for an instance. Takes /// an optional pointer to an existing holder to use; if not specified and the instance is /// `.owned`, a new holder will be constructed to manage the value pointer. - template ::value, int> = 0> + template ::value, int> = 0> static void init_instance(detail::instance *inst, const void *holder_ptr) { auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(type))); if (!v_h.instance_registered()) { @@ -2214,13 +2226,70 @@ class class_ : public detail::generic_type { init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr()); } - template ::value, int> = 0> - static void init_instance(detail::instance *inst, const void *holder_ptr) { - detail::type_caster::template init_instance_for_type(inst, holder_ptr); +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + + template + static bool try_initialization_using_shared_from_this(holder_type *, WrappedType *, ...) { + return false; + } + + // Adopting existing approach used by type_caster_base, although it leads to somewhat fuzzy + // ownership semantics: if we detected via shared_from_this that a shared_ptr exists already, + // it is reused, irrespective of the return_value_policy in effect. + // "SomeBaseOfWrappedType" is needed because std::enable_shared_from_this is not necessarily a + // direct base of WrappedType. + template + static bool try_initialization_using_shared_from_this( + holder_type *uninitialized_location, + WrappedType *value_ptr_w_t, + const std::enable_shared_from_this *) { + auto shd_ptr = std::dynamic_pointer_cast( + detail::try_get_shared_from_this(value_ptr_w_t)); + if (!shd_ptr) { + return false; + } + // Note: inst->owned ignored. + new (uninitialized_location) holder_type(holder_type::from_shared_ptr(shd_ptr)); + return true; + } + + template ::value, int> = 0> + static void init_instance(detail::instance *inst, const void *holder_const_void_ptr) { + // Need for const_cast is a consequence of the type_info::init_instance type: + // void (*init_instance)(instance *, const void *); + auto *holder_void_ptr = const_cast(holder_const_void_ptr); + + auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(type))); + if (!v_h.instance_registered()) { + register_instance(inst, v_h.value_ptr(), v_h.type); + v_h.set_instance_registered(); + } + auto *uninitialized_location = std::addressof(v_h.holder()); + auto *value_ptr_w_t = v_h.value_ptr(); + bool pointee_depends_on_holder_owner + = detail::dynamic_raw_ptr_cast_if_possible(value_ptr_w_t) != nullptr; + if (holder_void_ptr) { + // Note: inst->owned ignored. + auto *holder_ptr = static_cast(holder_void_ptr); + new (uninitialized_location) holder_type(std::move(*holder_ptr)); + } else if (!try_initialization_using_shared_from_this( + uninitialized_location, value_ptr_w_t, value_ptr_w_t)) { + if (inst->owned) { + new (uninitialized_location) holder_type(holder_type::from_raw_ptr_take_ownership( + value_ptr_w_t, /*void_cast_raw_ptr*/ pointee_depends_on_holder_owner)); + } else { + new (uninitialized_location) + holder_type(holder_type::from_raw_ptr_unowned(value_ptr_w_t)); + } + } + v_h.holder().pointee_depends_on_holder_owner + = pointee_depends_on_holder_owner; + v_h.set_holder_constructed(); } +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + /// Deallocates an instance; via holder, if constructed; otherwise via operator delete. static void dealloc(detail::value_and_holder &v_h) { // We could be deallocating because we are cleaning up after a Python exception. @@ -2261,6 +2330,18 @@ class class_ : public detail::generic_type { } }; +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + +// Supports easier switching between py::class_ and py::class_: +// users can simply replace the `_` in `class_` with `h` or vice versa. +template +class classh : public class_ { +public: + using class_::class_; +}; + +#endif + /// Binds an existing constructor taking arguments Args... template detail::initimpl::constructor init() { diff --git a/include/pybind11/smart_holder.h b/include/pybind11/smart_holder.h index 03ec4bb8..5f568a55 100644 --- a/include/pybind11/smart_holder.h +++ b/include/pybind11/smart_holder.h @@ -1,29 +1,14 @@ -// Copyright (c) 2021 The Pybind Development Team. +// Copyright (c) 2021-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 "pybind11.h" -#include "detail/common.h" -#include "detail/smart_holder_type_casters.h" -#undef PYBIND11_SH_AVL // Undoing #define in pybind11.h - -#define PYBIND11_SH_AVL(...) ::pybind11::smart_holder // "Smart_Holder if AVaiLable" -// ---- std::shared_ptr(...) -- same length by design, to not disturb the indentation -// of existing code. - -PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) - -// Supports easier switching between py::class_ and py::class_: -// users can simply replace the `_` in `class_` with `h` or vice versa. -// Note though that the PYBIND11_SMART_HOLDER_TYPE_CASTERS(T) macro also needs to be -// added (for `classh`) or commented out (when falling back to `class_`). -template -class classh : public class_ { -public: - using class_::class_; -}; - -PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) +// Legacy macros introduced with smart_holder_type_casters implementation in 2021. +// Deprecated. +#define PYBIND11_TYPE_CASTER_BASE_HOLDER(...) +#define PYBIND11_SMART_HOLDER_TYPE_CASTERS(...) +#define PYBIND11_SH_AVL(...) // "Smart_Holder if AVaiLable" +#define PYBIND11_SH_DEF(...) // "Smart_Holder if DEFault" diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index 09007caf..71bc5902 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -392,15 +392,12 @@ struct variant_caster> { template bool load_alternative(handle src, bool convert, type_list) { - PYBIND11_WARNING_PUSH - PYBIND11_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") auto caster = make_caster(); if (caster.load(src, convert)) { value = cast_op(std::move(caster)); return true; } return load_alternative(src, convert, type_list{}); - PYBIND11_WARNING_POP } bool load_alternative(handle, bool, type_list<>) { return false; } diff --git a/include/pybind11/trampoline_self_life_support.h b/include/pybind11/trampoline_self_life_support.h index 47f62395..06883572 100644 --- a/include/pybind11/trampoline_self_life_support.h +++ b/include/pybind11/trampoline_self_life_support.h @@ -4,9 +4,13 @@ #pragma once -#include "detail/common.h" -#include "detail/smart_holder_poc.h" -#include "detail/value_and_holder.h" +#include "detail/internals.h" + +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + +# include "detail/common.h" +# include "detail/using_smart_holder.h" +# include "detail/value_and_holder.h" PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) @@ -40,7 +44,7 @@ struct trampoline_self_life_support { if (value_void_ptr != nullptr) { PyGILState_STATE threadstate = PyGILState_Ensure(); v_h.value_ptr() = nullptr; - v_h.holder().release_disowned(); + v_h.holder().release_disowned(); detail::deregister_instance(v_h.inst, value_void_ptr, v_h.type); Py_DECREF((PyObject *) v_h.inst); // Must be after deregister. PyGILState_Release(threadstate); @@ -59,3 +63,5 @@ struct trampoline_self_life_support { }; PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) + +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT diff --git a/pybind11/_version.py b/pybind11/_version.py index c5cc1a0b..2dfe6761 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -8,5 +8,5 @@ def _to_int(s: str) -> int | str: return s -__version__ = "2.14.0.dev1" +__version__ = "3.0.0.dev1" version_info = tuple(_to_int(s) for s in __version__.split(".")) diff --git a/tests/class_sh_module_local_0.cpp b/tests/class_sh_module_local_0.cpp index bb1f46d5..8a0ac0f6 100644 --- a/tests/class_sh_module_local_0.cpp +++ b/tests/class_sh_module_local_0.cpp @@ -19,9 +19,16 @@ atyp rtrn_valu_atyp() { return atyp(); } PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_module_local::atyp) PYBIND11_MODULE(class_sh_module_local_0, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + using namespace pybind11_tests::class_sh_module_local; m.def("get_mtxt", get_mtxt); m.def("rtrn_valu_atyp", rtrn_valu_atyp); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/class_sh_module_local_1.cpp b/tests/class_sh_module_local_1.cpp index 66bc9551..e5a45844 100644 --- a/tests/class_sh_module_local_1.cpp +++ b/tests/class_sh_module_local_1.cpp @@ -18,6 +18,12 @@ std::string get_mtxt(const atyp &obj) { return obj.mtxt; } PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_module_local::atyp) PYBIND11_MODULE(class_sh_module_local_1, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + namespace py = pybind11; using namespace pybind11_tests::class_sh_module_local; @@ -30,4 +36,5 @@ PYBIND11_MODULE(class_sh_module_local_1, m) { .def("tag", [](const atyp &) { return 1; }); m.def("get_mtxt", get_mtxt); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/class_sh_module_local_2.cpp b/tests/class_sh_module_local_2.cpp index bef105aa..5dd4104a 100644 --- a/tests/class_sh_module_local_2.cpp +++ b/tests/class_sh_module_local_2.cpp @@ -18,6 +18,12 @@ std::string get_mtxt(const atyp &obj) { return obj.mtxt; } PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_module_local::atyp) PYBIND11_MODULE(class_sh_module_local_2, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + namespace py = pybind11; using namespace pybind11_tests::class_sh_module_local; @@ -30,4 +36,5 @@ PYBIND11_MODULE(class_sh_module_local_2, m) { .def("tag", [](const atyp &) { return 2; }); m.def("get_mtxt", get_mtxt); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index a61b4284..5c970537 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -60,10 +60,9 @@ "include/pybind11/detail/init.h", "include/pybind11/detail/internals.h", "include/pybind11/detail/smart_holder_poc.h", - "include/pybind11/detail/smart_holder_sfinae_hooks_only.h", - "include/pybind11/detail/smart_holder_type_casters.h", "include/pybind11/detail/type_caster_base.h", "include/pybind11/detail/typeid.h", + "include/pybind11/detail/using_smart_holder.h", "include/pybind11/detail/value_and_holder.h", } diff --git a/tests/test_class.cpp b/tests/test_class.cpp index d0ccc121..73ab6090 100644 --- a/tests/test_class.cpp +++ b/tests/test_class.cpp @@ -25,8 +25,6 @@ PYBIND11_WARNING_DISABLE_MSVC(4324) // warning C4324: structure was padded due to alignment specifier -namespace { - // test_brace_initialization struct NoBraceInitialization { explicit NoBraceInitialization(std::vector v) : vec{std::move(v)} {} @@ -36,17 +34,6 @@ struct NoBraceInitialization { std::vector vec; }; -// test_mismatched_holder -struct MismatchBase1 {}; -struct MismatchDerived1 : MismatchBase1 {}; -struct MismatchBase2 {}; -struct MismatchDerived2 : MismatchBase2 {}; - -// test_multiple_instances_with_same_pointer -struct SamePointer {}; - -} // namespace - namespace test_class { namespace pr4220_tripped_over_this { // PR #4227 @@ -67,12 +54,6 @@ void bind_empty0(py::module_ &m) { } // namespace pr4220_tripped_over_this } // namespace test_class -PYBIND11_TYPE_CASTER_BASE_HOLDER(MismatchBase1, std::shared_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(MismatchDerived1, std::unique_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(MismatchBase2, std::unique_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(MismatchDerived2, std::shared_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(SamePointer, std::unique_ptr) - TEST_SUBMODULE(class_, m) { m.def("obj_class_name", [](py::handle obj) { return py::detail::obj_class_name(obj.ptr()); }); @@ -108,6 +89,16 @@ TEST_SUBMODULE(class_, m) { .def_static("__new__", [](const py::object &) { return NoConstructorNew::new_instance(); }); + // test_pass_unique_ptr + struct ToBeHeldByUniquePtr {}; + py::class_>(m, "ToBeHeldByUniquePtr") + .def(py::init<>()); +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.def("pass_unique_ptr", [](std::unique_ptr &&) {}); +#else + m.attr("pass_unique_ptr") = py::none(); +#endif + // test_inheritance class Pet { public: @@ -221,6 +212,12 @@ TEST_SUBMODULE(class_, m) { m.def("as_type", [](const py::object &ob) { return py::type(ob); }); // test_mismatched_holder + struct MismatchBase1 {}; + struct MismatchDerived1 : MismatchBase1 {}; + + struct MismatchBase2 {}; + struct MismatchDerived2 : MismatchBase2 {}; + m.def("mismatched_holder_1", []() { auto mod = py::module_::import("__main__"); py::class_>(mod, "MismatchBase1"); @@ -520,6 +517,7 @@ TEST_SUBMODULE(class_, m) { .def("throw_something", &PyPrintDestructor::throw_something); // test_multiple_instances_with_same_pointer + struct SamePointer {}; static SamePointer samePointer; py::class_>(m, "SamePointer") .def(py::init([]() { return &samePointer; })); @@ -619,18 +617,12 @@ CHECK_NOALIAS(8); static_assert(std::is_same>>::value, \ "DoesntBreak" #N " has wrong holder_type!") -#define CHECK_SMART_HOLDER(N) \ - static_assert(std::is_same::value, \ - "DoesntBreak" #N " has wrong holder_type!") CHECK_HOLDER(1, unique); CHECK_HOLDER(2, unique); CHECK_HOLDER(3, unique); -#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT +#ifndef PYBIND11_ACTUALLY_USING_SMART_HOLDER_AS_DEFAULT CHECK_HOLDER(4, unique); CHECK_HOLDER(5, unique); -#else -CHECK_SMART_HOLDER(4); -CHECK_SMART_HOLDER(5); #endif CHECK_HOLDER(6, shared); CHECK_HOLDER(7, shared); diff --git a/tests/test_class.py b/tests/test_class.py index 9b2b1d83..3ecb663f 100644 --- a/tests/test_class.py +++ b/tests/test_class.py @@ -41,6 +41,18 @@ def test_instance_new(): assert cstats.alive() == 0 +def test_pass_unique_ptr(): + obj = m.ToBeHeldByUniquePtr() + if m.pass_unique_ptr is None: + pytest.skip("smart_holder not available.") + with pytest.raises(RuntimeError) as execinfo: + m.pass_unique_ptr(obj) + assert str(execinfo.value).startswith( + "Passing `std::unique_ptr` from Python to C++ requires `py::classh` (with T = " + ) + assert "ToBeHeldByUniquePtr" in str(execinfo.value) + + def test_type(): assert m.check_type(1) == m.DerivedClass1 with pytest.raises(RuntimeError) as execinfo: diff --git a/tests/test_class_sh_basic.cpp b/tests/test_class_sh_basic.cpp index fb939518..460dd1bd 100644 --- a/tests/test_class_sh_basic.cpp +++ b/tests/test_class_sh_basic.cpp @@ -145,6 +145,12 @@ namespace pybind11_tests { namespace class_sh_basic { TEST_SUBMODULE(class_sh_basic, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + namespace py = pybind11; py::classh(m, "atyp").def(py::init<>()).def(py::init([](const std::string &mtxt) { @@ -233,11 +239,14 @@ TEST_SUBMODULE(class_sh_basic, m) { []() { return std::unique_ptr(new atyp("rtrn_uq_automatic_reference")); }, pybind11::return_value_policy::automatic_reference); + m.def("pass_shared_ptr_ptr", [](std::shared_ptr *) {}); + py::classh(m, "LocalUnusualOpRef"); m.def("CallCastUnusualOpRefConstRef", []() { return CastUnusualOpRefConstRef(LocalUnusualOpRef()); }); m.def("CallCastUnusualOpRefMovable", []() { return CastUnusualOpRefMovable(LocalUnusualOpRef()); }); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } } // namespace class_sh_basic diff --git a/tests/test_class_sh_basic.py b/tests/test_class_sh_basic.py index 56d45d18..b3d9b98c 100644 --- a/tests/test_class_sh_basic.py +++ b/tests/test_class_sh_basic.py @@ -7,6 +7,9 @@ from pybind11_tests import class_sh_basic as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + def test_atyp_constructors(): obj = m.atyp() @@ -132,9 +135,7 @@ def test_cannot_disown_use_count_ne_1(pass_f, rtrn_f): stash.Add(obj) with pytest.raises(ValueError) as exc_info: pass_f(obj) - assert str(exc_info.value) == ( - "Cannot disown use_count != 1 (loaded_as_unique_ptr)." - ) + assert str(exc_info.value) == ("Cannot disown use_count != 1 (load_as_unique_ptr).") def test_unique_ptr_roundtrip(num_round_trips=1000): @@ -220,6 +221,16 @@ def test_unique_ptr_return_value_policy_automatic_reference(): assert m.get_mtxt(m.rtrn_uq_automatic_reference()) == "rtrn_uq_automatic_reference" +def test_pass_shared_ptr_ptr(): + obj = m.atyp() + with pytest.raises(RuntimeError) as excinfo: + m.pass_shared_ptr_ptr(obj) + assert str(excinfo.value) == ( + "Passing `std::shared_ptr *` from Python to C++ is not supported" + " (inherently unsafe)." + ) + + def test_unusual_op_ref(): # Merely to test that this still exists and built successfully. assert m.CallCastUnusualOpRefConstRef().__class__.__name__ == "LocalUnusualOpRef" diff --git a/tests/test_class_sh_disowning.cpp b/tests/test_class_sh_disowning.cpp index f934852f..aba3dc81 100644 --- a/tests/test_class_sh_disowning.cpp +++ b/tests/test_class_sh_disowning.cpp @@ -32,6 +32,12 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning::Atype<1>) PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning::Atype<2>) TEST_SUBMODULE(class_sh_disowning, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + using namespace pybind11_tests::class_sh_disowning; py::classh>(m, "Atype1").def(py::init()).def("get", &Atype<1>::get); @@ -43,4 +49,5 @@ TEST_SUBMODULE(class_sh_disowning, m) { m.def("overloaded", (int (*)(std::unique_ptr>, int)) & overloaded); m.def("overloaded", (int (*)(std::unique_ptr>, int)) & overloaded); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_disowning.py b/tests/test_class_sh_disowning.py index 52568203..36e46101 100644 --- a/tests/test_class_sh_disowning.py +++ b/tests/test_class_sh_disowning.py @@ -4,6 +4,9 @@ from pybind11_tests import class_sh_disowning as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + def is_disowned(obj): try: diff --git a/tests/test_class_sh_disowning_mi.cpp b/tests/test_class_sh_disowning_mi.cpp index 86333e86..1bba4015 100644 --- a/tests/test_class_sh_disowning_mi.cpp +++ b/tests/test_class_sh_disowning_mi.cpp @@ -57,6 +57,12 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning_mi::Base1) PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning_mi::Base2) TEST_SUBMODULE(class_sh_disowning_mi, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + using namespace pybind11_tests::class_sh_disowning_mi; py::classh(m, "B") @@ -92,4 +98,5 @@ TEST_SUBMODULE(class_sh_disowning_mi, m) { py::classh(m, "Base2").def(py::init()).def("bar", &Base2::bar); m.def("disown_base1", disown_base1); m.def("disown_base2", disown_base2); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_disowning_mi.py b/tests/test_class_sh_disowning_mi.py index 4a4beecc..781db8c0 100644 --- a/tests/test_class_sh_disowning_mi.py +++ b/tests/test_class_sh_disowning_mi.py @@ -5,6 +5,9 @@ import env # noqa: F401 from pybind11_tests import class_sh_disowning_mi as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + def test_diamond_inheritance(): # Very similar to test_multiple_inheritance.py:test_diamond_inheritance. diff --git a/tests/test_class_sh_factory_constructors.cpp b/tests/test_class_sh_factory_constructors.cpp index 937672cb..7ee56a8b 100644 --- a/tests/test_class_sh_factory_constructors.cpp +++ b/tests/test_class_sh_factory_constructors.cpp @@ -87,6 +87,12 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::with_alias) TEST_SUBMODULE(class_sh_factory_constructors, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + using namespace pybind11_tests::class_sh_factory_constructors; py::classh(m, "atyp_valu") @@ -177,4 +183,5 @@ TEST_SUBMODULE(class_sh_factory_constructors, m) { [](int, int, int, int, int) { return std::make_shared(); // Invalid alias factory. })); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_factory_constructors.py b/tests/test_class_sh_factory_constructors.py index 5d45db6f..38e529e5 100644 --- a/tests/test_class_sh_factory_constructors.py +++ b/tests/test_class_sh_factory_constructors.py @@ -4,6 +4,9 @@ from pybind11_tests import class_sh_factory_constructors as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + def test_atyp_factories(): assert m.atyp_valu().get_mtxt() == "Valu" diff --git a/tests/test_class_sh_inheritance.cpp b/tests/test_class_sh_inheritance.cpp index d8f7da0e..af57f03b 100644 --- a/tests/test_class_sh_inheritance.cpp +++ b/tests/test_class_sh_inheritance.cpp @@ -73,6 +73,12 @@ namespace pybind11_tests { namespace class_sh_inheritance { TEST_SUBMODULE(class_sh_inheritance, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + py::classh(m, "base"); py::classh(m, "drvd"); @@ -99,6 +105,7 @@ TEST_SUBMODULE(class_sh_inheritance, m) { m.def("pass_cptr_base1", pass_cptr_base1); m.def("pass_cptr_base2", pass_cptr_base2); m.def("pass_cptr_drvd2", pass_cptr_drvd2); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } } // namespace class_sh_inheritance diff --git a/tests/test_class_sh_inheritance.py b/tests/test_class_sh_inheritance.py index cd9d6f47..f03cee36 100644 --- a/tests/test_class_sh_inheritance.py +++ b/tests/test_class_sh_inheritance.py @@ -1,7 +1,12 @@ from __future__ import annotations +import pytest + from pybind11_tests import class_sh_inheritance as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + def test_rtrn_mptr_drvd_pass_cptr_base(): d = m.rtrn_mptr_drvd() diff --git a/tests/test_class_sh_mi_thunks.cpp b/tests/test_class_sh_mi_thunks.cpp index c4f430e8..0990c34f 100644 --- a/tests/test_class_sh_mi_thunks.cpp +++ b/tests/test_class_sh_mi_thunks.cpp @@ -40,6 +40,12 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Base1) PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Derived) TEST_SUBMODULE(class_sh_mi_thunks, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + using namespace test_class_sh_mi_thunks; m.def("ptrdiff_drvd_base0", []() { @@ -97,4 +103,5 @@ TEST_SUBMODULE(class_sh_mi_thunks, m) { } return obj_der->vec.size(); }); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_mi_thunks.py b/tests/test_class_sh_mi_thunks.py index c1c8a304..12b6e9d9 100644 --- a/tests/test_class_sh_mi_thunks.py +++ b/tests/test_class_sh_mi_thunks.py @@ -4,6 +4,9 @@ from pybind11_tests import class_sh_mi_thunks as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + def test_ptrdiff_drvd_base0(): ptrdiff = m.ptrdiff_drvd_base0() @@ -49,6 +52,5 @@ def test_get_shared_vec_size_unique(): with pytest.raises(ValueError) as exc_info: m.vec_size_base0_unique_ptr(obj) assert ( - str(exc_info.value) - == "Cannot disown external shared_ptr (loaded_as_unique_ptr)." + str(exc_info.value) == "Cannot disown external shared_ptr (load_as_unique_ptr)." ) diff --git a/tests/test_class_sh_module_local.py b/tests/test_class_sh_module_local.py index e504152a..79ccb8b4 100644 --- a/tests/test_class_sh_module_local.py +++ b/tests/test_class_sh_module_local.py @@ -5,6 +5,9 @@ import class_sh_module_local_2 as m2 import pytest +if not m0.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + def test_cross_module_get_mtxt(): obj1 = m1.atyp("A") diff --git a/tests/test_class_sh_property.cpp b/tests/test_class_sh_property.cpp index 1f692263..db744fae 100644 --- a/tests/test_class_sh_property.cpp +++ b/tests/test_class_sh_property.cpp @@ -58,6 +58,12 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_property::WithCharArrayMember) PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_property::WithConstCharPtrMember) TEST_SUBMODULE(class_sh_property, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + using namespace test_class_sh_property; py::class_>(m, "ClassicField") @@ -103,4 +109,5 @@ TEST_SUBMODULE(class_sh_property, m) { py::classh(m, "WithConstCharPtrMember") .def(py::init<>()) .def_readonly("const_char_ptr_member", &WithConstCharPtrMember::const_char_ptr_member); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_property.py b/tests/test_class_sh_property.py index 089cf7ca..dda786a2 100644 --- a/tests/test_class_sh_property.py +++ b/tests/test_class_sh_property.py @@ -7,6 +7,9 @@ import env # noqa: F401 from pybind11_tests import class_sh_property as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + @pytest.mark.xfail("env.PYPY", reason="gc after `del field` is apparently deferred") @pytest.mark.parametrize("m_attr", ["m_valu_readonly", "m_valu_readwrite"]) @@ -18,7 +21,7 @@ def test_valu_getter(m_attr): assert field.num == -99 with pytest.raises(ValueError) as excinfo: m.DisownOuter(outer) - assert str(excinfo.value) == "Cannot disown use_count != 1 (loaded_as_unique_ptr)." + assert str(excinfo.value) == "Cannot disown use_count != 1 (load_as_unique_ptr)." del field m.DisownOuter(outer) with pytest.raises(ValueError, match="Python instance was disowned") as excinfo: diff --git a/tests/test_class_sh_property_non_owning.cpp b/tests/test_class_sh_property_non_owning.cpp index cd7fc5c6..65103148 100644 --- a/tests/test_class_sh_property_non_owning.cpp +++ b/tests/test_class_sh_property_non_owning.cpp @@ -51,6 +51,12 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(DataField) PYBIND11_SMART_HOLDER_TYPE_CASTERS(DataFieldsHolder) TEST_SUBMODULE(class_sh_property_non_owning, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + py::classh(m, "CoreField").def_readwrite("int_value", &CoreField::int_value); py::classh(m, "DataField") @@ -65,4 +71,5 @@ TEST_SUBMODULE(class_sh_property_non_owning, m) { py::classh(m, "DataFieldsHolder") .def(py::init()) .def("vec_at", &DataFieldsHolder::vec_at, py::return_value_policy::reference_internal); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_property_non_owning.py b/tests/test_class_sh_property_non_owning.py index 33a9d450..89c7c0cd 100644 --- a/tests/test_class_sh_property_non_owning.py +++ b/tests/test_class_sh_property_non_owning.py @@ -4,6 +4,9 @@ from pybind11_tests import class_sh_property_non_owning as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + @pytest.mark.parametrize("persistent_holder", [True, False]) @pytest.mark.parametrize( diff --git a/tests/test_class_sh_shared_ptr_copy_move.cpp b/tests/test_class_sh_shared_ptr_copy_move.cpp index ae1afd6c..3e9eb9ac 100644 --- a/tests/test_class_sh_shared_ptr_copy_move.cpp +++ b/tests/test_class_sh_shared_ptr_copy_move.cpp @@ -50,7 +50,12 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::FooSmHld) namespace pybind11_tests { TEST_SUBMODULE(class_sh_shared_ptr_copy_move, m) { -#if true // Trick to avoid clang-format changes, in support of PR #5213. + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + namespace py = pybind11; py::class_>(m, "FooShPtr") @@ -108,7 +113,7 @@ TEST_SUBMODULE(class_sh_shared_ptr_copy_move, m) { l.append(std::move(o)); return l; }); -#endif +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } } // namespace pybind11_tests diff --git a/tests/test_class_sh_shared_ptr_copy_move.py b/tests/test_class_sh_shared_ptr_copy_move.py index 067bb47d..092aa1f3 100644 --- a/tests/test_class_sh_shared_ptr_copy_move.py +++ b/tests/test_class_sh_shared_ptr_copy_move.py @@ -1,7 +1,12 @@ from __future__ import annotations +import pytest + from pybind11_tests import class_sh_shared_ptr_copy_move as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + def test_shptr_copy(): txt = m.test_ShPtr_copy()[0].get_history() diff --git a/tests/test_class_sh_trampoline_basic.cpp b/tests/test_class_sh_trampoline_basic.cpp index 128701d7..faadb402 100644 --- a/tests/test_class_sh_trampoline_basic.cpp +++ b/tests/test_class_sh_trampoline_basic.cpp @@ -34,6 +34,7 @@ struct AbaseAlias : Abase { } }; +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT template <> struct AbaseAlias<1> : Abase<1>, py::trampoline_self_life_support { using Abase<1>::Abase; @@ -45,6 +46,7 @@ struct AbaseAlias<1> : Abase<1>, py::trampoline_self_life_support { other_val); } }; +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT template int AddInCppRawPtr(const Abase *obj, int other_val) { @@ -63,6 +65,7 @@ int AddInCppUniquePtr(std::unique_ptr> obj, int other_val) { template void wrap(py::module_ m, const char *py_class_name) { +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT py::classh, AbaseAlias>(m, py_class_name) .def(py::init(), py::arg("val")) .def("Get", &Abase::Get) @@ -71,6 +74,7 @@ void wrap(py::module_ m, const char *py_class_name) { m.def("AddInCppRawPtr", AddInCppRawPtr, py::arg("obj"), py::arg("other_val")); m.def("AddInCppSharedPtr", AddInCppSharedPtr, py::arg("obj"), py::arg("other_val")); m.def("AddInCppUniquePtr", AddInCppUniquePtr, py::arg("obj"), py::arg("other_val")); +#endif } } // namespace class_sh_trampoline_basic @@ -82,6 +86,13 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(Abase<0>) PYBIND11_SMART_HOLDER_TYPE_CASTERS(Abase<1>) TEST_SUBMODULE(class_sh_trampoline_basic, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + wrap<0>(m, "Abase0"); wrap<1>(m, "Abase1"); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_trampoline_basic.py b/tests/test_class_sh_trampoline_basic.py index eab82121..7b6e1a0f 100644 --- a/tests/test_class_sh_trampoline_basic.py +++ b/tests/test_class_sh_trampoline_basic.py @@ -4,6 +4,9 @@ from pybind11_tests import class_sh_trampoline_basic as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + class PyDrvd0(m.Abase0): def __init__(self, val): diff --git a/tests/test_class_sh_trampoline_self_life_support.cpp b/tests/test_class_sh_trampoline_self_life_support.cpp index b1b8969a..859b9f8f 100644 --- a/tests/test_class_sh_trampoline_self_life_support.cpp +++ b/tests/test_class_sh_trampoline_self_life_support.cpp @@ -38,9 +38,11 @@ struct Big5 { // Also known as "rule of five". Big5() : history{"DefaultConstructor"} {} }; +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT struct Big5Trampoline : Big5, py::trampoline_self_life_support { using Big5::Big5; }; +#endif } // namespace class_sh_trampoline_self_life_support } // namespace pybind11_tests @@ -50,6 +52,12 @@ using namespace pybind11_tests::class_sh_trampoline_self_life_support; PYBIND11_SMART_HOLDER_TYPE_CASTERS(Big5) TEST_SUBMODULE(class_sh_trampoline_self_life_support, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + py::classh(m, "Big5") .def(py::init()) .def_readonly("history", &Big5::history); @@ -86,4 +94,5 @@ TEST_SUBMODULE(class_sh_trampoline_self_life_support, m) { py::object o1 = py::cast(std::move(obj)); return py::make_tuple(o1, o2); }); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_trampoline_self_life_support.py b/tests/test_class_sh_trampoline_self_life_support.py index d4af2ab9..d366b48c 100644 --- a/tests/test_class_sh_trampoline_self_life_support.py +++ b/tests/test_class_sh_trampoline_self_life_support.py @@ -4,6 +4,9 @@ import pybind11_tests.class_sh_trampoline_self_life_support as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + class PyBig5(m.Big5): pass diff --git a/tests/test_class_sh_trampoline_shared_from_this.cpp b/tests/test_class_sh_trampoline_shared_from_this.cpp index ebbe94e9..aaf5a875 100644 --- a/tests/test_class_sh_trampoline_shared_from_this.cpp +++ b/tests/test_class_sh_trampoline_shared_from_this.cpp @@ -71,9 +71,11 @@ struct SftSharedPtrStash { } }; +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT struct SftTrampoline : Sft, py::trampoline_self_life_support { using Sft::Sft; }; +#endif long use_count(const std::shared_ptr &obj) { return obj.use_count(); } @@ -108,6 +110,12 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(Sft) PYBIND11_SMART_HOLDER_TYPE_CASTERS(SftSharedPtrStash) TEST_SUBMODULE(class_sh_trampoline_shared_from_this, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + py::classh(m, "Sft") .def(py::init()) .def(py::init([](const std::string &history, int) { @@ -132,4 +140,5 @@ TEST_SUBMODULE(class_sh_trampoline_shared_from_this, m) { m.def("make_pure_cpp_sft_unq_ptr", make_pure_cpp_sft_unq_ptr); m.def("make_pure_cpp_sft_shd_ptr", make_pure_cpp_sft_shd_ptr); m.def("pass_through_shd_ptr", pass_through_shd_ptr); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_trampoline_shared_from_this.py b/tests/test_class_sh_trampoline_shared_from_this.py index 85fe7858..75558421 100644 --- a/tests/test_class_sh_trampoline_shared_from_this.py +++ b/tests/test_class_sh_trampoline_shared_from_this.py @@ -8,6 +8,9 @@ import env import pybind11_tests.class_sh_trampoline_shared_from_this as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + class PySft(m.Sft): pass @@ -238,7 +241,7 @@ def __init__(self, history): str_exc_info_value = str(exc_info.value) assert ( str_exc_info_value - == "smart_holder_type_casters loaded_as_shared_ptr failure: not implemented:" + == "smart_holder_type_casters load_as_shared_ptr failure: not implemented:" " trampoline-self-life-support for external shared_ptr to type inheriting" " from std::enable_shared_from_this." ) diff --git a/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.cpp b/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.cpp index f4de884e..2b94310b 100644 --- a/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.cpp +++ b/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.cpp @@ -63,6 +63,12 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(SpGoAway) PYBIND11_SMART_HOLDER_TYPE_CASTERS(SpGoAwayTester) TEST_SUBMODULE(class_sh_trampoline_shared_ptr_cpp_arg, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + // For testing whether a python subclass of a C++ object dies when the // last python reference is lost @@ -95,4 +101,5 @@ TEST_SUBMODULE(class_sh_trampoline_shared_ptr_cpp_arg, m) { py::classh(m, "SpGoAwayTester") .def(py::init<>()) .def_readwrite("obj", &SpGoAwayTester::m_obj); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.py b/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.py index 431edb71..54575ddc 100644 --- a/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.py +++ b/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.py @@ -4,6 +4,9 @@ import pybind11_tests.class_sh_trampoline_shared_ptr_cpp_arg as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + def test_shared_ptr_cpp_arg(): import weakref diff --git a/tests/test_class_sh_trampoline_unique_ptr.cpp b/tests/test_class_sh_trampoline_unique_ptr.cpp index c4b34245..13dc27b0 100644 --- a/tests/test_class_sh_trampoline_unique_ptr.cpp +++ b/tests/test_class_sh_trampoline_unique_ptr.cpp @@ -39,6 +39,7 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_trampoline_unique_pt namespace pybind11_tests { namespace class_sh_trampoline_unique_ptr { +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT class PyClass : public Class, public py::trampoline_self_life_support { public: std::unique_ptr clone() const override { @@ -47,11 +48,18 @@ class PyClass : public Class, public py::trampoline_self_life_support { int foo() const override { PYBIND11_OVERRIDE_PURE(int, Class, foo); } }; +#endif } // namespace class_sh_trampoline_unique_ptr } // namespace pybind11_tests TEST_SUBMODULE(class_sh_trampoline_unique_ptr, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + using namespace pybind11_tests::class_sh_trampoline_unique_ptr; py::classh(m, "Class") @@ -63,4 +71,5 @@ TEST_SUBMODULE(class_sh_trampoline_unique_ptr, m) { m.def("clone", [](const Class &obj) { return obj.clone(); }); m.def("clone_and_foo", [](const Class &obj) { return obj.clone()->foo(); }); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_trampoline_unique_ptr.py b/tests/test_class_sh_trampoline_unique_ptr.py index 7799df6d..22505dc6 100644 --- a/tests/test_class_sh_trampoline_unique_ptr.py +++ b/tests/test_class_sh_trampoline_unique_ptr.py @@ -1,7 +1,12 @@ from __future__ import annotations +import pytest + import pybind11_tests.class_sh_trampoline_unique_ptr as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + class MyClass(m.Class): def foo(self): diff --git a/tests/test_class_sh_unique_ptr_custom_deleter.cpp b/tests/test_class_sh_unique_ptr_custom_deleter.cpp index 070a10e0..973bf490 100644 --- a/tests/test_class_sh_unique_ptr_custom_deleter.cpp +++ b/tests/test_class_sh_unique_ptr_custom_deleter.cpp @@ -31,9 +31,16 @@ namespace pybind11_tests { namespace class_sh_unique_ptr_custom_deleter { TEST_SUBMODULE(class_sh_unique_ptr_custom_deleter, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + py::classh(m, "Pet").def_readwrite("name", &Pet::name); m.def("create", &Pet::New); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } } // namespace class_sh_unique_ptr_custom_deleter diff --git a/tests/test_class_sh_unique_ptr_custom_deleter.py b/tests/test_class_sh_unique_ptr_custom_deleter.py index 34aa5206..f246e2d7 100644 --- a/tests/test_class_sh_unique_ptr_custom_deleter.py +++ b/tests/test_class_sh_unique_ptr_custom_deleter.py @@ -1,7 +1,12 @@ from __future__ import annotations +import pytest + from pybind11_tests import class_sh_unique_ptr_custom_deleter as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + def test_create(): pet = m.create("abc") diff --git a/tests/test_class_sh_unique_ptr_member.cpp b/tests/test_class_sh_unique_ptr_member.cpp index 3de12fe6..1341f140 100644 --- a/tests/test_class_sh_unique_ptr_member.cpp +++ b/tests/test_class_sh_unique_ptr_member.cpp @@ -45,6 +45,12 @@ namespace pybind11_tests { namespace class_sh_unique_ptr_member { TEST_SUBMODULE(class_sh_unique_ptr_member, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + py::classh(m, "pointee").def(py::init<>()).def("get_int", &pointee::get_int); m.def("make_unique_pointee", make_unique_pointee); @@ -54,6 +60,7 @@ TEST_SUBMODULE(class_sh_unique_ptr_member, m) { .def("is_owner", &ptr_owner::is_owner) .def("give_up_ownership_via_unique_ptr", &ptr_owner::give_up_ownership_via_unique_ptr) .def("give_up_ownership_via_shared_ptr", &ptr_owner::give_up_ownership_via_shared_ptr); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } } // namespace class_sh_unique_ptr_member diff --git a/tests/test_class_sh_unique_ptr_member.py b/tests/test_class_sh_unique_ptr_member.py index a5d2ccd2..dc1d5482 100644 --- a/tests/test_class_sh_unique_ptr_member.py +++ b/tests/test_class_sh_unique_ptr_member.py @@ -4,6 +4,9 @@ from pybind11_tests import class_sh_unique_ptr_member as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + def test_make_unique_pointee(): obj = m.make_unique_pointee() diff --git a/tests/test_class_sh_virtual_py_cpp_mix.cpp b/tests/test_class_sh_virtual_py_cpp_mix.cpp index 467d55aa..a68cb76a 100644 --- a/tests/test_class_sh_virtual_py_cpp_mix.cpp +++ b/tests/test_class_sh_virtual_py_cpp_mix.cpp @@ -31,6 +31,8 @@ int get_from_cpp_plainc_ptr(const Base *b) { return b->get() + 4000; } int get_from_cpp_unique_ptr(std::unique_ptr b) { return b->get() + 5000; } +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + struct BaseVirtualOverrider : Base, py::trampoline_self_life_support { using Base::Base; @@ -43,6 +45,8 @@ struct CppDerivedVirtualOverrider : CppDerived, py::trampoline_self_life_support int get() const override { PYBIND11_OVERRIDE(int, CppDerived, get); } }; +#endif + } // namespace class_sh_virtual_py_cpp_mix } // namespace pybind11_tests @@ -53,6 +57,12 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(CppDerivedPlain) PYBIND11_SMART_HOLDER_TYPE_CASTERS(CppDerived) TEST_SUBMODULE(class_sh_virtual_py_cpp_mix, m) { + m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + false; +#else + true; + py::classh(m, "Base").def(py::init<>()).def("get", &Base::get); py::classh(m, "CppDerivedPlain").def(py::init<>()); @@ -61,4 +71,5 @@ TEST_SUBMODULE(class_sh_virtual_py_cpp_mix, m) { m.def("get_from_cpp_plainc_ptr", get_from_cpp_plainc_ptr, py::arg("b")); m.def("get_from_cpp_unique_ptr", get_from_cpp_unique_ptr, py::arg("b")); +#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_virtual_py_cpp_mix.py b/tests/test_class_sh_virtual_py_cpp_mix.py index 33133eb8..3361713c 100644 --- a/tests/test_class_sh_virtual_py_cpp_mix.py +++ b/tests/test_class_sh_virtual_py_cpp_mix.py @@ -4,6 +4,9 @@ from pybind11_tests import class_sh_virtual_py_cpp_mix as m +if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: + pytest.skip("smart_holder not available.", allow_module_level=True) + class PyBase(m.Base): # Avoiding name PyDerived, for more systematic naming. def __init__(self): diff --git a/tests/test_classh_mock.cpp b/tests/test_classh_mock.cpp index 38e765fb..13532032 100644 --- a/tests/test_classh_mock.cpp +++ b/tests/test_classh_mock.cpp @@ -1,18 +1,20 @@ #include "pybind11_tests.h" -// The main purpose of this test is to ensure the suggested BOILERPLATE code block below is -// correct. +// The main purpose of this test was to ensure that the suggested +// BOILERPLATE code block (NOW DEPRECATED!) block below is correct. // Copy this block of code into your project. // Replace FOOEXT with the name of your project. -// BOILERPLATE BEGIN +// BOILERPLATE BEGIN DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED #ifdef FOOEXT_USING_PYBIND11_SMART_HOLDER # include #else # include PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +# ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT template using classh = class_; +# endif PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) # ifndef PYBIND11_SH_AVL # define PYBIND11_SH_AVL(...) std::shared_ptr<__VA_ARGS__> // "Smart_Holder if AVaiLable" @@ -27,7 +29,7 @@ PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) # define PYBIND11_TYPE_CASTER_BASE_HOLDER(...) # endif #endif -// BOILERPLATE END +// BOILERPLATE END DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED namespace { struct FooUc {}; @@ -37,8 +39,8 @@ struct FooSc {}; struct FooSp {}; } // namespace -PYBIND11_SMART_HOLDER_TYPE_CASTERS(FooUp) -PYBIND11_SMART_HOLDER_TYPE_CASTERS(FooSp) +PYBIND11_SMART_HOLDER_TYPE_CASTERS(FooUp) // DEPRECATED +PYBIND11_SMART_HOLDER_TYPE_CASTERS(FooSp) // DEPRECATED PYBIND11_TYPE_CASTER_BASE_HOLDER(FooSa, std::shared_ptr) diff --git a/tests/test_embed/test_interpreter.cpp b/tests/test_embed/test_interpreter.cpp index 6e9506d6..c6c8a22d 100644 --- a/tests/test_embed/test_interpreter.cpp +++ b/tests/test_embed/test_interpreter.cpp @@ -66,7 +66,7 @@ PYBIND11_EMBEDDED_MODULE(widget_module, m) { PYBIND11_EMBEDDED_MODULE(trampoline_module, m) { py::class_(m, "test_override_cache_helper") + std::shared_ptr>(m, "test_override_cache_helper") .def(py::init_alias<>()) .def("func", &test_override_cache_helper::func); } diff --git a/tests/test_factory_constructors.cpp b/tests/test_factory_constructors.cpp index c8e065bc..a387cd2e 100644 --- a/tests/test_factory_constructors.cpp +++ b/tests/test_factory_constructors.cpp @@ -250,7 +250,7 @@ TEST_SUBMODULE(factory_constructors, m) { }; // test_init_factory_basic, test_init_factory_casting - py::class_ pyTestFactory3(m, "TestFactory3"); + py::class_> pyTestFactory3(m, "TestFactory3"); pyTestFactory3 .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); })) .def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); })); @@ -277,12 +277,12 @@ TEST_SUBMODULE(factory_constructors, m) { .def_readwrite("value", &TestFactory3::value); // test_init_factory_casting - py::class_(m, "TestFactory4") + py::class_>(m, "TestFactory4") .def(py::init(c4a)) // pointer ; // Doesn't need to be registered, but registering makes getting ConstructorStats easier: - py::class_(m, "TestFactory5"); + py::class_>(m, "TestFactory5"); // test_init_factory_alias // Alias testing @@ -305,7 +305,7 @@ TEST_SUBMODULE(factory_constructors, m) { // test_init_factory_dual // Separate alias constructor testing - py::class_(m, "TestFactory7") + py::class_>(m, "TestFactory7") .def(py::init([](int i) { return TestFactory7(i); }, [](int i) { return PyTF7(i); })) .def(py::init([](pointer_tag, int i) { return new TestFactory7(i); }, [](pointer_tag, int i) { return new PyTF7(i); })) diff --git a/tests/test_factory_constructors.py b/tests/test_factory_constructors.py index 8a8ae66d..0ddad5e3 100644 --- a/tests/test_factory_constructors.py +++ b/tests/test_factory_constructors.py @@ -280,11 +280,10 @@ def get(self): assert not g1.has_alias() with pytest.raises(TypeError) as excinfo: PythFactory7(tag.shared_ptr, tag.invalid_base, 14) - assert str(excinfo.value) in ( - "pybind11::init(): construction failed: returned holder-wrapped instance is not an " - "alias instance", - "pybind11::init(): construction failed: returned std::shared_ptr pointee is not an " - "alias instance", + assert ( + str(excinfo.value) + == "pybind11::init(): construction failed: returned holder-wrapped instance is not an " + "alias instance" ) assert [i.alive() for i in cstats] == [13, 7] diff --git a/tests/test_methods_and_attributes.cpp b/tests/test_methods_and_attributes.cpp index c13ae933..f433847c 100644 --- a/tests/test_methods_and_attributes.cpp +++ b/tests/test_methods_and_attributes.cpp @@ -121,7 +121,7 @@ class NoneTester { }; int none1(const NoneTester &obj) { return obj.answer; } int none2(NoneTester *obj) { return obj ? obj->answer : -1; } -int none3(const std::shared_ptr &obj) { return obj ? obj->answer : -1; } +int none3(std::shared_ptr &obj) { return obj ? obj->answer : -1; } int none4(std::shared_ptr *obj) { return obj && *obj ? (*obj)->answer : -1; } int none5(const std::shared_ptr &obj) { return obj ? obj->answer : -1; } @@ -417,21 +417,17 @@ TEST_SUBMODULE(methods_and_attributes, m) { // [workaround(intel)] ICC 20/21 breaks with py::arg().stuff, using py::arg{}.stuff works. // test_accepts_none - py::class_(m, "NoneTester").def(py::init<>()); + py::class_>(m, "NoneTester").def(py::init<>()); m.def("no_none1", &none1, py::arg{}.none(false)); m.def("no_none2", &none2, py::arg{}.none(false)); m.def("no_none3", &none3, py::arg{}.none(false)); + m.def("no_none4", &none4, py::arg{}.none(false)); m.def("no_none5", &none5, py::arg{}.none(false)); m.def("ok_none1", &none1); m.def("ok_none2", &none2, py::arg{}.none(true)); m.def("ok_none3", &none3); - m.def("ok_none5", &none5); - -#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT - // smart_holder_type_caster does not support conversion to `const shared_ptr *`. - m.def("no_none4", &none4, py::arg{}.none(false)); m.def("ok_none4", &none4, py::arg{}.none(true)); -#endif + m.def("ok_none5", &none5); m.def("no_none_kwarg", &none2, "a"_a.none(false)); m.def("no_none_kwarg_kw_only", &none2, py::kw_only(), "a"_a.none(false)); diff --git a/tests/test_methods_and_attributes.py b/tests/test_methods_and_attributes.py index ec794457..dfa31f54 100644 --- a/tests/test_methods_and_attributes.py +++ b/tests/test_methods_and_attributes.py @@ -387,10 +387,12 @@ def test_accepts_none(msg): assert m.no_none1(a) == 42 assert m.no_none2(a) == 42 assert m.no_none3(a) == 42 + assert m.no_none4(a) == 42 assert m.no_none5(a) == 42 assert m.ok_none1(a) == 42 assert m.ok_none2(a) == 42 assert m.ok_none3(a) == 42 + assert m.ok_none4(a) == 42 assert m.ok_none5(a) == 42 with pytest.raises(TypeError) as excinfo: @@ -402,6 +404,9 @@ def test_accepts_none(msg): with pytest.raises(TypeError) as excinfo: m.no_none3(None) assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.no_none4(None) + assert "incompatible function arguments" in str(excinfo.value) with pytest.raises(TypeError) as excinfo: m.no_none5(None) assert "incompatible function arguments" in str(excinfo.value) @@ -422,6 +427,7 @@ def test_accepts_none(msg): # The rest take the argument as pointer or holder, and accept None: assert m.ok_none2(None) == -1 assert m.ok_none3(None) == -1 + assert m.ok_none4(None) == -1 assert m.ok_none5(None) == -1 with pytest.raises(TypeError) as excinfo: @@ -437,14 +443,6 @@ def test_accepts_none(msg): m.no_none_kwarg_kw_only(a=None) assert "incompatible function arguments" in str(excinfo.value) - if hasattr(m, "no_none4"): - assert m.no_none4(a) == 42 - assert m.ok_none4(a) == 42 - with pytest.raises(TypeError) as excinfo: - m.no_none4(None) - assert "incompatible function arguments" in str(excinfo.value) - assert m.ok_none4(None) == -1 - def test_casts_none(): """#2778: implicit casting from None to object (not pointer)""" diff --git a/tests/test_multiple_inheritance.cpp b/tests/test_multiple_inheritance.cpp index 3005b0d5..5916ae90 100644 --- a/tests/test_multiple_inheritance.cpp +++ b/tests/test_multiple_inheritance.cpp @@ -148,15 +148,15 @@ TEST_SUBMODULE(multiple_inheritance, m) { // test_multiple_inheritance_virtbase // Test the case where not all base classes are specified, and where pybind11 requires the // py::multiple_inheritance flag to perform proper casting between types. - py::class_(m, "Base1a") + py::class_>(m, "Base1a") .def(py::init()) .def("foo", &Base1a::foo); - py::class_(m, "Base2a") + py::class_>(m, "Base2a") .def(py::init()) .def("bar", &Base2a::bar); - py::class_( + py::class_>( m, "Base12a", py::multiple_inheritance()) .def(py::init()); @@ -173,14 +173,14 @@ TEST_SUBMODULE(multiple_inheritance, m) { }; struct I801E : I801B3, I801D {}; - py::class_(m, "I801B1") + py::class_>(m, "I801B1") .def(py::init<>()) .def_readonly("a", &I801B1::a); - py::class_(m, "I801B2") + py::class_>(m, "I801B2") .def(py::init<>()) .def_readonly("b", &I801B2::b); - py::class_(m, "I801C").def(py::init<>()); - py::class_(m, "I801D").def(py::init<>()); + py::class_>(m, "I801C").def(py::init<>()); + py::class_>(m, "I801D").def(py::init<>()); // Two separate issues here: first, we want to recognize a pointer to a base type as being a // known instance even when the pointer value is unequal (i.e. due to a non-first diff --git a/tests/test_smart_ptr.cpp b/tests/test_smart_ptr.cpp index 1d1d8a16..496073b3 100644 --- a/tests/test_smart_ptr.cpp +++ b/tests/test_smart_ptr.cpp @@ -287,42 +287,6 @@ PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr); PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator); PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator); -PYBIND11_TYPE_CASTER_BASE_HOLDER(Object, ref) -PYBIND11_TYPE_CASTER_BASE_HOLDER(MyObject1, ref) -PYBIND11_TYPE_CASTER_BASE_HOLDER(MyObject2, std::shared_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(MyObject3, std::shared_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(MyObject4, std::unique_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(MyObject4a, std::unique_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(MyObject4b, std::unique_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(MyObject5, huge_unique_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(SharedPtrRef::A, std::shared_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(SharedPtrRef, std::unique_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(SharedFromThisRef::B, std::shared_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(SharedFromThisRef, std::unique_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(SharedFromThisVirt, std::shared_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(C, custom_unique_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(TypeForHolderWithAddressOf, - shared_ptr_with_addressof_operator) -PYBIND11_TYPE_CASTER_BASE_HOLDER( - TypeForMoveOnlyHolderWithAddressOf, - unique_ptr_with_addressof_operator) -PYBIND11_TYPE_CASTER_BASE_HOLDER(HeldByDefaultHolder, std::unique_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(ElementBase, std::shared_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(ElementA, std::shared_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(ElementList, std::shared_ptr) - -#ifdef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT -// To prevent triggering a static_assert in the smart_holder code. -// This is a very special case, because the associated test exercises a holder mismatch. -namespace pybind11 { -namespace detail { -template <> -class type_caster> - : public copyable_holder_caster> {}; -} // namespace detail -} // namespace pybind11 -#endif - TEST_SUBMODULE(smart_ptr, m) { // Please do not interleave `struct` and `class` definitions with bindings code, // but implement `struct`s and `class`es in the anonymous namespace above. diff --git a/tests/test_smart_ptr.py b/tests/test_smart_ptr.py index 893d609f..bf0ae4ae 100644 --- a/tests/test_smart_ptr.py +++ b/tests/test_smart_ptr.py @@ -301,9 +301,9 @@ def test_smart_ptr_from_default(): instance = m.HeldByDefaultHolder() with pytest.raises(RuntimeError) as excinfo: m.HeldByDefaultHolder.load_shared_ptr(instance) - assert str(excinfo.value) in ( - "Unable to load a smart-pointer type from a non-smart_holder instance.", - "Unable to load a custom holder type from a default-holder instance", + assert ( + "Unable to load a custom holder type from a " + "default-holder instance" in str(excinfo.value) ) diff --git a/tests/test_virtual_functions.cpp b/tests/test_virtual_functions.cpp index 17a999ef..93b136ad 100644 --- a/tests/test_virtual_functions.cpp +++ b/tests/test_virtual_functions.cpp @@ -406,7 +406,7 @@ TEST_SUBMODULE(virtual_functions, m) { py::class_(m, "test_override_cache_helper") + std::shared_ptr>(m, "test_override_cache_helper") .def(py::init_alias<>()) .def("func", &test_override_cache_helper::func); diff --git a/ubench/holder_comparison.cpp b/ubench/holder_comparison.cpp index 75896c1b..f532bcfd 100644 --- a/ubench/holder_comparison.cpp +++ b/ubench/holder_comparison.cpp @@ -1,4 +1,4 @@ -#include +#include #include "number_bucket.h" @@ -22,6 +22,8 @@ void wrap_number_bucket(py::module m, const char *class_name) { .def("add", &WrappedType::add, py::arg("other")); } +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + template class padded_unique_ptr { std::unique_ptr ptr; @@ -35,20 +37,21 @@ class padded_unique_ptr { static_assert(sizeof(padded_unique_ptr) == sizeof(py::smart_holder), "Unexpected sizeof mismatch."); +#endif + } // namespace hc +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT PYBIND11_DECLARE_HOLDER_TYPE(T, hc::padded_unique_ptr); - -PYBIND11_TYPE_CASTER_BASE_HOLDER(hc::nb_up, std::unique_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(hc::nb_sp, std::shared_ptr) -PYBIND11_TYPE_CASTER_BASE_HOLDER(hc::nb_pu, hc::padded_unique_ptr) -PYBIND11_SMART_HOLDER_TYPE_CASTERS(hc::nb_sh) +#endif PYBIND11_MODULE(pybind11_ubench_holder_comparison, m) { using namespace hc; - m.def("sizeof_smart_holder", []() { return sizeof(py::smart_holder); }); wrap_number_bucket>(m, "number_bucket_up"); wrap_number_bucket>(m, "number_bucket_sp"); +#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.def("sizeof_smart_holder", []() { return sizeof(py::smart_holder); }); wrap_number_bucket>(m, "number_bucket_pu"); wrap_number_bucket(m, "number_bucket_sh"); +#endif } From 916778df48dc1c05b359ac74303ed18e5104799b Mon Sep 17 00:00:00 2001 From: fred-sch <73998525+fred-sch@users.noreply.github.com> Date: Fri, 2 Aug 2024 21:17:15 +0200 Subject: [PATCH 4/7] fix: typo in documentation (#5284) --- docs/compiling.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/compiling.rst b/docs/compiling.rst index 234f53fb..0c788335 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -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 From 7c6fe491063d4a7efdfd84c36b3b045cbcd253a0 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 4 Aug 2024 23:16:44 +0700 Subject: [PATCH 5/7] find . -name '*.h' -o -name '*.cpp' -o -name '*.py' | xargs -n 1 -- sed -i 's/PYBIND11_HAVE_/PYBIND11_HAS_/g' (#5286) --- include/pybind11/attr.h | 2 +- include/pybind11/cast.h | 10 +++++----- include/pybind11/detail/init.h | 4 ++-- include/pybind11/detail/internals.h | 4 ++-- include/pybind11/detail/type_caster_base.h | 6 +++--- include/pybind11/detail/using_smart_holder.h | 6 +++--- include/pybind11/pybind11.h | 16 ++++++++-------- include/pybind11/trampoline_self_life_support.h | 4 ++-- tests/class_sh_module_local_0.cpp | 6 +++--- tests/class_sh_module_local_1.cpp | 6 +++--- tests/class_sh_module_local_2.cpp | 6 +++--- tests/test_class.cpp | 2 +- tests/test_class_sh_basic.cpp | 6 +++--- tests/test_class_sh_basic.py | 2 +- tests/test_class_sh_disowning.cpp | 6 +++--- tests/test_class_sh_disowning.py | 2 +- tests/test_class_sh_disowning_mi.cpp | 6 +++--- tests/test_class_sh_disowning_mi.py | 2 +- tests/test_class_sh_factory_constructors.cpp | 6 +++--- tests/test_class_sh_factory_constructors.py | 2 +- tests/test_class_sh_inheritance.cpp | 6 +++--- tests/test_class_sh_inheritance.py | 2 +- tests/test_class_sh_mi_thunks.cpp | 6 +++--- tests/test_class_sh_mi_thunks.py | 2 +- tests/test_class_sh_module_local.py | 2 +- tests/test_class_sh_property.cpp | 6 +++--- tests/test_class_sh_property.py | 2 +- tests/test_class_sh_property_non_owning.cpp | 6 +++--- tests/test_class_sh_property_non_owning.py | 2 +- tests/test_class_sh_shared_ptr_copy_move.cpp | 6 +++--- tests/test_class_sh_shared_ptr_copy_move.py | 2 +- tests/test_class_sh_trampoline_basic.cpp | 12 ++++++------ tests/test_class_sh_trampoline_basic.py | 2 +- ...est_class_sh_trampoline_self_life_support.cpp | 8 ++++---- ...test_class_sh_trampoline_self_life_support.py | 2 +- ...test_class_sh_trampoline_shared_from_this.cpp | 8 ++++---- .../test_class_sh_trampoline_shared_from_this.py | 2 +- ...st_class_sh_trampoline_shared_ptr_cpp_arg.cpp | 6 +++--- ...est_class_sh_trampoline_shared_ptr_cpp_arg.py | 2 +- tests/test_class_sh_trampoline_unique_ptr.cpp | 8 ++++---- tests/test_class_sh_trampoline_unique_ptr.py | 2 +- .../test_class_sh_unique_ptr_custom_deleter.cpp | 6 +++--- tests/test_class_sh_unique_ptr_custom_deleter.py | 2 +- tests/test_class_sh_unique_ptr_member.cpp | 6 +++--- tests/test_class_sh_unique_ptr_member.py | 2 +- tests/test_class_sh_virtual_py_cpp_mix.cpp | 8 ++++---- tests/test_class_sh_virtual_py_cpp_mix.py | 2 +- tests/test_classh_mock.cpp | 2 +- ubench/holder_comparison.cpp | 6 +++--- 49 files changed, 116 insertions(+), 116 deletions(-) diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index 74dc361e..d7a60866 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -331,7 +331,7 @@ struct type_record { /// Is the class inheritable from python classes? bool is_final : 1; -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT holder_enum_t holder_enum_v = holder_enum_t::undefined; #endif diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 656b7666..d3b3fe07 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -836,7 +836,7 @@ struct copyable_holder_caster : public type_caster_base { holder_type holder; }; -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT template struct copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled : std::true_type {}; @@ -963,7 +963,7 @@ struct copyable_holder_caster< smart_holder_type_caster_support::load_helper> sh_load_helper; // Const2Mutbl }; -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT /// Specialize for the common std::shared_ptr, so users don't need to template @@ -985,7 +985,7 @@ struct move_only_holder_caster { static constexpr auto name = type_caster_base::name; }; -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT template struct move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled : std::true_type {}; @@ -1089,7 +1089,7 @@ struct move_only_holder_caster< smart_holder_type_caster_support::load_helper> sh_load_helper; // Const2Mutbl }; -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT template class type_caster> @@ -1127,7 +1127,7 @@ struct is_holder_type template struct is_holder_type> : std::true_type {}; -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT template struct is_holder_type : std::true_type {}; #endif diff --git a/include/pybind11/detail/init.h b/include/pybind11/detail/init.h index af8ec6dd..ae2e146b 100644 --- a/include/pybind11/detail/init.h +++ b/include/pybind11/detail/init.h @@ -198,7 +198,7 @@ void construct(value_and_holder &v_h, Alias &&result, bool) { v_h.value_ptr() = new Alias(std::move(result)); } -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT template smart_holder init_smart_holder_from_unique_ptr(std::unique_ptr &&unq_ptr, @@ -268,7 +268,7 @@ void construct(value_and_holder &v_h, v_h.type->init_instance(v_h.inst, &smhldr); } -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT // Implementing class for py::init<...>() template diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index d8b5c6b3..f27b0a66 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -240,7 +240,7 @@ struct internals { #if PYBIND11_INTERNALS_VERSION >= 6 -# define PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +# define PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT enum class holder_enum_t : uint8_t { undefined, @@ -280,7 +280,7 @@ struct type_info { bool default_holder : 1; /* true if this is a type registered with py::module_local */ bool module_local : 1; -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT holder_enum_t holder_enum_v = holder_enum_t::undefined; #endif }; diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index c2706878..92415718 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -472,7 +472,7 @@ inline PyThreadState *get_thread_state_unchecked() { void keep_alive_impl(handle nurse, handle patient); inline PyObject *make_new_instance(PyTypeObject *type); -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT // SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code. inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo); @@ -823,7 +823,7 @@ struct load_helper : value_and_holder_helper { PYBIND11_NAMESPACE_END(smart_holder_type_caster_support) -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT class type_caster_generic { public: @@ -929,7 +929,7 @@ class type_caster_generic { // Base methods for generic caster; there are overridden in copyable_holder_caster void load_value(value_and_holder &&v_h) { -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { smart_holder_type_caster_support::value_and_holder_helper v_h_helper; v_h_helper.loaded_v_h = v_h; diff --git a/include/pybind11/detail/using_smart_holder.h b/include/pybind11/detail/using_smart_holder.h index c47b691d..3d046320 100644 --- a/include/pybind11/detail/using_smart_holder.h +++ b/include/pybind11/detail/using_smart_holder.h @@ -9,19 +9,19 @@ #include -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT # include "smart_holder_poc.h" #endif PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT using pybindit::memory::smart_holder; #endif PYBIND11_NAMESPACE_BEGIN(detail) -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT template using is_smart_holder = std::is_same; #else diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 0f2b72cf..2a88a94a 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1424,7 +1424,7 @@ class generic_type : public object { tinfo->simple_ancestors = true; tinfo->default_holder = rec.default_holder; tinfo->module_local = rec.module_local; -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT tinfo->holder_enum_v = rec.holder_enum_v; #endif @@ -1631,7 +1631,7 @@ PYBIND11_NAMESPACE_END(detail) template struct property_cpp_function : detail::property_cpp_function_classic {}; -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT PYBIND11_NAMESPACE_BEGIN(detail) @@ -1810,10 +1810,10 @@ struct property_cpp_function< detail::both_t_and_d_use_type_caster_base>::value>> : detail::property_cpp_function_sh_unique_ptr_member {}; -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT #if defined(PYBIND11_USE_SMART_HOLDER_AS_DEFAULT) \ - && defined(PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT) + && defined(PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT) // NOTE: THIS IS MEANT FOR STRESS-TESTING ONLY! // As of PR #5257, for production use, there is no longer a strong reason to make // smart_holder the default holder: @@ -1881,7 +1881,7 @@ class class_ : public detail::generic_type { // A more fitting name would be uses_unique_ptr_holder. record.default_holder = detail::is_instantiation::value; -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT if (detail::is_instantiation::value) { record.holder_enum_v = detail::holder_enum_t::std_unique_ptr; } else if (detail::is_instantiation::value) { @@ -2226,7 +2226,7 @@ class class_ : public detail::generic_type { init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr()); } -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT template static bool try_initialization_using_shared_from_this(holder_type *, WrappedType *, ...) { @@ -2288,7 +2288,7 @@ class class_ : public detail::generic_type { v_h.set_holder_constructed(); } -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT /// Deallocates an instance; via holder, if constructed; otherwise via operator delete. static void dealloc(detail::value_and_holder &v_h) { @@ -2330,7 +2330,7 @@ class class_ : public detail::generic_type { } }; -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT // Supports easier switching between py::class_ and py::class_: // users can simply replace the `_` in `class_` with `h` or vice versa. diff --git a/include/pybind11/trampoline_self_life_support.h b/include/pybind11/trampoline_self_life_support.h index 06883572..cef69632 100644 --- a/include/pybind11/trampoline_self_life_support.h +++ b/include/pybind11/trampoline_self_life_support.h @@ -6,7 +6,7 @@ #include "detail/internals.h" -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT # include "detail/common.h" # include "detail/using_smart_holder.h" @@ -64,4 +64,4 @@ struct trampoline_self_life_support { PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT diff --git a/tests/class_sh_module_local_0.cpp b/tests/class_sh_module_local_0.cpp index 8a0ac0f6..4b570624 100644 --- a/tests/class_sh_module_local_0.cpp +++ b/tests/class_sh_module_local_0.cpp @@ -19,8 +19,8 @@ atyp rtrn_valu_atyp() { return atyp(); } PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_module_local::atyp) PYBIND11_MODULE(class_sh_module_local_0, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -30,5 +30,5 @@ PYBIND11_MODULE(class_sh_module_local_0, m) { m.def("get_mtxt", get_mtxt); m.def("rtrn_valu_atyp", rtrn_valu_atyp); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/class_sh_module_local_1.cpp b/tests/class_sh_module_local_1.cpp index e5a45844..5197d25f 100644 --- a/tests/class_sh_module_local_1.cpp +++ b/tests/class_sh_module_local_1.cpp @@ -18,8 +18,8 @@ std::string get_mtxt(const atyp &obj) { return obj.mtxt; } PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_module_local::atyp) PYBIND11_MODULE(class_sh_module_local_1, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -36,5 +36,5 @@ PYBIND11_MODULE(class_sh_module_local_1, m) { .def("tag", [](const atyp &) { return 1; }); m.def("get_mtxt", get_mtxt); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/class_sh_module_local_2.cpp b/tests/class_sh_module_local_2.cpp index 5dd4104a..0e3a39ba 100644 --- a/tests/class_sh_module_local_2.cpp +++ b/tests/class_sh_module_local_2.cpp @@ -18,8 +18,8 @@ std::string get_mtxt(const atyp &obj) { return obj.mtxt; } PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_module_local::atyp) PYBIND11_MODULE(class_sh_module_local_2, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -36,5 +36,5 @@ PYBIND11_MODULE(class_sh_module_local_2, m) { .def("tag", [](const atyp &) { return 2; }); m.def("get_mtxt", get_mtxt); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class.cpp b/tests/test_class.cpp index 73ab6090..d15dc391 100644 --- a/tests/test_class.cpp +++ b/tests/test_class.cpp @@ -93,7 +93,7 @@ TEST_SUBMODULE(class_, m) { struct ToBeHeldByUniquePtr {}; py::class_>(m, "ToBeHeldByUniquePtr") .def(py::init<>()); -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT m.def("pass_unique_ptr", [](std::unique_ptr &&) {}); #else m.attr("pass_unique_ptr") = py::none(); diff --git a/tests/test_class_sh_basic.cpp b/tests/test_class_sh_basic.cpp index 460dd1bd..9602387b 100644 --- a/tests/test_class_sh_basic.cpp +++ b/tests/test_class_sh_basic.cpp @@ -145,8 +145,8 @@ namespace pybind11_tests { namespace class_sh_basic { TEST_SUBMODULE(class_sh_basic, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -246,7 +246,7 @@ TEST_SUBMODULE(class_sh_basic, m) { []() { return CastUnusualOpRefConstRef(LocalUnusualOpRef()); }); m.def("CallCastUnusualOpRefMovable", []() { return CastUnusualOpRefMovable(LocalUnusualOpRef()); }); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } } // namespace class_sh_basic diff --git a/tests/test_class_sh_basic.py b/tests/test_class_sh_basic.py index b3d9b98c..87f1f8f0 100644 --- a/tests/test_class_sh_basic.py +++ b/tests/test_class_sh_basic.py @@ -7,7 +7,7 @@ from pybind11_tests import class_sh_basic as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_disowning.cpp b/tests/test_class_sh_disowning.cpp index aba3dc81..0474ca1d 100644 --- a/tests/test_class_sh_disowning.cpp +++ b/tests/test_class_sh_disowning.cpp @@ -32,8 +32,8 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning::Atype<1>) PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning::Atype<2>) TEST_SUBMODULE(class_sh_disowning, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -49,5 +49,5 @@ TEST_SUBMODULE(class_sh_disowning, m) { m.def("overloaded", (int (*)(std::unique_ptr>, int)) & overloaded); m.def("overloaded", (int (*)(std::unique_ptr>, int)) & overloaded); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_disowning.py b/tests/test_class_sh_disowning.py index 36e46101..5e2918e0 100644 --- a/tests/test_class_sh_disowning.py +++ b/tests/test_class_sh_disowning.py @@ -4,7 +4,7 @@ from pybind11_tests import class_sh_disowning as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_disowning_mi.cpp b/tests/test_class_sh_disowning_mi.cpp index 1bba4015..c18529b2 100644 --- a/tests/test_class_sh_disowning_mi.cpp +++ b/tests/test_class_sh_disowning_mi.cpp @@ -57,8 +57,8 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning_mi::Base1) PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning_mi::Base2) TEST_SUBMODULE(class_sh_disowning_mi, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -98,5 +98,5 @@ TEST_SUBMODULE(class_sh_disowning_mi, m) { py::classh(m, "Base2").def(py::init()).def("bar", &Base2::bar); m.def("disown_base1", disown_base1); m.def("disown_base2", disown_base2); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_disowning_mi.py b/tests/test_class_sh_disowning_mi.py index 781db8c0..238a76f2 100644 --- a/tests/test_class_sh_disowning_mi.py +++ b/tests/test_class_sh_disowning_mi.py @@ -5,7 +5,7 @@ import env # noqa: F401 from pybind11_tests import class_sh_disowning_mi as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_factory_constructors.cpp b/tests/test_class_sh_factory_constructors.cpp index 7ee56a8b..1e40ed96 100644 --- a/tests/test_class_sh_factory_constructors.cpp +++ b/tests/test_class_sh_factory_constructors.cpp @@ -87,8 +87,8 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::with_alias) TEST_SUBMODULE(class_sh_factory_constructors, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -183,5 +183,5 @@ TEST_SUBMODULE(class_sh_factory_constructors, m) { [](int, int, int, int, int) { return std::make_shared(); // Invalid alias factory. })); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_factory_constructors.py b/tests/test_class_sh_factory_constructors.py index 38e529e5..0ea93012 100644 --- a/tests/test_class_sh_factory_constructors.py +++ b/tests/test_class_sh_factory_constructors.py @@ -4,7 +4,7 @@ from pybind11_tests import class_sh_factory_constructors as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_inheritance.cpp b/tests/test_class_sh_inheritance.cpp index af57f03b..ebcca2c0 100644 --- a/tests/test_class_sh_inheritance.cpp +++ b/tests/test_class_sh_inheritance.cpp @@ -73,8 +73,8 @@ namespace pybind11_tests { namespace class_sh_inheritance { TEST_SUBMODULE(class_sh_inheritance, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -105,7 +105,7 @@ TEST_SUBMODULE(class_sh_inheritance, m) { m.def("pass_cptr_base1", pass_cptr_base1); m.def("pass_cptr_base2", pass_cptr_base2); m.def("pass_cptr_drvd2", pass_cptr_drvd2); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } } // namespace class_sh_inheritance diff --git a/tests/test_class_sh_inheritance.py b/tests/test_class_sh_inheritance.py index f03cee36..2b681aa8 100644 --- a/tests/test_class_sh_inheritance.py +++ b/tests/test_class_sh_inheritance.py @@ -4,7 +4,7 @@ from pybind11_tests import class_sh_inheritance as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_mi_thunks.cpp b/tests/test_class_sh_mi_thunks.cpp index 0990c34f..edf84726 100644 --- a/tests/test_class_sh_mi_thunks.cpp +++ b/tests/test_class_sh_mi_thunks.cpp @@ -40,8 +40,8 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Base1) PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Derived) TEST_SUBMODULE(class_sh_mi_thunks, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -103,5 +103,5 @@ TEST_SUBMODULE(class_sh_mi_thunks, m) { } return obj_der->vec.size(); }); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_mi_thunks.py b/tests/test_class_sh_mi_thunks.py index 12b6e9d9..65983b76 100644 --- a/tests/test_class_sh_mi_thunks.py +++ b/tests/test_class_sh_mi_thunks.py @@ -4,7 +4,7 @@ from pybind11_tests import class_sh_mi_thunks as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_module_local.py b/tests/test_class_sh_module_local.py index 79ccb8b4..9f423005 100644 --- a/tests/test_class_sh_module_local.py +++ b/tests/test_class_sh_module_local.py @@ -5,7 +5,7 @@ import class_sh_module_local_2 as m2 import pytest -if not m0.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m0.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_property.cpp b/tests/test_class_sh_property.cpp index db744fae..cb8cd21a 100644 --- a/tests/test_class_sh_property.cpp +++ b/tests/test_class_sh_property.cpp @@ -58,8 +58,8 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_property::WithCharArrayMember) PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_property::WithConstCharPtrMember) TEST_SUBMODULE(class_sh_property, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -109,5 +109,5 @@ TEST_SUBMODULE(class_sh_property, m) { py::classh(m, "WithConstCharPtrMember") .def(py::init<>()) .def_readonly("const_char_ptr_member", &WithConstCharPtrMember::const_char_ptr_member); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_property.py b/tests/test_class_sh_property.py index dda786a2..b9d40213 100644 --- a/tests/test_class_sh_property.py +++ b/tests/test_class_sh_property.py @@ -7,7 +7,7 @@ import env # noqa: F401 from pybind11_tests import class_sh_property as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_property_non_owning.cpp b/tests/test_class_sh_property_non_owning.cpp index 65103148..e5f24bd7 100644 --- a/tests/test_class_sh_property_non_owning.cpp +++ b/tests/test_class_sh_property_non_owning.cpp @@ -51,8 +51,8 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(DataField) PYBIND11_SMART_HOLDER_TYPE_CASTERS(DataFieldsHolder) TEST_SUBMODULE(class_sh_property_non_owning, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -71,5 +71,5 @@ TEST_SUBMODULE(class_sh_property_non_owning, m) { py::classh(m, "DataFieldsHolder") .def(py::init()) .def("vec_at", &DataFieldsHolder::vec_at, py::return_value_policy::reference_internal); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_property_non_owning.py b/tests/test_class_sh_property_non_owning.py index 89c7c0cd..163681fa 100644 --- a/tests/test_class_sh_property_non_owning.py +++ b/tests/test_class_sh_property_non_owning.py @@ -4,7 +4,7 @@ from pybind11_tests import class_sh_property_non_owning as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_shared_ptr_copy_move.cpp b/tests/test_class_sh_shared_ptr_copy_move.cpp index 3e9eb9ac..fd79d3d1 100644 --- a/tests/test_class_sh_shared_ptr_copy_move.cpp +++ b/tests/test_class_sh_shared_ptr_copy_move.cpp @@ -50,8 +50,8 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::FooSmHld) namespace pybind11_tests { TEST_SUBMODULE(class_sh_shared_ptr_copy_move, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -113,7 +113,7 @@ TEST_SUBMODULE(class_sh_shared_ptr_copy_move, m) { l.append(std::move(o)); return l; }); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } } // namespace pybind11_tests diff --git a/tests/test_class_sh_shared_ptr_copy_move.py b/tests/test_class_sh_shared_ptr_copy_move.py index 092aa1f3..445a657f 100644 --- a/tests/test_class_sh_shared_ptr_copy_move.py +++ b/tests/test_class_sh_shared_ptr_copy_move.py @@ -4,7 +4,7 @@ from pybind11_tests import class_sh_shared_ptr_copy_move as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_trampoline_basic.cpp b/tests/test_class_sh_trampoline_basic.cpp index faadb402..bfff9520 100644 --- a/tests/test_class_sh_trampoline_basic.cpp +++ b/tests/test_class_sh_trampoline_basic.cpp @@ -34,7 +34,7 @@ struct AbaseAlias : Abase { } }; -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT template <> struct AbaseAlias<1> : Abase<1>, py::trampoline_self_life_support { using Abase<1>::Abase; @@ -46,7 +46,7 @@ struct AbaseAlias<1> : Abase<1>, py::trampoline_self_life_support { other_val); } }; -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT template int AddInCppRawPtr(const Abase *obj, int other_val) { @@ -65,7 +65,7 @@ int AddInCppUniquePtr(std::unique_ptr> obj, int other_val) { template void wrap(py::module_ m, const char *py_class_name) { -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT py::classh, AbaseAlias>(m, py_class_name) .def(py::init(), py::arg("val")) .def("Get", &Abase::Get) @@ -86,13 +86,13 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(Abase<0>) PYBIND11_SMART_HOLDER_TYPE_CASTERS(Abase<1>) TEST_SUBMODULE(class_sh_trampoline_basic, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; wrap<0>(m, "Abase0"); wrap<1>(m, "Abase1"); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_trampoline_basic.py b/tests/test_class_sh_trampoline_basic.py index 7b6e1a0f..ba3f94d6 100644 --- a/tests/test_class_sh_trampoline_basic.py +++ b/tests/test_class_sh_trampoline_basic.py @@ -4,7 +4,7 @@ from pybind11_tests import class_sh_trampoline_basic as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_trampoline_self_life_support.cpp b/tests/test_class_sh_trampoline_self_life_support.cpp index 859b9f8f..68e91aa3 100644 --- a/tests/test_class_sh_trampoline_self_life_support.cpp +++ b/tests/test_class_sh_trampoline_self_life_support.cpp @@ -38,7 +38,7 @@ struct Big5 { // Also known as "rule of five". Big5() : history{"DefaultConstructor"} {} }; -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT struct Big5Trampoline : Big5, py::trampoline_self_life_support { using Big5::Big5; }; @@ -52,8 +52,8 @@ using namespace pybind11_tests::class_sh_trampoline_self_life_support; PYBIND11_SMART_HOLDER_TYPE_CASTERS(Big5) TEST_SUBMODULE(class_sh_trampoline_self_life_support, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -94,5 +94,5 @@ TEST_SUBMODULE(class_sh_trampoline_self_life_support, m) { py::object o1 = py::cast(std::move(obj)); return py::make_tuple(o1, o2); }); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_trampoline_self_life_support.py b/tests/test_class_sh_trampoline_self_life_support.py index d366b48c..8aab5d9d 100644 --- a/tests/test_class_sh_trampoline_self_life_support.py +++ b/tests/test_class_sh_trampoline_self_life_support.py @@ -4,7 +4,7 @@ import pybind11_tests.class_sh_trampoline_self_life_support as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_trampoline_shared_from_this.cpp b/tests/test_class_sh_trampoline_shared_from_this.cpp index aaf5a875..e5d688af 100644 --- a/tests/test_class_sh_trampoline_shared_from_this.cpp +++ b/tests/test_class_sh_trampoline_shared_from_this.cpp @@ -71,7 +71,7 @@ struct SftSharedPtrStash { } }; -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT struct SftTrampoline : Sft, py::trampoline_self_life_support { using Sft::Sft; }; @@ -110,8 +110,8 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(Sft) PYBIND11_SMART_HOLDER_TYPE_CASTERS(SftSharedPtrStash) TEST_SUBMODULE(class_sh_trampoline_shared_from_this, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -140,5 +140,5 @@ TEST_SUBMODULE(class_sh_trampoline_shared_from_this, m) { m.def("make_pure_cpp_sft_unq_ptr", make_pure_cpp_sft_unq_ptr); m.def("make_pure_cpp_sft_shd_ptr", make_pure_cpp_sft_shd_ptr); m.def("pass_through_shd_ptr", pass_through_shd_ptr); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_trampoline_shared_from_this.py b/tests/test_class_sh_trampoline_shared_from_this.py index 75558421..a074b20a 100644 --- a/tests/test_class_sh_trampoline_shared_from_this.py +++ b/tests/test_class_sh_trampoline_shared_from_this.py @@ -8,7 +8,7 @@ import env import pybind11_tests.class_sh_trampoline_shared_from_this as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.cpp b/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.cpp index 2b94310b..d9605c8c 100644 --- a/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.cpp +++ b/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.cpp @@ -63,8 +63,8 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(SpGoAway) PYBIND11_SMART_HOLDER_TYPE_CASTERS(SpGoAwayTester) TEST_SUBMODULE(class_sh_trampoline_shared_ptr_cpp_arg, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -101,5 +101,5 @@ TEST_SUBMODULE(class_sh_trampoline_shared_ptr_cpp_arg, m) { py::classh(m, "SpGoAwayTester") .def(py::init<>()) .def_readwrite("obj", &SpGoAwayTester::m_obj); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.py b/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.py index 54575ddc..13daeee2 100644 --- a/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.py +++ b/tests/test_class_sh_trampoline_shared_ptr_cpp_arg.py @@ -4,7 +4,7 @@ import pybind11_tests.class_sh_trampoline_shared_ptr_cpp_arg as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_trampoline_unique_ptr.cpp b/tests/test_class_sh_trampoline_unique_ptr.cpp index 13dc27b0..d5406c9e 100644 --- a/tests/test_class_sh_trampoline_unique_ptr.cpp +++ b/tests/test_class_sh_trampoline_unique_ptr.cpp @@ -39,7 +39,7 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_trampoline_unique_pt namespace pybind11_tests { namespace class_sh_trampoline_unique_ptr { -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT class PyClass : public Class, public py::trampoline_self_life_support { public: std::unique_ptr clone() const override { @@ -54,8 +54,8 @@ class PyClass : public Class, public py::trampoline_self_life_support { } // namespace pybind11_tests TEST_SUBMODULE(class_sh_trampoline_unique_ptr, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -71,5 +71,5 @@ TEST_SUBMODULE(class_sh_trampoline_unique_ptr, m) { m.def("clone", [](const Class &obj) { return obj.clone(); }); m.def("clone_and_foo", [](const Class &obj) { return obj.clone()->foo(); }); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_trampoline_unique_ptr.py b/tests/test_class_sh_trampoline_unique_ptr.py index 22505dc6..893f3ae6 100644 --- a/tests/test_class_sh_trampoline_unique_ptr.py +++ b/tests/test_class_sh_trampoline_unique_ptr.py @@ -4,7 +4,7 @@ import pybind11_tests.class_sh_trampoline_unique_ptr as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_unique_ptr_custom_deleter.cpp b/tests/test_class_sh_unique_ptr_custom_deleter.cpp index 973bf490..e71d34dc 100644 --- a/tests/test_class_sh_unique_ptr_custom_deleter.cpp +++ b/tests/test_class_sh_unique_ptr_custom_deleter.cpp @@ -31,8 +31,8 @@ namespace pybind11_tests { namespace class_sh_unique_ptr_custom_deleter { TEST_SUBMODULE(class_sh_unique_ptr_custom_deleter, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -40,7 +40,7 @@ TEST_SUBMODULE(class_sh_unique_ptr_custom_deleter, m) { py::classh(m, "Pet").def_readwrite("name", &Pet::name); m.def("create", &Pet::New); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } } // namespace class_sh_unique_ptr_custom_deleter diff --git a/tests/test_class_sh_unique_ptr_custom_deleter.py b/tests/test_class_sh_unique_ptr_custom_deleter.py index f246e2d7..fbe7e599 100644 --- a/tests/test_class_sh_unique_ptr_custom_deleter.py +++ b/tests/test_class_sh_unique_ptr_custom_deleter.py @@ -4,7 +4,7 @@ from pybind11_tests import class_sh_unique_ptr_custom_deleter as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_unique_ptr_member.cpp b/tests/test_class_sh_unique_ptr_member.cpp index 1341f140..410c65ab 100644 --- a/tests/test_class_sh_unique_ptr_member.cpp +++ b/tests/test_class_sh_unique_ptr_member.cpp @@ -45,8 +45,8 @@ namespace pybind11_tests { namespace class_sh_unique_ptr_member { TEST_SUBMODULE(class_sh_unique_ptr_member, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -60,7 +60,7 @@ TEST_SUBMODULE(class_sh_unique_ptr_member, m) { .def("is_owner", &ptr_owner::is_owner) .def("give_up_ownership_via_unique_ptr", &ptr_owner::give_up_ownership_via_unique_ptr) .def("give_up_ownership_via_shared_ptr", &ptr_owner::give_up_ownership_via_shared_ptr); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } } // namespace class_sh_unique_ptr_member diff --git a/tests/test_class_sh_unique_ptr_member.py b/tests/test_class_sh_unique_ptr_member.py index dc1d5482..56ca8d06 100644 --- a/tests/test_class_sh_unique_ptr_member.py +++ b/tests/test_class_sh_unique_ptr_member.py @@ -4,7 +4,7 @@ from pybind11_tests import class_sh_unique_ptr_member as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_class_sh_virtual_py_cpp_mix.cpp b/tests/test_class_sh_virtual_py_cpp_mix.cpp index a68cb76a..7184322a 100644 --- a/tests/test_class_sh_virtual_py_cpp_mix.cpp +++ b/tests/test_class_sh_virtual_py_cpp_mix.cpp @@ -31,7 +31,7 @@ int get_from_cpp_plainc_ptr(const Base *b) { return b->get() + 4000; } int get_from_cpp_unique_ptr(std::unique_ptr b) { return b->get() + 5000; } -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT struct BaseVirtualOverrider : Base, py::trampoline_self_life_support { using Base::Base; @@ -57,8 +57,8 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(CppDerivedPlain) PYBIND11_SMART_HOLDER_TYPE_CASTERS(CppDerived) TEST_SUBMODULE(class_sh_virtual_py_cpp_mix, m) { - m.attr("defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = -#ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT + m.attr("defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT") = +#ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT false; #else true; @@ -71,5 +71,5 @@ TEST_SUBMODULE(class_sh_virtual_py_cpp_mix, m) { m.def("get_from_cpp_plainc_ptr", get_from_cpp_plainc_ptr, py::arg("b")); m.def("get_from_cpp_unique_ptr", get_from_cpp_unique_ptr, py::arg("b")); -#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#endif // PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT } diff --git a/tests/test_class_sh_virtual_py_cpp_mix.py b/tests/test_class_sh_virtual_py_cpp_mix.py index 3361713c..76bb09a4 100644 --- a/tests/test_class_sh_virtual_py_cpp_mix.py +++ b/tests/test_class_sh_virtual_py_cpp_mix.py @@ -4,7 +4,7 @@ from pybind11_tests import class_sh_virtual_py_cpp_mix as m -if not m.defined_PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT: +if not m.defined_PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT: pytest.skip("smart_holder not available.", allow_module_level=True) diff --git a/tests/test_classh_mock.cpp b/tests/test_classh_mock.cpp index 13532032..51be4ae0 100644 --- a/tests/test_classh_mock.cpp +++ b/tests/test_classh_mock.cpp @@ -11,7 +11,7 @@ #else # include PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) -# ifndef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +# ifndef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT template using classh = class_; # endif diff --git a/ubench/holder_comparison.cpp b/ubench/holder_comparison.cpp index f532bcfd..f9673b57 100644 --- a/ubench/holder_comparison.cpp +++ b/ubench/holder_comparison.cpp @@ -22,7 +22,7 @@ void wrap_number_bucket(py::module m, const char *class_name) { .def("add", &WrappedType::add, py::arg("other")); } -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT template class padded_unique_ptr { @@ -41,7 +41,7 @@ static_assert(sizeof(padded_unique_ptr) == sizeof(py::smart_holder), } // namespace hc -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT PYBIND11_DECLARE_HOLDER_TYPE(T, hc::padded_unique_ptr); #endif @@ -49,7 +49,7 @@ PYBIND11_MODULE(pybind11_ubench_holder_comparison, m) { using namespace hc; wrap_number_bucket>(m, "number_bucket_up"); wrap_number_bucket>(m, "number_bucket_sp"); -#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT +#ifdef PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT m.def("sizeof_smart_holder", []() { return sizeof(py::smart_holder); }); wrap_number_bucket>(m, "number_bucket_pu"); wrap_number_bucket(m, "number_bucket_sh"); From 845105383f4a80666330cbf1c9fefa373cbb7425 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 10:07:55 -0400 Subject: [PATCH 6/7] chore(deps): bump the actions group with 2 updates (#5287) Bumps the actions group with 2 updates: [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) and [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance). Updates `pypa/cibuildwheel` from 2.19 to 2.20 - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/v2.19...v2.20) Updates `actions/attest-build-provenance` from 1.3.3 to 1.4.0 - [Release notes](https://github.com/actions/attest-build-provenance/releases) - [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md) - [Commits](https://github.com/actions/attest-build-provenance/compare/5e9cb68e95676991667494a6a4e59b8a2f13e1d0...210c1913531870065f03ce1f9440dd87bc0938cd) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: actions/attest-build-provenance dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/emscripten.yaml | 2 +- .github/workflows/pip.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/emscripten.yaml b/.github/workflows/emscripten.yaml index 4f12e81c..cbd7f5d5 100644 --- a/.github/workflows/emscripten.yaml +++ b/.github/workflows/emscripten.yaml @@ -20,7 +20,7 @@ jobs: submodules: true fetch-depth: 0 - - uses: pypa/cibuildwheel@v2.19 + - uses: pypa/cibuildwheel@v2.20 env: PYODIDE_BUILD_EXPORTS: whole_archive CFLAGS: -fexceptions diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml index c1acb8bb..75074ff7 100644 --- a/.github/workflows/pip.yml +++ b/.github/workflows/pip.yml @@ -102,7 +102,7 @@ jobs: - uses: actions/download-artifact@v4 - name: Generate artifact attestation for sdist and wheel - uses: actions/attest-build-provenance@5e9cb68e95676991667494a6a4e59b8a2f13e1d0 # v1.3.3 + uses: actions/attest-build-provenance@210c1913531870065f03ce1f9440dd87bc0938cd # v1.4.0 with: subject-path: "*/pybind11*" From 20551ab3d8de4afd85738e3b31cd9378017da1c4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 20:19:10 -0700 Subject: [PATCH 7/7] chore(deps): update pre-commit hooks (#5288) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.5.0 β†’ v0.5.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.0...v0.5.6) - [github.com/pre-commit/mirrors-mypy: v1.10.1 β†’ v1.11.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.10.1...v1.11.1) - [github.com/PyCQA/pylint: v3.2.4 β†’ v3.2.6](https://github.com/PyCQA/pylint/compare/v3.2.4...v3.2.6) - [github.com/python-jsonschema/check-jsonschema: 0.28.6 β†’ 0.29.1](https://github.com/python-jsonschema/check-jsonschema/compare/0.28.6...0.29.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 92469eb3..ecac1cba 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -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.5.0 + 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.1" + rev: "v1.11.1" hooks: - id: mypy args: [] @@ -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.4" + 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.6 + rev: 0.29.1 hooks: - id: check-readthedocs - id: check-github-workflows