-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Expand file tree
/
Copy pathtest_class_sh_trampoline_shared_ptr_cpp_arg.py
More file actions
154 lines (112 loc) · 4.12 KB
/
Copy pathtest_class_sh_trampoline_shared_ptr_cpp_arg.py
File metadata and controls
154 lines (112 loc) · 4.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
from __future__ import annotations
import pytest
import env # noqa: F401
import pybind11_tests.class_sh_trampoline_shared_ptr_cpp_arg as m
@pytest.mark.skipif("env.GRAALPY", reason="Cannot reliably trigger GC")
def test_shared_ptr_cpp_arg():
import weakref
class PyChild(m.SpBase):
def is_base_used(self):
return False
tester = m.SpBaseTester()
obj = PyChild()
objref = weakref.ref(obj)
# Pass the last python reference to the C++ function
tester.set_object(obj)
del obj
pytest.gc_collect()
# python reference is still around since C++ has it now
assert objref() is not None
assert tester.is_base_used() is False
assert tester.obj.is_base_used() is False
assert tester.get_object() is objref()
@pytest.mark.skipif("env.GRAALPY", reason="Cannot reliably trigger GC")
def test_shared_ptr_cpp_prop():
class PyChild(m.SpBase):
def is_base_used(self):
return False
tester = m.SpBaseTester()
# Set the last python reference as a property of the C++ object
tester.obj = PyChild()
pytest.gc_collect()
# python reference is still around since C++ has it now
assert tester.is_base_used() is False
assert tester.has_python_instance() is True
assert tester.obj.is_base_used() is False
assert tester.obj.has_python_instance() is True
@pytest.mark.skipif("env.GRAALPY", reason="Cannot reliably trigger GC")
def test_shared_ptr_arg_identity():
import weakref
tester = m.SpBaseTester()
obj = m.SpBase()
objref = weakref.ref(obj)
tester.set_object(obj)
del obj
pytest.gc_collect()
# NOTE: the behavior below is DIFFERENT from PR #2839
# python reference is gone because it is not an Alias instance
assert objref() is None
assert tester.has_python_instance() is False
@pytest.mark.skipif("env.GRAALPY", reason="Cannot reliably trigger GC")
def test_shared_ptr_alias_nonpython():
tester = m.SpBaseTester()
# C++ creates the object, a python instance shouldn't exist
tester.set_nonpython_instance()
assert tester.is_base_used() is True
assert tester.has_instance() is True
assert tester.has_python_instance() is False
# Now a python instance exists
cobj = tester.get_object()
assert cobj.has_python_instance()
assert tester.has_instance() is True
assert tester.has_python_instance() is True
# Now it's gone
del cobj
pytest.gc_collect()
assert tester.has_instance() is True
assert tester.has_python_instance() is False
# When we pass it as an arg to a new tester the python instance should
# disappear because it wasn't created with an alias
new_tester = m.SpBaseTester()
cobj = tester.get_object()
assert cobj.has_python_instance()
new_tester.set_object(cobj)
assert tester.has_python_instance() is True
assert new_tester.has_python_instance() is True
del cobj
pytest.gc_collect()
# Gone!
assert tester.has_instance() is True
assert tester.has_python_instance() is False
assert new_tester.has_instance() is True
assert new_tester.has_python_instance() is False
@pytest.mark.skipif("env.GRAALPY", reason="Cannot reliably trigger GC")
def test_shared_ptr_goaway():
import weakref
tester = m.SpGoAwayTester()
obj = m.SpGoAway()
objref = weakref.ref(obj)
assert tester.obj is None
tester.obj = obj
del obj
pytest.gc_collect()
# python reference is no longer around
assert objref() is None
# C++ reference is still around
assert tester.obj is not None
def test_infinite():
tester = m.SpBaseTester()
while True:
tester.set_object(m.SpBase())
break # Comment out for manual leak checking (use `top` command).
@pytest.mark.parametrize(
"pass_through_func", [m.pass_through_shd_ptr, m.pass_through_shd_ptr_release_gil]
)
def test_std_make_shared_factory(pass_through_func):
class PyChild(m.SpBase):
def __init__(self):
super().__init__(0)
obj = PyChild()
while True:
assert pass_through_func(obj) is obj
break # Comment out for manual leak checking (use `top` command).