]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
*: Switch from percent formatting to f-strings 3403/head
authorBen Darnell <ben@bendarnell.com>
Thu, 13 Jun 2024 19:25:50 +0000 (15:25 -0400)
committerBen Darnell <ben@bendarnell.com>
Thu, 13 Jun 2024 19:25:50 +0000 (15:25 -0400)
Automated change using pyupgrade in two passes (once to go from percent
formatting to str.format, then to go from str.format to f-strings),
followed by black.

This left a few uses of str.format for unknown reasons.

22 files changed:
demos/webspider/webspider.py
tornado/auth.py
tornado/escape.py
tornado/gen.py
tornado/http1connection.py
tornado/httpclient.py
tornado/httputil.py
tornado/locale.py
tornado/locks.py
tornado/log.py
tornado/queues.py
tornado/routing.py
tornado/simple_httpclient.py
tornado/template.py
tornado/test/curl_httpclient_test.py
tornado/test/gen_test.py
tornado/test/httpclient_test.py
tornado/test/httpserver_test.py
tornado/test/simple_httpclient_test.py
tornado/test/web_test.py
tornado/testing.py
tornado/web.py

index d7757917f4cfe42df2373489aa7bb84b7354f255..0c62a70f86e5af0ec78769bde4bd749307bc9d97 100755 (executable)
@@ -74,7 +74,7 @@ async def main():
             try:
                 await fetch_url(url)
             except Exception as e:
-                print("Exception: %s %s" % (e, url))
+                print(f"Exception: {e} {url}")
                 dead.add(url)
             finally:
                 q.task_done()
