Merge pull request #379 from Pylons/enhancement/pyupgrade-3.7

Run pyupgrade --py37-plus
diff --git a/src/waitress/adjustments.py b/src/waitress/adjustments.py
index 6e9b702..e08d75d 100644
--- a/src/waitress/adjustments.py
+++ b/src/waitress/adjustments.py
@@ -143,7 +143,7 @@
     # TCP port to listen on
     port = _int_marker(8080)
 
-    listen = ["{}:{}".format(host, port)]
+    listen = [f"{host}:{port}"]
 
     # number of threads available for tasks
     threads = 4
@@ -322,7 +322,7 @@
         if not isinstance(self.host, _str_marker) or not isinstance(
             self.port, _int_marker
         ):
-            self.listen = ["{}:{}".format(self.host, self.port)]
+            self.listen = [f"{self.host}:{self.port}"]
 
         enabled_families = socket.AF_UNSPEC
 
diff --git a/src/waitress/proxy_headers.py b/src/waitress/proxy_headers.py
index 5d61646..652ca0b 100644
--- a/src/waitress/proxy_headers.py
+++ b/src/waitress/proxy_headers.py
@@ -52,7 +52,7 @@
                     ex.reason,
                     ex.value,
                 )
-                error = BadRequest('Header "{}" malformed.'.format(ex.header))
+                error = BadRequest(f'Header "{ex.header}" malformed.')
                 return error.wsgi_response(environ, start_response)
 
         # Clear out the untrusted proxy headers
@@ -95,7 +95,7 @@
                 if "." not in forward_hop and (
                     ":" in forward_hop and forward_hop[-1] != "]"
                 ):
-                    forwarded_for.append("[{}]".format(forward_hop))
+                    forwarded_for.append(f"[{forward_hop}]")
                 else:
                     forwarded_for.append(forward_hop)
 
diff --git a/src/waitress/runner.py b/src/waitress/runner.py
index 9a5f0e3..22f70f3 100644
--- a/src/waitress/runner.py
+++ b/src/waitress/runner.py
@@ -198,7 +198,7 @@
 def match(obj_name):
     matches = RUNNER_PATTERN.match(obj_name)
     if not matches:
-        raise ValueError("Malformed application '{}'".format(obj_name))
+        raise ValueError(f"Malformed application '{obj_name}'")
     return matches.group("module"), matches.group("object")
 
 
@@ -223,7 +223,7 @@
 
 def show_help(stream, name, error=None):  # pragma: no cover
     if error is not None:
-        print("Error: {}\n".format(error), file=stream)
+        print(f"Error: {error}\n", file=stream)
     print(HELP.format(name), file=stream)
 
 
@@ -239,7 +239,7 @@
     if args:
         print("It had these arguments: ", file=stream)
         for idx, arg in enumerate(args, start=1):
-            print("{}. {}\n".format(idx, arg), file=stream)
+            print(f"{idx}. {arg}\n", file=stream)
     else:
         print("It had no arguments.", file=stream)
 
@@ -282,11 +282,11 @@
     try:
         app = resolve(module, obj_name)
     except ImportError:
-        show_help(sys.stderr, name, "Bad module '{}'".format(module))
+        show_help(sys.stderr, name, f"Bad module '{module}'")
         show_exception(sys.stderr)
         return 1
     except AttributeError:
-        show_help(sys.stderr, name, "Bad object name '{}'".format(obj_name))
+        show_help(sys.stderr, name, f"Bad object name '{obj_name}'")
         show_exception(sys.stderr)
         return 1
     if kw["call"]:
diff --git a/src/waitress/server.py b/src/waitress/server.py
index 55cffe9..0a0f876 100644
--- a/src/waitress/server.py
+++ b/src/waitress/server.py
@@ -157,7 +157,7 @@
             l = list(l)
 
             if ":" in l[0]:
-                l[0] = "[{}]".format(l[0])
+                l[0] = f"[{l[0]}]"
 
             self.log_info(format_str.format(*l))
 
