diff --git a/demos/webspider/webspider.py b/demos/webspider/webspider.py
index d7757917..0c62a70f 100755
--- a/demos/webspider/webspider.py
+++ b/demos/webspider/webspider.py
@@ -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()
diff --git a/tornado/auth.py b/tornado/auth.py
index 035d34b0..64428c59 100644
--- a/tornado/auth.py
+++ b/tornado/auth.py
@@ -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)
diff --git a/tornado/escape.py b/tornado/escape.py
index 023ee16a..8515bf58 100644
--- a/tornado/escape.py
+++ b/tornado/escape.py
@@ -392,7 +392,7 @@ def linkify(
# have a status bar, such as Safari by default)
params += ' title="%s"' % href
- return '%s' % (href, params, url)
+ return f'{url}'
# First HTML-escape so that our strings are all safe.
# The regex is modified to avoid character entites other than & so
diff --git a/tornado/gen.py b/tornado/gen.py
index c824c9ff..51fa4c19 100644
--- a/tornado/gen.py
+++ b/tornado/gen.py
@@ -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)
diff --git a/tornado/http1connection.py b/tornado/http1connection.py
index 53cfca96..8dd0c9b6 100644
--- a/tornado/http1connection.py
+++ b/tornado/http1connection.py
@@ -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.
diff --git a/tornado/httpclient.py b/tornado/httpclient.py
index 1fc04c64..3a45ffd0 100644
--- a/tornado/httpclient.py
+++ b/tornado/httpclient.py
@@ -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):
diff --git a/tornado/httputil.py b/tornado/httputil.py
index bffb7bd0..4ec7b68f 100644
--- a/tornado/httputil.py
+++ b/tornado/httputil.py
@@ -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)
diff --git a/tornado/locale.py b/tornado/locale.py
index 3fb1a686..abd8668c 100644
--- a/tornado/locale.py
+++ b/tornado/locale.py
@@ -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
diff --git a/tornado/locks.py b/tornado/locks.py
index 6d794687..9ee1f2f0 100644
--- a/tornado/locks.py
+++ b/tornado/locks.py
@@ -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
diff --git a/tornado/log.py b/tornado/log.py
index 86998961..f5ca5c0c 100644
--- a/tornado/log.py
+++ b/tornado/log.py
@@ -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))
diff --git a/tornado/queues.py b/tornado/queues.py
index 1358d0ec..95526333 100644
--- a/tornado/queues.py
+++ b/tornado/queues.py
@@ -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:
diff --git a/tornado/routing.py b/tornado/routing.py
index 324818eb..ee81f977 100644
--- a/tornado/routing.py
+++ b/tornado/routing.py
@@ -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,
diff --git a/tornado/simple_httpclient.py b/tornado/simple_httpclient.py
index 79fe292d..cc163761 100644
--- a/tornado/simple_httpclient.py
+++ b/tornado/simple_httpclient.py
@@ -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:
diff --git a/tornado/template.py b/tornado/template.py
index 921545cc..0064c6fb 100644
--- a/tornado/template.py
+++ b/tornado/template.py
@@ -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
diff --git a/tornado/test/curl_httpclient_test.py b/tornado/test/curl_httpclient_test.py
index 99af2933..ce3f68d7 100644
--- a/tornado/test/curl_httpclient_test.py
+++ b/tornado/test/curl_httpclient_test.py
@@ -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}"',
)
diff --git a/tornado/test/gen_test.py b/tornado/test/gen_test.py
index 3190ef40..87f6ab7f 100644
--- a/tornado/test/gen_test.py
+++ b/tornado/test/gen_test.py
@@ -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")
diff --git a/tornado/test/httpclient_test.py b/tornado/test/httpclient_test.py
index 1eb758b5..40a29d0b 100644
--- a/tornado/test/httpclient_test.py
+++ b/tornado/test/httpclient_test.py
@@ -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)
diff --git a/tornado/test/httpserver_test.py b/tornado/test/httpserver_test.py
index 85755405..5657f629 100644
--- a/tornado/test/httpserver_test.py
+++ b/tornado/test/httpserver_test.py
@@ -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):
diff --git a/tornado/test/simple_httpclient_test.py b/tornado/test/simple_httpclient_test.py
index bcb1aaba..3bb66187 100644
--- a/tornado/test/simple_httpclient_test.py
+++ b/tornado/test/simple_httpclient_test.py
@@ -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):
diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py
index ac55aa39..32a12bad 100644
--- a/tornado/test/web_test.py
+++ b/tornado/test/web_test.py
@@ -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:
diff --git a/tornado/testing.py b/tornado/testing.py
index 4064873d..a397e3fa 100644
--- a/tornado/testing.py
+++ b/tornado/testing.py
@@ -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()
diff --git a/tornado/web.py b/tornado/web.py
index aa64145e..3514760e 100644
--- a/tornado/web.py
+++ b/tornado/web.py
@@ -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.