index 035d34b0458ffa079189e45bffa938a35a8ba424..64428c59ea75108a13dad16e3fc517dda02b4c45 100644 (file)
@@ -1170,9 +1170,7 @@ def _oauth_signature(
     base_elems.append(method.upper())
     base_elems.append(normalized_url)
     base_elems.append(
-        "&".join(
-            "%s=%s" % (k, _oauth_escape(str(v))) for k, v in sorted(parameters.items())
-        )
+        "&".join(f"{k}={_oauth_escape(str(v))}" for k, v in sorted(parameters.items()))
     )
     base_string = "&".join(_oauth_escape(e) for e in base_elems)
 
@@ -1203,9 +1201,7 @@ def _oauth10a_signature(
     base_elems.append(method.upper())
     base_elems.append(normalized_url)
     base_elems.append(
-        "&".join(
-            "%s=%s" % (k, _oauth_escape(str(v))) for k, v in sorted(parameters.items())
-        )
+        "&".join(f"{k}={_oauth_escape(str(v))}" for k, v in sorted(parameters.items()))
     )
 
     base_string = "&".join(_oauth_escape(e) for e in base_elems)
index 023ee16af489a29fc4cefccf83aa6327f451a2bd..8515bf58fb6e23f53dc1b4d2b01910883874c76e 100644 (file)
@@ -392,7 +392,7 @@ def linkify(
                     # have a status bar, such as Safari by default)
                     params += ' title="%s"' % href
 
-        return '<a href="%s"%s>%s</a>' % (href, params, url)
+        return f'<a href="{href}"{params}>{url}</a>'
 
     # First HTML-escape so that our strings are all safe.
     # The regex is modified to avoid character entites other than &amp; so
index c824c9ff6660b449ab1045ede9e709141cd09cea..51fa4c19aecd6ccf0796626bf1f08adeb263b9a4 100644 (file)
@@ -874,7 +874,7 @@ def convert_yielded(yielded: _Yieldable) -> Future:
     elif isawaitable(yielded):
         return _wrap_awaitable(yielded)  # type: ignore
     else:
-        raise BadYieldError("yielded unknown object %r" % (yielded,))
+        raise BadYieldError(f"yielded unknown object {yielded!r}")
 
 
 convert_yielded = singledispatch(convert_yielded)
index 53cfca9686ca7a908b02b3c460b6aa535fa7dca1..8dd0c9b6e27d5faab1456fcf466803c03b26c712 100644 (file)
@@ -389,7 +389,7 @@ class HTTP1Connection(httputil.HTTPConnection):
         if self.is_client:
             assert isinstance(start_line, httputil.RequestStartLine)
             self._request_start_line = start_line
-            lines.append(utf8("%s %s HTTP/1.1" % (start_line[0], start_line[1])))
+            lines.append(utf8(f"{start_line[0]} {start_line[1]} HTTP/1.1"))
             # Client requests with a non-empty body must have either a
             # Content-Length or a Transfer-Encoding. If Content-Length is not
             # present we'll add our Transfer-Encoding below.
index 1fc04c64f06b031ea3ccd202fda7526a31a9b1ef..3a45ffd0415b087e267385067678f87bb117728f 100644 (file)
@@ -684,7 +684,7 @@ class HTTPResponse:
 
     def __repr__(self) -> str:
         args = ",".join("%s=%r" % i for i in sorted(self.__dict__.items()))
-        return "%s(%s)" % (self.__class__.__name__, args)
+        return f"{self.__class__.__name__}({args})"
 
 
 class HTTPClientError(Exception):
index bffb7bd0096d39aad6f1f382a7ad4a4534e5a5fd..4ec7b68fedbf9469c8790432572cadfa9af9c330 100644 (file)
@@ -247,7 +247,7 @@ class HTTPHeaders(StrMutableMapping):
     def __str__(self) -> str:
         lines = []
         for name, value in self.get_all():
-            lines.append("%s: %s\n" % (name, value))
+            lines.append(f"{name}: {value}\n")
         return "".join(lines)
 
     __unicode__ = __str__
@@ -471,8 +471,8 @@ class HTTPServerRequest:
 
     def __repr__(self) -> str:
         attrs = ("protocol", "host", "method", "uri", "version", "remote_ip")
-        args = ", ".join(["%s=%r" % (n, getattr(self, n)) for n in attrs])
-        return "%s(%s)" % (self.__class__.__name__, args)
+        args = ", ".join([f"{n}={getattr(self, n)!r}" for n in attrs])
+        return f"{self.__class__.__name__}({args})"
 
 
 class HTTPInputError(Exception):
@@ -741,7 +741,7 @@ def _get_content_range(start: Optional[int], end: Optional[int], total: int) ->
     """
     start = start or 0
     end = (end or total) - 1
-    return "bytes %s-%s/%s" % (start, end, total)
+    return f"bytes {start}-{end}/{total}"
 
 
 def _int_or_none(val: str) -> Optional[int]:
@@ -1008,7 +1008,7 @@ def _encode_header(key: str, pdict: Dict[str, str]) -> str:
             out.append(k)
         else:
             # TODO: quote if necessary.
-            out.append("%s=%s" % (k, v))
+            out.append(f"{k}={v}")
     return "; ".join(out)
 
 
index 3fb1a686164f3995b0ccf996b6533e29e9ab2ce6..abd8668c6ecefa8827a29843573eede20eaa60b6 100644 (file)
@@ -569,8 +569,8 @@ class GettextLocale(Locale):
         if plural_message is not None:
             assert count is not None
             msgs_with_ctxt = (
-                "%s%s%s" % (context, CONTEXT_SEPARATOR, message),
-                "%s%s%s" % (context, CONTEXT_SEPARATOR, plural_message),
+                f"{context}{CONTEXT_SEPARATOR}{message}",
+                f"{context}{CONTEXT_SEPARATOR}{plural_message}",
                 count,
             )
             result = self.ngettext(*msgs_with_ctxt)
@@ -579,7 +579,7 @@ class GettextLocale(Locale):
                 result = self.ngettext(message, plural_message, count)
             return result
         else:
-            msg_with_ctxt = "%s%s%s" % (context, CONTEXT_SEPARATOR, message)
+            msg_with_ctxt = f"{context}{CONTEXT_SEPARATOR}{message}"
             result = self.gettext(msg_with_ctxt)
             if CONTEXT_SEPARATOR in result:
                 # Translation not found
index 6d794687db08b62b4108cb31997a7ac2f2c827d0..9ee1f2f0f3b167622e48ac03c075c9c1806fb8d7 100644 (file)
@@ -111,7 +111,7 @@ class Condition(_TimeoutGarbageCollector):
     """
 
     def __repr__(self) -> str:
-        result = "<%s" % (self.__class__.__name__,)
+        result = f"<{self.__class__.__name__}"
         if self._waiters:
             result += " waiters[%s]" % len(self._waiters)
         return result + ">"
@@ -200,7 +200,7 @@ class Event:
         self._waiters = set()  # type: Set[Future[None]]
 
     def __repr__(self) -> str:
-        return "<%s %s>" % (
+        return "<{} {}>".format(
             self.__class__.__name__,
             "set" if self.is_set() else "clear",
         )
@@ -389,12 +389,10 @@ class Semaphore(_TimeoutGarbageCollector):
 
     def __repr__(self) -> str:
         res = super().__repr__()
-        extra = (
-            "locked" if self._value == 0 else "unlocked,value:{0}".format(self._value)
-        )
+        extra = "locked" if self._value == 0 else f"unlocked,value:{self._value}"
         if self._waiters:
-            extra = "{0},waiters:{1}".format(extra, len(self._waiters))
-        return "<{0} [{1}]>".format(res[1:-1], extra)
+            extra = f"{extra},waiters:{len(self._waiters)}"
+        return f"<{res[1:-1]} [{extra}]>"
 
     def release(self) -> None:
         """Increment the counter and wake one waiter."""
@@ -525,7 +523,7 @@ class Lock:
         self._block = BoundedSemaphore(value=1)
 
     def __repr__(self) -> str:
-        return "<%s _block=%s>" % (self.__class__.__name__, self._block)
+        return f"<{self.__class__.__name__} _block={self._block}>"
 
     def acquire(
         self, timeout: Optional[Union[float, datetime.timedelta]] = None
index 86998961397bd2970755f87c02049a62fa34a76a..f5ca5c0c40b5eecdd6a69893b6f417be7b1d1914 100644 (file)
@@ -187,7 +187,7 @@ class LogFormatter(logging.Formatter):
             # byte strings wherever possible).
             record.message = _safe_unicode(message)
         except Exception as e:
-            record.message = "Bad message (%r): %r" % (e, record.__dict__)
+            record.message = f"Bad message ({e!r}): {record.__dict__!r}"
 
         record.asctime = self.formatTime(record, cast(str, self.datefmt))
 
index 1358d0ecf1b1f8ea0f6d33cbb121ecfb07094fa6..9552633330101cfd45a89efa85ef9db95063c863 100644 (file)
@@ -328,13 +328,13 @@ class Queue(Generic[_T]):
             self._getters.popleft()
 
     def __repr__(self) -> str:
-        return "<%s at %s %s>" % (type(self).__name__, hex(id(self)), self._format())
+        return f"<{type(self).__name__} at {hex(id(self))} {self._format()}>"
 
     def __str__(self) -> str:
-        return "<%s %s>" % (type(self).__name__, self._format())
+        return f"<{type(self).__name__} {self._format()}>"
 
     def _format(self) -> str:
-        result = "maxsize=%r" % (self.maxsize,)
+        result = f"maxsize={self.maxsize!r}"
         if getattr(self, "_queue", None):
             result += " queue=%r" % self._queue
         if self._getters:
index 324818ebc4168464b6cc107883bd7c5e014c1055..ee81f977073088a1cce39c9e89508f189a6a1b33 100644 (file)
@@ -478,7 +478,7 @@ class Rule:
         return self.matcher.reverse(*args)
 
     def __repr__(self) -> str:
-        return "%s(%r, %s, kwargs=%r, name=%r)" % (
+        return "{}({!r}, {}, kwargs={!r}, name={!r})".format(
             self.__class__.__name__,
             self.matcher,
             self.target,
@@ -686,7 +686,7 @@ class URLSpec(Rule):
         self.kwargs = kwargs
 
     def __repr__(self) -> str:
-        return "%s(%r, %s, kwargs=%r, name=%r)" % (
+        return "{}({!r}, {}, kwargs={!r}, name={!r})".format(
             self.__class__.__name__,
             self.regex.pattern,
             self.handler_class,
index 79fe292de75d3919428458ea17bc95436e60e1f1..cc1637613350dd9e9a812b1da50aa2fef02ad286 100644 (file)
@@ -238,7 +238,7 @@ class SimpleAsyncHTTPClient(AsyncHTTPClient):
         request, callback, timeout_handle = self.waiting[key]
         self.queue.remove((key, request, callback))
 
-        error_message = "Timeout {0}".format(info) if info else "Timeout"
+        error_message = f"Timeout {info}" if info else "Timeout"
         timeout_response = HTTPResponse(
             request,
             599,
@@ -399,7 +399,7 @@ class _HTTPConnection(httputil.HTTPMessageDelegate):
             if self.request.user_agent:
                 self.request.headers["User-Agent"] = self.request.user_agent
             elif self.request.headers.get("User-Agent") is None:
-                self.request.headers["User-Agent"] = "Tornado/{}".format(version)
+                self.request.headers["User-Agent"] = f"Tornado/{version}"
             if not self.request.allow_nonstandard_methods:
                 # Some HTTP methods nearly always have bodies while others
                 # almost never do. Fail in this case unless the user has
@@ -485,7 +485,7 @@ class _HTTPConnection(httputil.HTTPMessageDelegate):
         :info string key: More detailed timeout information.
         """
         self._timeout = None
-        error_message = "Timeout {0}".format(info) if info else "Timeout"
+        error_message = f"Timeout {info}" if info else "Timeout"
         if self.final_callback is not None:
             self._handle_exception(
                 HTTPTimeoutError, HTTPTimeoutError(error_message), None
@@ -605,7 +605,7 @@ class _HTTPConnection(httputil.HTTPMessageDelegate):
             # Reassemble the start line.
             self.request.header_callback("%s %s %s\r\n" % first_line)
             for k, v in self.headers.get_all():
-                self.request.header_callback("%s: %s\r\n" % (k, v))
+                self.request.header_callback(f"{k}: {v}\r\n")
             self.request.header_callback("\r\n")
 
     def _should_follow_redirect(self) -> bool:
index 921545ccf0e5c884cb337ded878d5dcac2b95a40..0064c6fbd1fff31b630b8579712c26d73feb4fe8 100644 (file)
@@ -610,7 +610,7 @@ class _ApplyBlock(_Node):
             self.body.generate(writer)
             writer.write_line("return _tt_utf8('').join(_tt_buffer)", self.line)
         writer.write_line(
-            "_tt_append(_tt_utf8(%s(%s())))" % (self.method, method_name), self.line
+            f"_tt_append(_tt_utf8({self.method}({method_name}())))", self.line
         )
 
 
@@ -944,12 +944,10 @@ def _parse(
         allowed_parents = intermediate_blocks.get(operator)
         if allowed_parents is not None:
             if not in_block:
-                reader.raise_parse_error(
-                    "%s outside %s block" % (operator, allowed_parents)
-                )
+                reader.raise_parse_error(f"{operator} outside {allowed_parents} block")
             if in_block not in allowed_parents:
                 reader.raise_parse_error(
-                    "%s block cannot be attached to %s block" % (operator, in_block)
+                    f"{operator} block cannot be attached to {in_block} block"
                 )
             body.chunks.append(_IntermediateControlBlock(contents, line))
             continue
@@ -1038,7 +1036,7 @@ def _parse(
         elif operator in ("break", "continue"):
             if not in_loop:
                 reader.raise_parse_error(
-                    "%s outside %s block" % (operator, {"for", "while"})
+                    "{} outside {} block".format(operator, {"for", "while"})
                 )
             body.chunks.append(_Statement(contents, line))
             continue
index 99af29336710b06b855641c3c1cab83494094196..ce3f68d7f779ea227aa4f590d37874d6f9dc1a16 100644 (file)
@@ -51,13 +51,9 @@ class DigestAuthHandler(RequestHandler):
             assert param_dict["nonce"] == nonce
             assert param_dict["username"] == self.username
             assert param_dict["uri"] == self.request.path
-            h1 = md5(
-                utf8("%s:%s:%s" % (self.username, realm, self.password))
-            ).hexdigest()
-            h2 = md5(
-                utf8("%s:%s" % (self.request.method, self.request.path))
-            ).hexdigest()
-            digest = md5(utf8("%s:%s:%s" % (h1, nonce, h2))).hexdigest()
+            h1 = md5(utf8(f"{self.username}:{realm}:{self.password}")).hexdigest()
+            h2 = md5(utf8(f"{self.request.method}:{self.request.path}")).hexdigest()
+            digest = md5(utf8(f"{h1}:{nonce}:{h2}")).hexdigest()
             if digest == param_dict["response"]:
                 self.write("ok")
             else:
@@ -66,7 +62,7 @@ class DigestAuthHandler(RequestHandler):
             self.set_status(401)
             self.set_header(
                 "WWW-Authenticate",
-                'Digest realm="%s", nonce="%s", opaque="%s"' % (realm, nonce, opaque),
+                f'Digest realm="{realm}", nonce="{nonce}", opaque="{opaque}"',
             )
 
 
index 3190ef40f7c7f7dfd6635d17017fd78414107570..87f6ab7fa497aa48e0b0bd9850dce0fd25992a25 100644 (file)
@@ -853,7 +853,7 @@ class WaitIteratorTest(AsyncTestCase):
                     "WaitIterator dict status incorrect",
                 )
             else:
-                self.fail("got bad WaitIterator index {}".format(dg.current_index))
+                self.fail(f"got bad WaitIterator index {dg.current_index}")
 
             i += 1
         self.assertIsNone(g.current_index, "bad nil current index")
index 1eb758b5551581e5dd392cd491802c41c92bad6f..40a29d0b9ebee62c4ae0d97166b73035c155ef69 100644 (file)
@@ -146,7 +146,7 @@ class InvalidGzipHandler(RequestHandler):
         # Triggering the potential bug seems to depend on input length.
         # This length is taken from the bad-response example reported in
         # https://github.com/tornadoweb/tornado/pull/2875 (uncompressed).
-        text = "".join("Hello World {}\n".format(i) for i in range(9000))[:149051]
+        text = "".join(f"Hello World {i}\n" for i in range(9000))[:149051]
         body = gzip.compress(text.encode(), compresslevel=6) + b"\00"
         self.write(body)
 
@@ -701,7 +701,7 @@ X-XSS-Protection: 1;
         self.assertLess(abs(response.start_time - start_time), 1.0)
 
         for k, v in response.time_info.items():
-            self.assertTrue(0 <= v < 1.0, "time_info[%s] out of bounds: %s" % (k, v))
+            self.assertTrue(0 <= v < 1.0, f"time_info[{k}] out of bounds: {v}")
 
     def test_zero_timeout(self):
         response = self.fetch("/hello", connect_timeout=0)
index 857554055a80323d9d4537192839c1b95f25cf6f..5657f629c3ce899d7ab90859c9ff944eac6c45c9 100644 (file)
@@ -380,7 +380,7 @@ class TypeCheckHandler(RequestHandler):
     def check_type(self, name, obj, expected_type):
         actual_type = type(obj)
         if expected_type != actual_type:
-            self.errors[name] = "expected %s, got %s" % (expected_type, actual_type)
+            self.errors[name] = f"expected {expected_type}, got {actual_type}"
 
 
 class PostEchoHandler(RequestHandler):
index bcb1aaba26964eecc7615088085d94c7abcd0250..3bb66187648cabce2091a9bc02e7919a4482da66 100644 (file)
@@ -251,7 +251,7 @@ class SimpleHTTPClientTestMixin:
     def test_default_user_agent(self: typing.Any):
         response = self.fetch("/user_agent", method="GET")
         self.assertEqual(200, response.code)
-        self.assertEqual(response.body.decode(), "Tornado/{}".format(version))
+        self.assertEqual(response.body.decode(), f"Tornado/{version}")
 
     def test_see_other_redirect(self: typing.Any):
         for code in (302, 303):
index ac55aa39a18abe3a32956957c72c939542ed28cd..32a12bad990b6a8ebd511b352528e9ac5ad3fb91 100644 (file)
@@ -158,7 +158,7 @@ class SecureCookieV1Test(unittest.TestCase):
         )
         # tamper with the cookie
         handler._cookies["foo"] = utf8(
-            "1234|5678%s|%s" % (to_basestring(timestamp), to_basestring(sig))
+            f"1234|5678{to_basestring(timestamp)}|{to_basestring(sig)}"
         )
         # it gets rejected
         with ExpectLog(gen_log, "Cookie timestamp in future"):
@@ -625,7 +625,7 @@ class TypeCheckHandler(RequestHandler):
     def check_type(self, name, obj, expected_type):
         actual_type = type(obj)
         if expected_type != actual_type:
-            self.errors[name] = "expected %s, got %s" % (expected_type, actual_type)
+            self.errors[name] = f"expected {expected_type}, got {actual_type}"
 
 
 class DecodeArgHandler(RequestHandler):
@@ -1511,7 +1511,7 @@ class CustomStaticFileTest(WebTestCase):
                 extension_index = path.rindex(".")
                 before_version = path[:extension_index]
                 after_version = path[(extension_index + 1) :]
-                return "/static/%s.%s.%s" % (
+                return "/static/{}.{}.{}".format(
                     before_version,
                     version_hash,
                     after_version,
@@ -1520,7 +1520,7 @@ class CustomStaticFileTest(WebTestCase):
             def parse_url_path(self, url_path):
                 extension_index = url_path.rindex(".")
                 version_index = url_path.rindex(".", 0, extension_index)
-                return "%s%s" % (url_path[:version_index], url_path[extension_index:])
+                return f"{url_path[:version_index]}{url_path[extension_index:]}"
 
             @classmethod
             def get_absolute_path(cls, settings, path):
@@ -1976,11 +1976,11 @@ class UIMethodUIModuleTest(SimpleHandlerTestCase):
 
     def get_app_kwargs(self):
         def my_ui_method(handler, x):
-            return "In my_ui_method(%s) with handler value %s." % (x, handler.value())
+            return f"In my_ui_method({x}) with handler value {handler.value()}."
 
         class MyModule(UIModule):
             def render(self, x):
-                return "In MyModule(%s) with handler value %s." % (
+                return "In MyModule({}) with handler value {}.".format(
                     x,
                     typing.cast(UIMethodUIModuleTest.Handler, self.handler).value(),
                 )
@@ -2038,7 +2038,7 @@ class SetLazyPropertiesTest(SimpleHandlerTestCase):
             raise NotImplementedError()
 
         def get(self):
-            self.write("Hello %s (%s)" % (self.current_user, self.locale.code))
+            self.write(f"Hello {self.current_user} ({self.locale.code})")
 
     def test_set_properties(self):
         # Ensure that current_user can be assigned to normally for apps
@@ -2400,7 +2400,7 @@ class BaseFlowControlHandler(RequestHandler):
     @contextlib.contextmanager
     def in_method(self, method):
         if self.method is not None:
-            self.test.fail("entered method %s while in %s" % (method, self.method))
+            self.test.fail(f"entered method {method} while in {self.method}")
         self.method = method
         self.methods.append(method)
         try:
index 4064873d487495a368a46caa46314f4aa0e00db6..a397e3fa1cadee67d43a411c46cc40eb1deb2ce8 100644 (file)
@@ -466,7 +466,7 @@ class AsyncHTTPTestCase(AsyncTestCase):
 
     def get_url(self, path: str) -> str:
         """Returns an absolute url for the given path on the test server."""
-        return "%s://127.0.0.1:%s%s" % (self.get_protocol(), self.get_http_port(), path)
+        return f"{self.get_protocol()}://127.0.0.1:{self.get_http_port()}{path}"
 
     def tearDown(self) -> None:
         self.http_server.stop()
index aa64145ecd92a99a0d64332a9490658220778ae0..3514760ee430a2fd31257cc3fbe0b6aac23bbee2 100644 (file)
@@ -608,7 +608,7 @@ class RequestHandler:
             return _unicode(value)
         except UnicodeDecodeError:
             raise HTTPError(
-                400, "Invalid unicode in %s: %r" % (name or "url", value[:40])
+                400, "Invalid unicode in {}: {!r}".format(name or "url", value[:40])
             )
 
     @property
@@ -671,7 +671,7 @@ class RequestHandler:
         value = escape.native_str(value)
         if re.search(r"[\x00-\x20]", name + value):
             # Don't let us accidentally inject bad stuff
-            raise ValueError("Invalid cookie %r: %r" % (name, value))
+            raise ValueError(f"Invalid cookie {name!r}: {value!r}")
         if not hasattr(self, "_new_cookie"):
             self._new_cookie = (
                 http.cookies.SimpleCookie()
@@ -1859,7 +1859,7 @@ class RequestHandler:
         self.application.log_request(self)
 
     def _request_summary(self) -> str:
-        return "%s %s (%s)" % (
+        return "{} {} ({})".format(
             self.request.method,
             self.request.uri,
             self.request.remote_ip,
@@ -2758,7 +2758,7 @@ class StaticFileHandler(RequestHandler):
                 # and less than the first-byte-pos.
                 self.set_status(416)  # Range Not Satisfiable
                 self.set_header("Content-Type", "text/plain")
-                self.set_header("Content-Range", "bytes */%s" % (size,))
+                self.set_header("Content-Range", f"bytes */{size}")
                 return
             if end is not None and end > size:
                 # Clients sometimes blindly use a large range to limit their
@@ -2812,7 +2812,7 @@ class StaticFileHandler(RequestHandler):
         version_hash = self._get_cached_version(self.absolute_path)
         if not version_hash:
             return None
-        return '"%s"' % (version_hash,)
+        return f'"{version_hash}"'
 
     def set_headers(self) -> None:
         """Sets the content and caching headers on the response.
@@ -3111,7 +3111,7 @@ class StaticFileHandler(RequestHandler):
         if not version_hash:
             return url
 
-        return "%s?v=%s" % (url, version_hash)
+        return f"{url}?v={version_hash}"
 
     def parse_url_path(self, url_path: str) -> str:
         """Converts a static URL path into a filesystem path.