4646
4747
4848def same_indentation (group ):
49+ # the regex must have re.MULTILINE flag
4950 return fr'{ SPACE_REGEX } *(?:{ NEWLINE_REGEX } { group } )?'
5051
5152
5253def 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
5758def get_member_regex (member ):
@@ -67,7 +68,7 @@ def get_member_regex(member):
6768
6869def 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
7374def 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+
259271class 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