diff --git a/src/waitress/task.py b/src/waitress/task.py
index 3bc7f7c..574532f 100644
--- a/src/waitress/task.py
+++ b/src/waitress/task.py
@@ -57,7 +57,7 @@
 
     def start_new_thread(self, target, thread_no):
         t = threading.Thread(
-            target=target, name="waitress-{}".format(thread_no), args=(thread_no,)
+            target=target, name=f"waitress-{thread_no}", args=(thread_no,)
         )
         t.daemon = True
         t.start()
@@ -266,7 +266,7 @@
 
         self.response_headers = response_headers
 
-        first_line = "HTTP/%s %s" % (self.version, self.status)
+        first_line = f"HTTP/{self.version} {self.status}"
         # NB: sorting headers needs to preserve same-named-header order
         # as per RFC 2616 section 4.2; thus the key=lambda x: x[0] here;
         # rely on stable sort to keep relative position of same-named headers
@@ -400,11 +400,11 @@
             for k, v in headers:
                 if not k.__class__ is str:
                     raise AssertionError(
-                        "Header name %r is not a string in %r" % (k, (k, v))
+                        f"Header name {k!r} is not a string in {(k, v)!r}"
                     )
                 if not v.__class__ is str:
                     raise AssertionError(
-                        "Header value %r is not a string in %r" % (v, (k, v))
+                        f"Header value {v!r} is not a string in {(k, v)!r}"
                     )
 
                 if "\n" in v or "\r" in v:
diff --git a/src/waitress/trigger.py b/src/waitress/trigger.py
index 49b2034..73ac31c 100644
--- a/src/waitress/trigger.py
+++ b/src/waitress/trigger.py
@@ -106,9 +106,7 @@
                     thunk()
                 except:
                     nil, t, v, tbinfo = wasyncore.compact_traceback()
-                    self.log_info(
-                        "exception in trigger thunk: (%s:%s %s)" % (t, v, tbinfo)
-                    )
+                    self.log_info(f"exception in trigger thunk: ({t}:{v} {tbinfo})")
             self.thunks = []
 
 
diff --git a/src/waitress/utilities.py b/src/waitress/utilities.py
index a9d3361..164752f 100644
--- a/src/waitress/utilities.py
+++ b/src/waitress/utilities.py
@@ -259,8 +259,8 @@
         self.body = body
 
     def to_response(self):
-        status = "%s %s" % (self.code, self.reason)
-        body = "%s\r\n\r\n%s" % (self.reason, self.body)
+        status = f"{self.code} {self.reason}"
+        body = f"{self.reason}\r\n\r\n{self.body}"
         tag = "\r\n\r\n(generated by waitress)"
         body = (body + tag).encode("utf-8")
         headers = [("Content-Type", "text/plain; charset=utf-8")]
diff --git a/src/waitress/wasyncore.py b/src/waitress/wasyncore.py
index 9a68c51..a879608 100644
--- a/src/waitress/wasyncore.py
+++ b/src/waitress/wasyncore.py
@@ -328,7 +328,7 @@
                 status.append("%s:%d" % self.addr)
             except TypeError:  # pragma: no cover
                 status.append(repr(self.addr))
-        return "<%s at %#x>" % (" ".join(status), id(self))
+        return "<{} at {:#x}>".format(" ".join(status), id(self))
 
     __str__ = __repr__
 
diff --git a/tests/test_wasyncore.py b/tests/test_wasyncore.py
index 5e0559f..e833c7e 100644
--- a/tests/test_wasyncore.py
+++ b/tests/test_wasyncore.py
@@ -31,7 +31,7 @@
 else:
     TESTFN = "@test"
 
-TESTFN = "{}_{}_tmp".format(TESTFN, os.getpid())
+TESTFN = f"{TESTFN}_{os.getpid()}_tmp"
 
 
 class DummyLogger:  # pragma: no cover
@@ -574,7 +574,7 @@
         self.assertEqual(function, "test_compact_traceback")
         self.assertEqual(t, real_t)
         self.assertEqual(v, real_v)
-        self.assertEqual(info, "[%s|%s|%s]" % (f, function, line))
+        self.assertEqual(info, f"[{f}|{function}|{line}]")
 
 
 class DispatcherTests(unittest.TestCase):