Skip to content

Add py::potentially_slicing_weak_ptr(handle) function #5624

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
May 13, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
50c3c1e
Added weak_ptr test (currently failing)
nsoblath Apr 16, 2025
528d1cc
Merge branch 'master' into weak_ptr_test_only
nsoblath Apr 17, 2025
b160f6c
Cleanup
nsoblath Apr 17, 2025
2fe82b2
[skip ci] Simplify test case.
rwgk Apr 19, 2025
ff70657
Add test_class_sp_trampoline_weak_ptr.cpp,py (using std::shared_ptr a…
rwgk Apr 19, 2025
a481647
Resolve clang-tidy errors
rwgk Apr 19, 2025
32858da
PYPY, GRAALPY: skip last part of test_weak_ptr_base
rwgk Apr 19, 2025
e978d93
Rename test_weak_ptr_base → test_weak_ptr_owner
rwgk Apr 19, 2025
1c0b700
Add SpOwner, test_with_sp_owner, test_with_sp_and_wp_owners
rwgk Apr 20, 2025
4638e01
Modify py::trampoline_self_life_support semantics: if trampoline clas…
rwgk Apr 20, 2025
6cc6368
Remove debug printf in include/pybind11/pybind11.h
rwgk Apr 20, 2025
62d3265
Resolve MSVC error
rwgk Apr 20, 2025
2f672eb
[skip ci] Undo the production code change under 4638e017b6e7bbd246c03…
rwgk Apr 26, 2025
888a295
[skip ci] Introduce lambda in `WpOwner::set_wp` bindings, but simply …
rwgk Apr 26, 2025
b20f557
Add `py::potentially_slicing_shared_ptr()`
rwgk Apr 26, 2025
3b4b28c
Add `type_id<T>()` to `py::potentially_slicing_shared_ptr()` error me…
rwgk Apr 27, 2025
56d23dc
test_potentially_slicing_shared_ptr.cpp,py (for smart_holder only)
rwgk Apr 27, 2025
ff0792e
Generalize test_potentially_slicing_shared_ptr.cpp,py for testing wit…
rwgk Apr 27, 2025
eb1787c
Add back test_potentially_slicing_shared_ptr_not_convertible_error(),…
rwgk Apr 27, 2025
10f6e78
Add simple trampoline state assertions.
rwgk Apr 28, 2025
121c8cf
Resolve clang-tidy errors.
rwgk Apr 28, 2025
b42bd11
Add a (long) C++ comment for py::potentially_slicing_shared_ptr<>()
rwgk Apr 28, 2025
f160450
[skip ci] Add new "Avoiding Inheritance Slicing and ``std::weak_ptr``…
rwgk Apr 28, 2025
78178d7
[skip ci] Add introductory comment to test_potentially_slicing_shared…
rwgk Apr 28, 2025
62d2242
[skip ci] Merge branch 'master' into weak_ptr_test_only
rwgk Apr 28, 2025
0ecb396
Merge branch 'master' into weak_ptr_test_only
rwgk Apr 30, 2025
faf1e61
Merge branch 'master' into weak_ptr_test_only
rwgk May 1, 2025
222b4a7
Minimal (!) changes to have py::potentially_slicing_weak_ptr<T>(handl…
rwgk May 1, 2025
7c4a8bc
Merge branch 'master' into weak_ptr_test_only
rwgk May 8, 2025
03a8981
Rename test_potentially_slicing_shared_ptr.cpp,py → test_potentially_…
rwgk May 8, 2025
bad0c12
Update docs/advanced/classes.rst and C++ comments → potentially_slici…
rwgk May 8, 2025
683fff4
Write "shared_ptr" instead of just "pointer" in a couple places in do…
rwgk May 8, 2025
9f379ea
Merge branch 'master' into weak_ptr_test_only
rwgk May 9, 2025
b349e84
Add comment for force_potentially_slicing_shared_ptr in type_caster_b…
rwgk May 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ set(PYBIND11_TEST_FILES
test_class_sh_trampoline_shared_from_this
test_class_sh_trampoline_shared_ptr_cpp_arg
test_class_sh_trampoline_unique_ptr
test_class_sh_trampoline_weak_ptr
test_class_sh_unique_ptr_custom_deleter
test_class_sh_unique_ptr_member
test_class_sh_virtual_py_cpp_mix
Expand Down
61 changes: 61 additions & 0 deletions tests/test_class_sh_trampoline_weak_ptr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// 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.

#include "pybind11_tests.h"

#include <utility>

namespace pybind11_tests {
namespace class_sh_trampoline_weak_ptr {

// // For testing whether a python subclass of a C++ object can be accessed from a C++ weak_ptr
struct WpBase {
// returns true if the base virtual function is called
virtual bool is_base_used() { return true; }

// returns true if there's an associated python instance
bool has_python_instance() {
auto *tinfo = py::detail::get_type_info(typeid(WpBase));
return (bool) py::detail::get_object_handle(this, tinfo);
}

WpBase() = default;
WpBase(const WpBase &) = delete;
virtual ~WpBase() = default;
};

struct PyWpBase : WpBase {
Copy link
Collaborator

@rwgk rwgk Apr 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

struct PyWpBase : WpBase, py::trampoline_self_life_support {

Does that help?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I just fixed an oversight in my previous comment.)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
struct PyWpBase : WpBase {
struct PyWpBase : WpBase, py::trampoline_self_life_support {

using WpBase::WpBase;
bool is_base_used() override { PYBIND11_OVERRIDE(bool, WpBase, is_base_used); }
};

struct WpBaseTester {
std::shared_ptr<WpBase> get_object() const { return m_obj.lock(); }
void set_object(std::shared_ptr<WpBase> obj) { m_obj = obj; }
bool is_expired() { return m_obj.expired(); }
bool is_base_used() { return m_obj.lock()->is_base_used(); }
std::weak_ptr<WpBase> m_obj;
};

} // namespace class_sh_trampoline_weak_ptr
} // namespace pybind11_tests

using namespace pybind11_tests::class_sh_trampoline_weak_ptr;

TEST_SUBMODULE(class_sh_trampoline_weak_ptr, m) {
// For testing whether a python subclass of a C++ object can be accessed from a C++ weak_ptr

py::classh<WpBase, PyWpBase>(m, "WpBase")
.def(py::init<>())
.def(py::init([](int) { return std::make_shared<PyWpBase>(); }))
.def("is_base_used", &WpBase::is_base_used)
.def("has_python_instance", &WpBase::has_python_instance);

py::classh<WpBaseTester>(m, "WpBaseTester")
.def(py::init<>())
.def("get_object", &WpBaseTester::get_object)
.def("set_object", &WpBaseTester::set_object)
.def("is_expired", &WpBaseTester::is_expired)
.def("is_base_used", &WpBaseTester::is_base_used);
}
36 changes: 36 additions & 0 deletions tests/test_class_sh_trampoline_weak_ptr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from __future__ import annotations

import pytest

import env # noqa: F401
import pybind11_tests.class_sh_trampoline_weak_ptr as m


@pytest.mark.skipif("env.GRAALPY", reason="Cannot reliably trigger GC")
def test_weak_ptr_base():
tester = m.WpBaseTester()

obj = m.WpBase()

tester.set_object(obj)

assert tester.is_expired() is False
assert tester.is_base_used() is True
assert tester.get_object().is_base_used() is True


@pytest.mark.skipif("env.GRAALPY", reason="Cannot reliably trigger GC")
def test_weak_ptr_child():
class PyChild(m.WpBase):
def is_base_used(self):
return False

tester = m.WpBaseTester()

obj = PyChild()

tester.set_object(obj)

assert tester.is_expired() is False

Check failure on line 34 in tests/test_class_sh_trampoline_weak_ptr.py

View workflow job for this annotation

GitHub Actions / 🐍 pypy-3.11 • ubuntu-22.04 • x64

test_weak_ptr_child assert True is False + where True = is_expired() + where is_expired = <pybind11_tests.class_sh_trampoline_weak_ptr.WpBaseTester object at 0x00000000385e20e0>.is_expired

Check failure on line 34 in tests/test_class_sh_trampoline_weak_ptr.py

View workflow job for this annotation

GitHub Actions / 🐍 pypy-3.10 • ubuntu-22.04 • x64

test_weak_ptr_child assert True is False + where True = is_expired() + where is_expired = <pybind11_tests.class_sh_trampoline_weak_ptr.WpBaseTester object at 0x00000000352e9f80>.is_expired

Check failure on line 34 in tests/test_class_sh_trampoline_weak_ptr.py

View workflow job for this annotation

GitHub Actions / 🐍 3.13 • ubuntu-22.04 • x64

test_weak_ptr_child assert True is False + where True = is_expired() + where is_expired = <pybind11_tests.class_sh_trampoline_weak_ptr.WpBaseTester object at 0x7f2a1e7e8e30>.is_expired

Check failure on line 34 in tests/test_class_sh_trampoline_weak_ptr.py

View workflow job for this annotation

GitHub Actions / 🐍 3.8 • ubuntu-22.04 • x64 -DPYBIND11_FINDPYTHON=OFF -DCMAKE_CXX_FLAGS="-D_=1" -DPYBIND11_NUMPY_1_ONLY=ON

test_weak_ptr_child assert True is False + where True = is_expired() + where is_expired = <pybind11_tests.class_sh_trampoline_weak_ptr.WpBaseTester object at 0x7f5a93d659b0>.is_expired

Check failure on line 34 in tests/test_class_sh_trampoline_weak_ptr.py

View workflow job for this annotation

GitHub Actions / 🐍 3.12 • ubuntu-latest • x64 -DCMAKE_CXX_FLAGS="-DPYBIND11_RUN_TESTING_WITH_SMART_HOLDER_AS_DEFAULT_BUT_NEVER_USE_IN_PRODUCTION_PLEASE"

test_weak_ptr_child assert True is False + where True = is_expired() + where is_expired = <pybind11_tests.class_sh_trampoline_weak_ptr.WpBaseTester object at 0x7ff9ce37eb30>.is_expired
assert tester.is_base_used() is False
assert tester.get_object().is_base_used() is False
Loading