test_call_policies.py 5.39 KB
Newer Older
1
# -*- coding: utf-8 -*-
Wenzel Jakob's avatar
Wenzel Jakob committed
2
import pytest
3
4
5

import env  # noqa: F401

6
7
from pybind11_tests import call_policies as m
from pybind11_tests import ConstructorStats
Dean Moldovan's avatar
Dean Moldovan committed
8
9


10
@pytest.mark.xfail("env.PYPY", reason="sometimes comes out 1 off on PyPy", strict=False)
Dean Moldovan's avatar
Dean Moldovan committed
11
def test_keep_alive_argument(capture):
12
    n_inst = ConstructorStats.detail_reg_inst()
Dean Moldovan's avatar
Dean Moldovan committed
13
    with capture:
14
        p = m.Parent()
Dean Moldovan's avatar
Dean Moldovan committed
15
16
    assert capture == "Allocating parent."
    with capture:
17
        p.addChild(m.Child())
18
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
Dean Moldovan's avatar
Dean Moldovan committed
19
20
21
22
23
24
    assert capture == """
        Allocating child.
        Releasing child.
    """
    with capture:
        del p
25
        assert ConstructorStats.detail_reg_inst() == n_inst
Dean Moldovan's avatar
Dean Moldovan committed
26
27
28
    assert capture == "Releasing parent."

    with capture:
29
        p = m.Parent()
Dean Moldovan's avatar
Dean Moldovan committed
30
31
    assert capture == "Allocating parent."
    with capture:
32
        p.addChildKeepAlive(m.Child())
33
        assert ConstructorStats.detail_reg_inst() == n_inst + 2
Dean Moldovan's avatar
Dean Moldovan committed
34
35
36
    assert capture == "Allocating child."
    with capture:
        del p
37
        assert ConstructorStats.detail_reg_inst() == n_inst
Dean Moldovan's avatar
Dean Moldovan committed
38
39
40
41
42
43
44
    assert capture == """
        Releasing parent.
        Releasing child.
    """


def test_keep_alive_return_value(capture):
45
    n_inst = ConstructorStats.detail_reg_inst()
Dean Moldovan's avatar
Dean Moldovan committed
46
    with capture:
47
        p = m.Parent()
Dean Moldovan's avatar
Dean Moldovan committed
48
49
50
    assert capture == "Allocating parent."
    with capture:
        p.returnChild()
51
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
Dean Moldovan's avatar
Dean Moldovan committed
52
53
54
55
56
57
    assert capture == """
        Allocating child.
        Releasing child.
    """
    with capture:
        del p
58
        assert ConstructorStats.detail_reg_inst() == n_inst
Dean Moldovan's avatar
Dean Moldovan committed
59
60
61
    assert capture == "Releasing parent."

    with capture:
62
        p = m.Parent()
Dean Moldovan's avatar
Dean Moldovan committed
63
64
65
    assert capture == "Allocating parent."
    with capture:
        p.returnChildKeepAlive()
66
        assert ConstructorStats.detail_reg_inst() == n_inst + 2
Dean Moldovan's avatar
Dean Moldovan committed
67
68
69
    assert capture == "Allocating child."
    with capture:
        del p
70
71
72
73
74
75
76
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
        Releasing parent.
        Releasing child.
    """


77
78
# https://foss.heptapod.net/pypy/pypy/-/issues/2447
@pytest.mark.xfail("env.PYPY", reason="_PyObject_GetDictPtr is unimplemented")
79
80
def test_alive_gc(capture):
    n_inst = ConstructorStats.detail_reg_inst()
81
82
    p = m.ParentGC()
    p.addChildKeepAlive(m.Child())
83
84
85
86
87
88
89
90
91
92
93
94
95
    assert ConstructorStats.detail_reg_inst() == n_inst + 2
    lst = [p]
    lst.append(lst)   # creates a circular reference
    with capture:
        del p, lst
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
        Releasing parent.
        Releasing child.
    """


def test_alive_gc_derived(capture):
96
    class Derived(m.Parent):
97
98
99
100
        pass

    n_inst = ConstructorStats.detail_reg_inst()
    p = Derived()
101
    p.addChildKeepAlive(m.Child())
102
103
104
105
106
107
108
109
110
111
112
113
114
    assert ConstructorStats.detail_reg_inst() == n_inst + 2
    lst = [p]
    lst.append(lst)   # creates a circular reference
    with capture:
        del p, lst
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
        Releasing parent.
        Releasing child.
    """


def test_alive_gc_multi_derived(capture):
115
    class Derived(m.Parent, m.Child):
116
        def __init__(self):
117
118
            m.Parent.__init__(self)
            m.Child.__init__(self)
119
120
121

    n_inst = ConstructorStats.detail_reg_inst()
    p = Derived()
122
    p.addChildKeepAlive(m.Child())
123
124
125
126
127
128
129
    # +3 rather than +2 because Derived corresponds to two registered instances
    assert ConstructorStats.detail_reg_inst() == n_inst + 3
    lst = [p]
    lst.append(lst)   # creates a circular reference
    with capture:
        del p, lst
        assert ConstructorStats.detail_reg_inst() == n_inst
Dean Moldovan's avatar
Dean Moldovan committed
130
131
132
    assert capture == """
        Releasing parent.
        Releasing child.
133
        Releasing child.
Dean Moldovan's avatar
Dean Moldovan committed
134
135
136
137
    """


def test_return_none(capture):
138
    n_inst = ConstructorStats.detail_reg_inst()
Dean Moldovan's avatar
Dean Moldovan committed
139
    with capture:
140
        p = m.Parent()
Dean Moldovan's avatar
Dean Moldovan committed
141
142
143
    assert capture == "Allocating parent."
    with capture:
        p.returnNullChildKeepAliveChild()
144
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
Dean Moldovan's avatar
Dean Moldovan committed
145
146
147
    assert capture == ""
    with capture:
        del p
148
        assert ConstructorStats.detail_reg_inst() == n_inst
Dean Moldovan's avatar
Dean Moldovan committed
149
150
151
    assert capture == "Releasing parent."

    with capture:
152
        p = m.Parent()
Dean Moldovan's avatar
Dean Moldovan committed
153
154
155
    assert capture == "Allocating parent."
    with capture:
        p.returnNullChildKeepAliveParent()
156
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
Dean Moldovan's avatar
Dean Moldovan committed
157
158
159
    assert capture == ""
    with capture:
        del p
160
        assert ConstructorStats.detail_reg_inst() == n_inst
Dean Moldovan's avatar
Dean Moldovan committed
161
    assert capture == "Releasing parent."
Dean Moldovan's avatar
Dean Moldovan committed
162
163


164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
def test_keep_alive_constructor(capture):
    n_inst = ConstructorStats.detail_reg_inst()

    with capture:
        p = m.Parent(m.Child())
        assert ConstructorStats.detail_reg_inst() == n_inst + 2
    assert capture == """
        Allocating child.
        Allocating parent.
    """
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
        Releasing parent.
        Releasing child.
    """


Dean Moldovan's avatar
Dean Moldovan committed
183
def test_call_guard():
184
185
    assert m.unguarded_call() == "unguarded"
    assert m.guarded_call() == "guarded"
Dean Moldovan's avatar
Dean Moldovan committed
186

187
188
    assert m.multiple_guards_correct_order() == "guarded & guarded"
    assert m.multiple_guards_wrong_order() == "unguarded & guarded"
Dean Moldovan's avatar
Dean Moldovan committed
189

190
191
192
    if hasattr(m, "with_gil"):
        assert m.with_gil() == "GIL held"
        assert m.without_gil() == "GIL released"