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

Skip to content

Commit 2c86932

Browse files
committed
upgrade_pythoncapi: add FORCE_STEALREF
1 parent 592bf24 commit 2c86932

2 files changed

Lines changed: 96 additions & 2 deletions

File tree

tests/test_upgrade_pythoncapi.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,59 @@ def test_py_incref_assign(self):
420420
}
421421
""")
422422

423+
@unittest.skipUnless(upgrade_pythoncapi.FORCE_STEALREF, 'FORCE_STEALREF=False')
424+
def test_py_decref_return(self):
425+
self.check_replace("""
426+
PyObject* steal_ref(PyObject *obj)
427+
{
428+
Py_DECREF(obj);
429+
return obj;
430+
}
431+
""", """
432+
#include "pythoncapi_compat.h"
433+
434+
PyObject* steal_ref(PyObject *obj)
435+
{
436+
return _Py_StealRef(obj);
437+
}
438+
""")
439+
440+
@unittest.skipUnless(upgrade_pythoncapi.FORCE_STEALREF, 'FORCE_STEALREF=False')
441+
def test_py_decref_assign(self):
442+
self.check_replace("""
443+
void set_attr(MyStruct *obj, PyObject *value)
444+
{
445+
Py_DECREF(value);
446+
obj->attr1 = value;
447+
448+
obj->attr2 = value;
449+
Py_DECREF(value);
450+
}
451+
""", """
452+
#include "pythoncapi_compat.h"
453+
454+
void set_attr(MyStruct *obj, PyObject *value)
455+
{
456+
obj->attr1 = _Py_StealRef(value);
457+
458+
obj->attr2 = _Py_StealRef(value);
459+
}
460+
""")
461+
462+
# The regex matchs "value" in "obj->value" of case 2
463+
self.check_dont_replace("""
464+
void set_attr(MyStruct *obj, PyObject *value)
465+
{
466+
// Case 1
467+
Py_DECREF(value);
468+
obj->value = NULL;
469+
470+
// Case 2
471+
obj->value = NULL;
472+
Py_DECREF(value);
473+
}
474+
""")
475+
423476

424477
if __name__ == "__main__":
425478
unittest.main()

upgrade_pythoncapi.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
FORCE_NEWREF = False
9+
FORCE_STEALREF = False
910

1011

1112
PYTHONCAPI_COMPAT_URL = ('https://raw.githubusercontent.com/pythoncapi/'
@@ -265,7 +266,42 @@ class Py_INCREF_assign(Operation):
265266
NEED_PYTHONCAPI_COMPAT = True
266267

267268

268-
OPERATIONS = (
269+
class Py_DECREF_return(Operation):
270+
NAME = "Py_DECREF_return"
271+
DOC = ('replace "Py_DECREF(obj); return (obj);" '
272+
'with "return Py_NewRef(obj);"')
273+
REPLACE = (
274+
(re.compile(r'Py_DECREF\((%s)\);\s*return \1;' % ID_REGEX),
275+
r'return _Py_StealRef(\1);'),
276+
)
277+
# Need _Py_StealRef(): new in Python 3.10
278+
NEED_PYTHONCAPI_COMPAT = True
279+
280+
281+
class Py_DECREF_assign(Operation):
282+
NAME = "Py_DECREF_assign"
283+
DOC = 'replace "Py_DECREF(obj); var = (obj);" with "var = Py_BorrowRed(obj);"'
284+
285+
def replace2(regs):
286+
x = regs.group(1)
287+
y = regs.group(2)
288+
if y == 'NULL':
289+
return regs.group(0)
290+
return f'{x} = _Py_StealRef({y});'
291+
292+
REPLACE = (
293+
(re.compile(r'Py_DECREF\((%s)\);\s*' % ID_REGEX
294+
+ assign_regex_str(r'(%s)' % EXPR_REGEX, r'\1')),
295+
r'\2 = _Py_StealRef(\1);'),
296+
(re.compile(assign_regex_str(r'(%s)' % EXPR_REGEX, r'(%s)' % ID_REGEX)
297+
+ r"\s*Py_DECREF\((?:\1|\2)\);"),
298+
replace2),
299+
)
300+
# Need Py_Borrowef(): new in Python 3.10
301+
NEED_PYTHONCAPI_COMPAT = True
302+
303+
304+
OPERATIONS = [
269305
Py_SET_TYPE,
270306
Py_SET_SIZE,
271307
Py_SET_REFCNT,
@@ -283,12 +319,17 @@ class Py_INCREF_assign(Operation):
283319

284320
PyThreadState_GetInterpreter,
285321
PyThreadState_GetFrame,
286-
)
322+
]
287323
if FORCE_NEWREF:
288324
OPERATIONS.extend((
289325
Py_INCREF_return,
290326
Py_INCREF_assign,
291327
))
328+
if FORCE_STEALREF:
329+
OPERATIONS.extend((
330+
Py_DECREF_return,
331+
Py_DECREF_assign,
332+
))
292333

293334

294335
class Patcher:

0 commit comments

Comments
 (0)