From f7818e799a0fc72e136b93d34c94eda2e127a88c Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Thu, 13 Jun 2024 15:25:50 -0400 Subject: [PATCH] *: Switch from percent formatting to f-strings 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. --- demos/webspider/webspider.py | 2 +- tornado/auth.py | 8 ++------ tornado/escape.py | 2 +- tornado/gen.py | 2 +- tornado/http1connection.py | 2 +- tornado/httpclient.py | 2 +- tornado/httputil.py | 10 +++++----- tornado/locale.py | 6 +++--- tornado/locks.py | 14 ++++++-------- tornado/log.py | 2 +- tornado/queues.py | 6 +++--- tornado/routing.py | 4 ++-- tornado/simple_httpclient.py | 8 ++++---- tornado/template.py | 10 ++++------ tornado/test/curl_httpclient_test.py | 12 ++++-------- tornado/test/gen_test.py | 2 +- tornado/test/httpclient_test.py | 4 ++-- tornado/test/httpserver_test.py | 2 +- tornado/test/simple_httpclient_test.py | 2 +- tornado/test/web_test.py | 16 ++++++++-------- tornado/testing.py | 2 +- tornado/web.py | 12 ++++++------ 22 files changed, 59 insertions(+), 71 deletions(-) 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.