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

Skip to content

Commit ba0752f

Browse files
authored
Enhance NewRef operations (#52)
1 parent 5d39703 commit ba0752f

2 files changed

Lines changed: 95 additions & 18 deletions

File tree

tests/test_upgrade_pythoncapi.py

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,10 @@ def test_py_incref_return(self):
399399
return obj;
400400
}
401401
402+
PyObject* same_line(PyObject *obj) {
403+
Py_INCREF(obj); return obj;
404+
}
405+
402406
PyObject* new_xref(PyObject *obj) {
403407
Py_XINCREF(obj);
404408
return obj;
@@ -410,6 +414,10 @@ def test_py_incref_return(self):
410414
return Py_NewRef(obj);
411415
}
412416
417+
PyObject* same_line(PyObject *obj) {
418+
return Py_NewRef(obj);
419+
}
420+
413421
PyObject* new_xref(PyObject *obj) {
414422
return Py_XNewRef(obj);
415423
}
@@ -418,7 +426,7 @@ def test_py_incref_return(self):
418426
@unittest.skipUnless(upgrade_pythoncapi.FORCE_NEWREF, 'FORCE_NEWREF=False')
419427
def test_py_incref_assign(self):
420428
self.check_replace("""
421-
void set_attr(MyStruct *obj, PyObject *value)
429+
void set_attr(MyStruct *obj, PyObject *value, int test)
422430
{
423431
// 1
424432
Py_INCREF(value);
@@ -429,21 +437,43 @@ def test_py_incref_assign(self):
429437
// 3
430438
obj->attr = value;
431439
Py_INCREF(obj->attr);
432-
// 4
433-
obj->attr = value; Py_INCREF(obj->attr);
440+
441+
// same line 1
442+
obj->attr = value; Py_INCREF(value);
443+
// same line 2
444+
if (test) { obj->attr = value; Py_INCREF(obj->attr); }
445+
// same line 3
446+
if (test) { Py_INCREF(value); obj->attr = value; }
447+
448+
// cast 1
449+
Py_INCREF(value);
450+
obj->attr = (PyObject*)value;
451+
// cast 2
452+
obj->attr = (PyObject*)value;
453+
Py_INCREF(value);
434454
}
435455
""", """
436456
#include "pythoncapi_compat.h"
437457
438-
void set_attr(MyStruct *obj, PyObject *value)
458+
void set_attr(MyStruct *obj, PyObject *value, int test)
439459
{
440460
// 1
441461
obj->attr = Py_NewRef(value);
442462
// 2
443463
obj->attr = Py_NewRef(value);
444464
// 3
445465
obj->attr = Py_NewRef(value);
446-
// 4
466+
467+
// same line 1
468+
obj->attr = Py_NewRef(value);
469+
// same line 2
470+
if (test) { obj->attr = Py_NewRef(value); }
471+
// same line 3
472+
if (test) { obj->attr = Py_NewRef(value); }
473+
474+
// cast 1
475+
obj->attr = Py_NewRef(value);
476+
// cast 2
447477
obj->attr = Py_NewRef(value);
448478
}
449479
""")
@@ -476,7 +506,7 @@ def test_py_incref_assign(self):
476506
""")
477507

478508
self.check_dont_replace("""
479-
void true_false(int test)
509+
void test1(int test)
480510
{
481511
PyObject *res;
482512
if (test)
@@ -487,6 +517,17 @@ def test_py_incref_assign(self):
487517
488518
Py_DECREF(res);
489519
}
520+
521+
int test2(struct datetime* result, PyObject *tzinfo)
522+
{
523+
int res = 0;
524+
if (test)
525+
res = 1;
526+
else
527+
Py_INCREF(tzinfo);
528+
result->tzinfo = tzinfo;
529+
return res;
530+
}
490531
""")
491532

492533
def test_py_is(self):

upgrade_pythoncapi.py

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,13 @@
4646

4747

4848
def same_indentation(group):
49+
# the regex must have re.MULTILINE flag
4950
return fr'{SPACE_REGEX}*(?:{NEWLINE_REGEX}{group})?'
5051

5152

5253
def get_member_regex_str(member):
5354
# Match "var->member".
54-
return fr'\b({EXPR_REGEX}) *-> *%s\b' % member
55+
return fr'\b({EXPR_REGEX}) *-> *{member}\b'
5556

5657

5758
def get_member_regex(member):
@@ -67,7 +68,7 @@ def get_member_regex(member):
6768

6869
def assign_regex_str(var, expr):
6970
# Match "var = expr;".
70-
return (r'%s\s*=\s*%s\s*;' % (var, expr))
71+
return fr'{var}\s*=\s*{expr}\s*;'
7172

7273

7374
def set_member_regex(member):
@@ -80,7 +81,7 @@ def call_assign_regex(name):
8081
# Match "Py_TYPE(expr) = expr;".
8182
# Don't match "assert(Py_TYPE(expr) == expr);".
8283
# Tolerate spaces
83-
regex = (r'%s *\( *(.+) *\) *= *([^=].*) *;' % name)
84+
regex = fr'{name} *\( *(.+) *\) *= *([^=].*) *;'
8485
return re.compile(regex)
8586

8687

@@ -251,30 +252,66 @@ class Py_INCREF_return(Operation):
251252
+ r'return \3;',
252253
re.MULTILINE),
253254
r'\1return Py_\2NewRef(\3);'),
255+
256+
# Same regex than the previous one,
257+
# but the two statements are on the same line.
258+
(re.compile(fr'Py_(X?)INCREF\(({EXPR_REGEX})\)\s*;'
259+
+ fr'{SPACE_REGEX}*'
260+
+ r'return \2;',
261+
re.MULTILINE),
262+
r'return Py_\1NewRef(\2);'),
254263
)
255264
# Need Py_NewRef(): new in Python 3.10
256265
NEED_PYTHONCAPI_COMPAT = True
257266

258267

268+
def optional_ptr_cast(to_type):
269+
return fr'(?:\({to_type}\s*\*\))?'
270+
259271
class Py_INCREF_assign(Operation):
260272
NAME = "Py_INCREF_assign"
261273
REPLACE = (
262274
# "y = x; Py_INCREF(x);" => "y = Py_NewRef(x);"
263275
# "y = x; Py_INCREF(y);" => "y = Py_NewRef(x);"
264276
# "y = x; Py_XINCREF(x);" => "y = Py_XNewRef(x);"
265277
# "y = x; Py_XINCREF(y);" => "y = Py_XNewRef(x);"
278+
# "y = (PyObject*)x; Py_XINCREF(y);" => "y = Py_XNewRef(x);"
266279
# The two statements must have the same indentation, otherwise the
267280
# regex does not match.
268281
(re.compile(fr'({INDENTATION_REGEX})'
269-
+ assign_regex_str(r'(%s)' % EXPR_REGEX, r'(%s)' % EXPR_REGEX)
282+
+ assign_regex_str(fr'({EXPR_REGEX})',
283+
optional_ptr_cast('PyObject') + fr'({EXPR_REGEX})')
270284
+ same_indentation(r'\1')
271285
+ r'Py_(X?)INCREF\((?:\2|\3)\);',
272286
re.MULTILINE),
273287
r'\1\2 = Py_\4NewRef(\3);'),
288+
289+
# Same regex than the previous one,
290+
# but the two statements are on the same line.
291+
(re.compile(assign_regex_str(fr'({EXPR_REGEX})',
292+
optional_ptr_cast('PyObject') + fr'({EXPR_REGEX})')
293+
+ fr'{SPACE_REGEX}*'
294+
+ r'Py_(X?)INCREF\((?:\1|\2)\);'),
295+
r'\1 = Py_\3NewRef(\2);'),
296+
274297
# "Py_INCREF(x); y = x;" => "y = Py_NewRef(x)"
275298
# "Py_XINCREF(x); y = x;" => "y = Py_XNewRef(x)"
276-
(re.compile(r'Py_(X?)INCREF\((%s)\);\s*' % EXPR_REGEX
277-
+ assign_regex_str(r'(%s)' % EXPR_REGEX, r'\2')),
299+
# The two statements must have the same indentation, otherwise the
300+
# regex does not match.
301+
(re.compile(fr'({INDENTATION_REGEX})'
302+
+ fr'Py_(X?)INCREF\(({EXPR_REGEX})\);'
303+
+ same_indentation(r'\1')
304+
+ assign_regex_str(fr'({EXPR_REGEX})',
305+
optional_ptr_cast('PyObject') + r'\3'),
306+
re.MULTILINE),
307+
r'\1\4 = Py_\2NewRef(\3);'),
308+
309+
# Same regex than the previous one,
310+
# but the two statements are on the same line.
311+
(re.compile(fr'Py_(X?)INCREF\(({EXPR_REGEX})\);'
312+
+ fr'{SPACE_REGEX}*'
313+
+ assign_regex_str(fr'({EXPR_REGEX})',
314+
optional_ptr_cast('PyObject') + r'\2')),
278315
r'\3 = Py_\1NewRef(\2);'),
279316
)
280317
# Need Py_NewRef(): new in Python 3.10
@@ -292,7 +329,7 @@ def replace2(regs):
292329
return f'{x} = _Py_StealRef({y});'
293330

294331
REPLACE = []
295-
expr = r'(%s)' % EXPR_REGEX
332+
expr = fr'({EXPR_REGEX})'
296333
for name in ('None', 'True', 'False'):
297334
REPLACE.extend((
298335
(re.compile(fr'{expr} == Py_{name}\b'),
@@ -351,7 +388,7 @@ def log(self, msg=''):
351388
print(msg, file=sys.stderr, flush=True)
352389

353390
def warning(self, msg):
354-
self.log("WARNING: %s" % msg)
391+
self.log(f"WARNING: {msg}")
355392

356393
def _get_operations(self, parser):
357394
args_names = self.args.operations.split(',')
@@ -381,7 +418,7 @@ def _get_operations(self, parser):
381418
operations.append(operation)
382419

383420
if wanted:
384-
print("invalid operations: %s" % ','.join(wanted))
421+
print(f"invalid operations: {','.join(wanted)}")
385422
print()
386423
self.usage(parser)
387424
sys.exit(1)
@@ -479,8 +516,7 @@ def _walk_dir(self, path):
479516
empty = False
480517

481518
if empty:
482-
self.warning("Directory %s doesn't contain any "
483-
"C file" % path)
519+
self.warning(f"Directory {path} doesn't contain any C file")
484520
self.exitcode = 1
485521

486522
def walk(self, paths):
@@ -491,7 +527,7 @@ def walk(self, paths):
491527
elif os.path.exists(path):
492528
yield path
493529
else:
494-
self.warning("Path %s does not exist" % path)
530+
self.warning(f"Path {path} does not exist")
495531
self.exitcode = 1
496532

497533
def get_latest_header(self, base_dir):

0 commit comments

Comments
 (0)