Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 12724dd

Browse files
committed
Add Borrow variant functions
1 parent 1b7e660 commit 12724dd

3 files changed

Lines changed: 70 additions & 30 deletions

File tree

README.rst

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,35 @@ Copy the header file in your project and include it using::
3535
Functions
3636
=========
3737

38+
Borrow variant
39+
--------------
40+
41+
To ease migration of C extensions to the new C API, a variant is provided
42+
to return borrowed references rather than strong references::
43+
44+
// PyThreadState_GetFrame()
45+
PyFrameObject* _PyThreadState_GetFrameBorrow(PyThreadState *tstate)
46+
47+
// PyFrame_GetCode()
48+
PyCodeObject* _PyFrame_GetCodeBorrow(PyFrameObject *frame)
49+
50+
// PyFrame_GetBack()
51+
PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame)
52+
53+
For example, ``tstate->frame`` can be replaced with
54+
``_PyThreadState_GetFrameBorrow(tstate)`` to avoid accessing directly
55+
``PyThreadState.frame`` member.
56+
57+
These functions are only available in ``pythoncapi_compat.h`` and are not
58+
part of the Python C API.
59+
3860
Python 3.10
3961
-----------
4062

4163
::
4264

4365
PyObject* Py_NewRef(PyObject *obj);
4466
PyObject* Py_XNewRef(PyObject *obj);
45-
PyObject* _Py_Borrow(PyObject *obj);
46-
PyObject* _Py_XBorrow(PyObject *obj);
4767

4868
Python 3.9
4969
----------

pythoncapi_compat.h

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,6 @@ static inline PyObject* Py_XNewRef(PyObject *obj)
4141
#endif
4242

4343

44-
// bpo-42522
45-
static inline PyObject* __Py_Borrow(PyObject *obj)
46-
{
47-
Py_DECREF(obj);
48-
return obj;
49-
}
50-
#define _Py_Borrow(obj) __Py_Borrow(_PyObject_CAST(obj))
51-
52-
static inline PyObject* __Py_XBorrow(PyObject *obj)
53-
{
54-
Py_XDECREF(obj);
55-
return obj;
56-
}
57-
#define _Py_XBorrow(obj) __Py_XBorrow(_PyObject_CAST(obj))
58-
59-
6044
// bpo-39573: Py_TYPE(), Py_REFCNT() and Py_SIZE() can no longer be used
6145
// as l-value in Python 3.10.
6246
#if PY_VERSION_HEX < 0x030900A4
@@ -96,6 +80,14 @@ PyFrame_GetCode(PyFrameObject *frame)
9680
}
9781
#endif
9882

83+
static inline PyCodeObject*
84+
_PyFrame_GetCodeBorrow(PyFrameObject *frame)
85+
{
86+
PyCodeObject *code = PyFrame_GetCode(frame);
87+
Py_DECREF(code);
88+
return code; // borrowed reference
89+
}
90+
9991

10092
#if PY_VERSION_HEX < 0x030900B1
10193
static inline PyFrameObject*
@@ -108,6 +100,14 @@ PyFrame_GetBack(PyFrameObject *frame)
108100
}
109101
#endif
110102

103+
static inline PyFrameObject*
104+
_PyFrame_GetBackBorrow(PyFrameObject *frame)
105+
{
106+
PyFrameObject *back = PyFrame_GetBack(frame);
107+
Py_XDECREF(back);
108+
return back; // borrowed reference
109+
}
110+
111111

112112
#if PY_VERSION_HEX < 0x030900A5
113113
static inline PyInterpreterState *
@@ -130,6 +130,14 @@ PyThreadState_GetFrame(PyThreadState *tstate)
130130
}
131131
#endif
132132

133+
static inline PyFrameObject*
134+
_PyThreadState_GetFrameBorrow(PyThreadState *tstate)
135+
{
136+
PyFrameObject *frame = PyThreadState_GetFrame(tstate);
137+
Py_XDECREF(frame);
138+
return frame; // borrowed reference
139+
}
140+
133141

134142
#if PY_VERSION_HEX < 0x030900A5
135143
static inline PyInterpreterState *

tests/test_pythoncapi_compat.c

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,6 @@ test_object(PyObject *self, PyObject *ignored)
3939
int is_type = Py_IS_TYPE(obj, Py_TYPE(obj));
4040
assert(is_type);
4141

42-
// test _Py_Borrow()
43-
Py_INCREF(obj);
44-
PyObject *borrowed = _Py_Borrow(obj);
45-
assert(borrowed == obj);
46-
assert(Py_REFCNT(obj) == refcnt);
47-
48-
// test _Py_XBorrow()
49-
Py_INCREF(obj);
50-
PyObject *xborrowed = _Py_XBorrow(obj);
51-
assert(xborrowed == obj);
52-
assert(Py_REFCNT(obj) == refcnt);
53-
5442
Py_DECREF(obj);
5543
Py_RETURN_NONE;
5644
}
@@ -67,17 +55,41 @@ test_frame(PyObject *self, PyObject *ignored)
6755
return ASSERT_FAILED("PyThreadState_GetFrame failed");
6856
}
6957

58+
// test _PyThreadState_GetFrameBorrow()
59+
Py_ssize_t frame_refcnt = Py_REFCNT(frame);
60+
PyFrameObject *frame2 = _PyThreadState_GetFrameBorrow(tstate);
61+
assert(frame2 == frame);
62+
assert(Py_REFCNT(frame) == frame_refcnt);
63+
7064
// test PyFrame_GetCode()
7165
PyCodeObject *code = PyFrame_GetCode(frame);
7266
assert(code != NULL);
7367
assert(PyCode_Check(code));
68+
69+
// test _PyFrame_GetCodeBorrow()
70+
Py_ssize_t code_refcnt = Py_REFCNT(code);
71+
PyCodeObject *code2 = _PyFrame_GetCodeBorrow(frame);
72+
assert(code2 == code);
73+
assert(Py_REFCNT(code) == code_refcnt);
7474
Py_DECREF(code);
7575

7676
// PyFrame_GetBack()
7777
PyFrameObject* back = PyFrame_GetBack(frame);
7878
if (back != NULL) {
7979
assert(PyFrame_Check(back));
8080
}
81+
82+
// test _PyFrame_GetBackBorrow()
83+
if (back != NULL) {
84+
Py_ssize_t back_refcnt = Py_REFCNT(back);
85+
PyCodeObject *back2 = _PyFrame_GetBackBorrow(frame);
86+
assert(back2 == back);
87+
assert(Py_REFCNT(back) == back_refcnt);
88+
}
89+
else {
90+
PyCodeObject *back2 = _PyFrame_GetBackBorrow(frame);
91+
assert(back2 == back);
92+
}
8193
Py_XDECREF(back);
8294

8395
Py_DECREF(frame);

0 commit comments

Comments
 (0)