From 36324ee63056b29bc9eaced9a51d3f5cc4ba5c66 Mon Sep 17 00:00:00 2001 From: Noxaster <208382900+Noxaster@users.noreply.github.com> Date: Fri, 13 Feb 2026 01:28:38 +0100 Subject: [PATCH] MAINT: Replace %-formatting with f-strings in numpy/_build_utils (UP031) (#30799) Co-authored-by: Joren Hammudoglu --- numpy/_build_utils/conv_template.py | 14 ++-- numpy/_build_utils/tempita/_looper.py | 6 +- numpy/_build_utils/tempita/_tempita.py | 92 ++++++++++++-------------- 3 files changed, 51 insertions(+), 61 deletions(-) diff --git a/numpy/_build_utils/conv_template.py b/numpy/_build_utils/conv_template.py index fb57abdf1587..3f6347371ae0 100644 --- a/numpy/_build_utils/conv_template.py +++ b/numpy/_build_utils/conv_template.py @@ -110,8 +110,8 @@ def parse_structure(astr, level): loopbeg = "/**begin repeat" loopend = "/**end repeat**/" else: - loopbeg = "/**begin repeat%d" % level - loopend = "/**end repeat%d**/" % level + loopbeg = f"/**begin repeat{level}" + loopend = f"/**end repeat{level}**/" ind = 0 line = 0 @@ -214,7 +214,7 @@ def parse_loop_header(loophead): def parse_string(astr, env, level, line): - lineno = "#line %d\n" % line + lineno = f"#line {line}\n" # local function for string replacement, uses env def replace(match): @@ -242,7 +242,7 @@ def replace(match): try: envlist = parse_loop_header(head) except ValueError as e: - msg = "line %d: %s" % (newline, e) + msg = f"line {newline}: {e}" raise ValueError(msg) for newenv in envlist: newenv.update(env) @@ -289,8 +289,8 @@ def process_file(source): try: code = process_str(''.join(lines)) except ValueError as e: - raise ValueError('In "%s" loop at %s' % (sourcefile, e)) from None - return '#line 1 "%s"\n%s' % (sourcefile, code) + raise ValueError(f'In "{sourcefile}" loop at {e}') from None + return f'#line 1 "{sourcefile}"\n{code}' def unique_key(adict): @@ -326,7 +326,7 @@ def main(): try: writestr = process_str(allstr) except ValueError as e: - raise ValueError("In %s loop at %s" % (file, e)) from None + raise ValueError(f"In {file} loop at {e}") from None outfile.write(writestr) diff --git a/numpy/_build_utils/tempita/_looper.py b/numpy/_build_utils/tempita/_looper.py index e7d6b2649fb5..0d3de22ac80c 100644 --- a/numpy/_build_utils/tempita/_looper.py +++ b/numpy/_build_utils/tempita/_looper.py @@ -41,8 +41,7 @@ def __iter__(self): return looper_iter(self.seq) def __repr__(self): - return '<%s for %r>' % ( - self.__class__.__name__, self.seq) + return f'<{self.__class__.__name__} for {self.seq!r}>' class looper_iter: @@ -69,8 +68,7 @@ def __init__(self, seq, pos): self.pos = pos def __repr__(self): - return '' % ( - self.seq[self.pos], self.pos) + return f'' def index(self): return self.pos diff --git a/numpy/_build_utils/tempita/_tempita.py b/numpy/_build_utils/tempita/_tempita.py index 88ead791574b..3d5113085183 100644 --- a/numpy/_build_utils/tempita/_tempita.py +++ b/numpy/_build_utils/tempita/_tempita.py @@ -64,9 +64,9 @@ def __init__(self, message, position, name=None): def __str__(self): msg = " ".join(self.args) if self.position: - msg = "%s at line %s column %s" % (msg, self.position[0], self.position[1]) + msg = f"{msg} at line {self.position[0]} column {self.position[1]}" if self.name: - msg += " in %s" % self.name + msg += f" in {self.name}" return msg @@ -140,7 +140,7 @@ def __init__( else: name = "" if lineno: - name += ":%s" % lineno + name += f":{lineno}" self.name = name self._parsed = parse( content, name=name, line_offset=line_offset, delimiters=self.delimiters @@ -185,8 +185,8 @@ def substitute(self, *args, **kw): if not hasattr(args[0], "items"): raise TypeError( "If you pass in a single argument, you must pass in a " - "dictionary-like object (with a .items() method); you gave %r" - % (args[0],) + "dictionary-like object (with a .items() method); " + f"you gave {args[0]!r}" ) kw = args[0] ns = kw @@ -278,7 +278,7 @@ def _interpret_code(self, code, ns, out, defs): elif name == "comment": return else: - assert 0, "Unknown code: %r" % name + assert 0, f"Unknown code: {name!r}" def _interpret_for(self, vars, expr, content, ns, out, defs): __traceback_hide__ = True @@ -288,8 +288,7 @@ def _interpret_for(self, vars, expr, content, ns, out, defs): else: if len(vars) != len(item): raise ValueError( - "Need %i items to unpack (got %i items)" - % (len(vars), len(item)) + f"Need {len(vars)} items to unpack (got {len(item)} items)" ) for name, value in zip(vars, item): ns[name] = value @@ -320,7 +319,7 @@ def _eval(self, code, ns, pos): try: value = eval(code, self.default_namespace, ns) except SyntaxError as e: - raise SyntaxError("invalid syntax in expression: %s" % code) + raise SyntaxError(f"invalid syntax in expression: {code}") return value except Exception as e: if getattr(e, "args", None): @@ -363,8 +362,8 @@ def _repr(self, value, pos): if self._unicode and isinstance(value, bytes): if not self.default_encoding: raise UnicodeDecodeError( - "Cannot decode bytes value %r into unicode " - "(no default_encoding provided)" % value + f"Cannot decode bytes value {value!r} into unicode " + "(no default_encoding provided)" ) try: value = value.decode(self.default_encoding) @@ -374,21 +373,21 @@ def _repr(self, value, pos): e.object, e.start, e.end, - e.reason + " in string %r" % value, + e.reason + f" in string {value!r}", ) elif not self._unicode and isinstance(value, str): if not self.default_encoding: raise UnicodeEncodeError( - "Cannot encode unicode value %r into bytes " - "(no default_encoding provided)" % value + f"Cannot encode unicode value {value!r} into bytes " + "(no default_encoding provided)" ) value = value.encode(self.default_encoding) return value def _add_line_info(self, msg, pos): - msg = "%s at line %s column %s" % (msg, pos[0], pos[1]) + msg = f"{msg} at line {pos[0]} column {pos[1]}" if self.name: - msg += " in file %s" % self.name + msg += f" in file {self.name}" return msg @@ -427,10 +426,8 @@ def __getitem__(self, key): return dict.__getitem__(self, key) def __repr__(self): - return "<%s %s>" % ( - self.__class__.__name__, - " ".join(["%s=%r" % (k, v) for k, v in sorted(self.items())]), - ) + items_str = " ".join([f"{k}={v!r}" for k, v in sorted(self.items())]) + return f"<{self.__class__.__name__} {items_str}>" class TemplateDef: @@ -446,12 +443,8 @@ def __init__( self._bound_self = bound_self def __repr__(self): - return "" % ( - self._func_name, - self._func_signature, - self._template.name, - self._pos, - ) + return (f"") def __str__(self): return self() @@ -486,7 +479,7 @@ def _parse_signature(self, args, kw): extra_kw = {} for name, value in kw.items(): if not var_kw and name not in sig_args: - raise TypeError("Unexpected argument %s" % name) + raise TypeError(f"Unexpected argument {name}") if name in sig_args: values[sig_args] = value else: @@ -503,15 +496,14 @@ def _parse_signature(self, args, kw): values[var_args] = tuple(args) break else: - raise TypeError( - "Extra position arguments: %s" % ", ".join([repr(v) for v in args]) - ) + args_str = ", ".join([repr(v) for v in args]) + raise TypeError(f"Extra position arguments: {args_str}") for name, value_expr in defaults.items(): if name not in values: values[name] = self._template._eval(value_expr, self._ns, self._pos) for name in sig_args: if name not in values: - raise TypeError("Missing argument: %s" % name) + raise TypeError(f"Missing argument: {name}") if var_kw: values[var_kw] = extra_kw return values @@ -523,7 +515,7 @@ def __init__(self, name): self.get = TemplateObjectGetter(self) def __repr__(self): - return "<%s %s>" % (self.__class__.__name__, self.__name) + return f"<{self.__class__.__name__} {self.__name}>" class TemplateObjectGetter: @@ -534,7 +526,7 @@ def __getattr__(self, attr): return getattr(self.__template_obj, attr, Empty) def __repr__(self): - return "<%s around %r>" % (self.__class__.__name__, self.__template_obj) + return f"<{self.__class__.__name__} around {self.__template_obj!r}>" class _Empty: @@ -598,18 +590,18 @@ def lex(s, name=None, trim_whitespace=True, line_offset=0, delimiters=None): last_pos = (line_offset + 1, 1) token_re = re.compile( - r"%s|%s" % (re.escape(delimiters[0]), re.escape(delimiters[1])) + rf"{re.escape(delimiters[0])}|{re.escape(delimiters[1])}" ) for match in token_re.finditer(s): expr = match.group(0) pos = find_position(s, match.end(), last, last_pos) if expr == delimiters[0] and in_expr: raise TemplateError( - "%s inside expression" % delimiters[0], position=pos, name=name + f"{delimiters[0]} inside expression", position=pos, name=name ) elif expr == delimiters[1] and not in_expr: raise TemplateError( - "%s outside expression" % delimiters[1], position=pos, name=name + f"{delimiters[1]} outside expression", position=pos, name=name ) if expr == delimiters[0]: part = s[last:match.start()] @@ -623,7 +615,7 @@ def lex(s, name=None, trim_whitespace=True, line_offset=0, delimiters=None): last_pos = pos if in_expr: raise TemplateError( - "No %s to finish last expression" % delimiters[1], + f"No {delimiters[1]} to finish last expression", name=name, position=last_pos, ) @@ -800,12 +792,12 @@ def parse_expr(tokens, name, context=()): return parse_cond(tokens, name, context) elif expr.startswith("elif ") or expr == "else": raise TemplateError( - "%s outside of an if block" % expr.split()[0], position=pos, name=name + f"{expr.split()[0]} outside of an if block", position=pos, name=name ) elif expr in ("if", "elif", "for"): - raise TemplateError("%s with no expression" % expr, position=pos, name=name) + raise TemplateError(f"{expr} with no expression", position=pos, name=name) elif expr in ("endif", "endfor", "enddef"): - raise TemplateError("Unexpected %s" % expr, position=pos, name=name) + raise TemplateError(f"Unexpected {expr}", position=pos, name=name) elif expr.startswith("for "): return parse_for(tokens, name, context) elif expr.startswith("default "): @@ -843,7 +835,7 @@ def parse_one_cond(tokens, name, context): elif first == "else": part = ("else", pos, None, content) else: - assert 0, "Unexpected token %r at %s" % (first, pos) + assert 0, f"Unexpected token {first!r} at {pos}" while 1: if not tokens: raise TemplateError("No {{endif}}", position=pos, name=name) @@ -867,11 +859,11 @@ def parse_for(tokens, name, context): first = first[3:].strip() match = in_re.search(first) if not match: - raise TemplateError('Bad for (no "in") in %r' % first, position=pos, name=name) + raise TemplateError(f'Bad for (no "in") in {first!r}', position=pos, name=name) vars = first[: match.start()] if "(" in vars: raise TemplateError( - "You cannot have () in the variable section of a for loop (%r)" % vars, + f"You cannot have () in the variable section of a for loop ({vars!r})", position=pos, name=name, ) @@ -893,7 +885,7 @@ def parse_default(tokens, name, context): parts = first.split("=", 1) if len(parts) == 1: raise TemplateError( - "Expression must be {{default var=value}}; no = found in %r" % first, + f"Expression must be {{{{default var=value}}}}; no = found in {first!r}", position=pos, name=name, ) @@ -904,7 +896,7 @@ def parse_default(tokens, name, context): ) if not var_re.search(var): raise TemplateError( - "Not a valid variable name for {{default}}: %r" % var, + f"Not a valid variable name for {{{{default}}}}: {var!r}", position=pos, name=name, ) @@ -930,7 +922,7 @@ def parse_def(tokens, name, context): sig = ((), None, None, {}) elif not first.endswith(")"): raise TemplateError( - "Function definition doesn't end with ): %s" % first, + f"Function definition doesn't end with ): {first}", position=start, name=name, ) @@ -976,7 +968,7 @@ def get_token(pos=False): tok_type, tok_string = get_token() if tok_type != tokenize.NAME: raise TemplateError( - "Invalid signature: (%s)" % sig_text, position=pos, name=name + f"Invalid signature: ({sig_text})", position=pos, name=name ) var_name = tok_string tok_type, tok_string = get_token() @@ -994,7 +986,7 @@ def get_token(pos=False): continue if var_arg_type is not None: raise TemplateError( - "Invalid signature: (%s)" % sig_text, position=pos, name=name + f"Invalid signature: ({sig_text})", position=pos, name=name ) if tok_type == tokenize.OP and tok_string == "=": nest_type = None @@ -1009,7 +1001,7 @@ def get_token(pos=False): end_pos = e if tok_type == tokenize.ENDMARKER and nest_count: raise TemplateError( - "Invalid signature: (%s)" % sig_text, position=pos, name=name + f"Invalid signature: ({sig_text})", position=pos, name=name ) if not nest_count and ( tok_type == tokenize.ENDMARKER @@ -1098,7 +1090,7 @@ def fill_command(args=None): vars.update(os.environ) for value in args: if "=" not in value: - print("Bad argument: %r" % value) + print(f"Bad argument: {value!r}") sys.exit(2) name, value = value.split("=", 1) if name.startswith("py:"):