From 1d7e589968a236873602c322aaa0f42c27bd9210 Mon Sep 17 00:00:00 2001
From: Asher Foa <asher@asherfoa.com>
Date: Sun, 24 Nov 2019 15:59:03 -0800
Subject: [PATCH] Convert `contrib/node` and `contrib/go` to use f-strings.
 (#8699)

Co-Authored-By: Eric Arellano <ericarellano@me.com>
---
 .../pants/contrib/go/subsystems/archive_retriever.py   |  6 +++---
 .../python/pants/contrib/go/subsystems/fetch_error.py  |  2 +-
 .../src/python/pants/contrib/go/subsystems/fetcher.py  |  8 ++++----
 .../contrib/go/subsystems/go_import_meta_tag_reader.py |  2 +-
 .../pants/contrib/go/subsystems/protoc_gen_go.py       |  4 ++--
 .../src/python/pants/contrib/go/targets/go_target.py   |  4 ++--
 .../src/python/pants/contrib/go/tasks/go_buildgen.py   |  9 ++++-----
 .../go/src/python/pants/contrib/go/tasks/go_compile.py |  8 ++++----
 .../go/src/python/pants/contrib/go/tasks/go_fetch.py   |  6 +++---
 .../python/pants/contrib/go/tasks/go_fmt_task_base.py  |  2 +-
 contrib/go/src/python/pants/contrib/go/tasks/go_go.py  |  4 ++--
 .../python/pants/contrib/go/tasks/go_protobuf_gen.py   |  8 ++++----
 contrib/go/src/python/pants/contrib/go/tasks/go_run.py |  3 +--
 .../go/src/python/pants/contrib/go/tasks/go_task.py    |  5 ++---
 .../go/src/python/pants/contrib/go/tasks/go_test.py    |  4 ++--
 .../src/python/pants/contrib/go/tasks/go_thrift_gen.py |  8 ++++----
 .../contrib/go/targets/go_local_source_test_base.py    |  4 ++--
 .../contrib/go/tasks/test_go_binary_create.py          |  2 +-
 .../pants_test/contrib/go/tasks/test_go_fetch.py       |  6 +++---
 .../python/pants/contrib/node/subsystems/command.py    |  2 +-
 .../pants/contrib/node/subsystems/package_managers.py  | 10 +++++-----
 .../contrib/node/subsystems/resolvers/npm_resolver.py  | 10 +++++-----
 .../pants/contrib/node/tasks/javascript_style.py       | 10 +++++-----
 .../src/python/pants/contrib/node/tasks/node_bundle.py |  4 ++--
 .../src/python/pants/contrib/node/tasks/node_test.py   |  2 +-
 .../pants_test/contrib/node/tasks/test_node_bundle.py  |  2 +-
 .../contrib/node/tasks/test_node_resolve_src_deps.py   |  4 ++--
 .../pants_test/contrib/node/tasks/test_node_task.py    |  4 ++--
 28 files changed, 70 insertions(+), 73 deletions(-)

diff --git a/contrib/go/src/python/pants/contrib/go/subsystems/archive_retriever.py b/contrib/go/src/python/pants/contrib/go/subsystems/archive_retriever.py
index 4f4375211a1..8336a8442ad 100644
--- a/contrib/go/src/python/pants/contrib/go/subsystems/archive_retriever.py
+++ b/contrib/go/src/python/pants/contrib/go/subsystems/archive_retriever.py
@@ -37,7 +37,7 @@ def fetch_archive(self, archive_url, strip_level, dest):
     try:
       archiver = archiver_for_path(archive_url)
     except ValueError:
-      raise FetchError("Don't know how to unpack archive at url {}".format(archive_url))
+      raise FetchError(f"Don't know how to unpack archive at url {archive_url}")
 
     with self._fetch(archive_url) as archive:
       if strip_level == 0:
@@ -68,10 +68,10 @@ def _fetch(self, url):
   @contextmanager
   def _download(self, url):
     # TODO(jsirois): Wrap with workunits, progress meters, checksums.
-    logger.info('Downloading {}...'.format(url))
+    logger.info(f'Downloading {url}...')
     with closing(self._session().get(url, stream=True)) as res:
       if res.status_code != requests.codes.ok:
-        raise FetchError('Failed to download {} ({} error)'.format(url, res.status_code))
+        raise FetchError(f'Failed to download {url} ({res.status_code} error)')
       with temporary_file() as archive_fp:
         # NB: Archives might be very large so we play it safe and buffer them to disk instead of
         # memory before unpacking.
diff --git a/contrib/go/src/python/pants/contrib/go/subsystems/fetch_error.py b/contrib/go/src/python/pants/contrib/go/subsystems/fetch_error.py
index 24974d42588..53e6d867f80 100644
--- a/contrib/go/src/python/pants/contrib/go/subsystems/fetch_error.py
+++ b/contrib/go/src/python/pants/contrib/go/subsystems/fetch_error.py
@@ -7,4 +7,4 @@ class FetchError(Exception):
 
   def add_message_prefix(self, prefix):
     # Note: Assumes that this object was created with a single string argument.
-    self.args = ('{}{}'.format(prefix, self.args[0]), )
+    self.args = (f'{prefix}{self.args[0]}', )
diff --git a/contrib/go/src/python/pants/contrib/go/subsystems/fetcher.py b/contrib/go/src/python/pants/contrib/go/subsystems/fetcher.py
index a57ecaca909..5ca2ec3295b 100644
--- a/contrib/go/src/python/pants/contrib/go/subsystems/fetcher.py
+++ b/contrib/go/src/python/pants/contrib/go/subsystems/fetcher.py
@@ -77,7 +77,7 @@ def root(self):
     if imported_repo:
       return imported_repo.import_prefix
     else:
-      raise FetchError('No <meta name="go-import"> tag found at {}'.format(self.import_path))
+      raise FetchError(f'No <meta name="go-import"> tag found at {self.import_path}')
 
   def fetch(self, dest, rev=None):
     imported_repo = self._meta_tag_reader.get_imported_repo(self.import_path)
@@ -86,9 +86,9 @@ def fetch(self, dest, rev=None):
                        'at {}'.format(self.import_path))
     if imported_repo.vcs != 'git':
       # TODO: Support other vcs systems as needed.
-      raise FetchError("Don't know how to fetch for vcs type {}.".format(imported_repo.vcs))
+      raise FetchError(f"Don't know how to fetch for vcs type {imported_repo.vcs}.")
     # TODO: Do this in a workunit (see https://github.com/pantsbuild/pants/issues/3502).
-    logger.info('Cloning {} into {}'.format(imported_repo.url, dest))
+    logger.info(f'Cloning {imported_repo.url} into {dest}')
     repo = Git.clone(imported_repo.url, dest)
     if rev:
       repo.set_state(rev)
@@ -124,7 +124,7 @@ def fetch(self, dest, rev=None):
       self._fetch(archive_url, self._url_info.strip_level, dest)
     except FetchError as e:
       # Modify the message to add more information, then reraise with the original traceback.
-      e.add_message_prefix('Error while fetching import {}: '.format(self.import_path))
+      e.add_message_prefix(f'Error while fetching import {self.import_path}: ')
       raise
 
   def _fetch(self, archive_url, strip_level, dest):
diff --git a/contrib/go/src/python/pants/contrib/go/subsystems/go_import_meta_tag_reader.py b/contrib/go/src/python/pants/contrib/go/subsystems/go_import_meta_tag_reader.py
index 2a93b1aabe1..5b96397f15e 100644
--- a/contrib/go/src/python/pants/contrib/go/subsystems/go_import_meta_tag_reader.py
+++ b/contrib/go/src/python/pants/contrib/go/subsystems/go_import_meta_tag_reader.py
@@ -51,7 +51,7 @@ def get_imported_repo(self, import_path):
       # See https://github.com/pantsbuild/pants/issues/3503.
       session.mount("http://",
                     requests.adapters.HTTPAdapter(max_retries=self.get_options().retries))
-      page_data = session.get('http://{import_path}?go-get=1'.format(import_path=import_path))
+      page_data = session.get(f'http://{import_path}?go-get=1')
     except requests.ConnectionError:
       return None
 
diff --git a/contrib/go/src/python/pants/contrib/go/subsystems/protoc_gen_go.py b/contrib/go/src/python/pants/contrib/go/subsystems/protoc_gen_go.py
index 92a17444eed..5e18ce1fa7a 100644
--- a/contrib/go/src/python/pants/contrib/go/subsystems/protoc_gen_go.py
+++ b/contrib/go/src/python/pants/contrib/go/subsystems/protoc_gen_go.py
@@ -59,7 +59,7 @@ def select(self, context):
       )
 
       if result != 0:
-        raise SubsystemError('{} failed with exit code {}'.format(go_cmd, result))
+        raise SubsystemError(f'{go_cmd} failed with exit code {result}')
 
-    logger.info('Selected {} binary bootstrapped to: {}'.format(self.options_scope, tool_path))
+    logger.info(f'Selected {self.options_scope} binary bootstrapped to: {tool_path}')
     return tool_path
diff --git a/contrib/go/src/python/pants/contrib/go/targets/go_target.py b/contrib/go/src/python/pants/contrib/go/targets/go_target.py
index 4310b84f8b2..e6a02f29d6f 100644
--- a/contrib/go/src/python/pants/contrib/go/targets/go_target.py
+++ b/contrib/go/src/python/pants/contrib/go/targets/go_target.py
@@ -49,9 +49,9 @@ def normalize_package_path(cls, package_path):
     :raises: `ValueError` if the package path cannot be normalized.
     """
     if package_path.startswith(os.pardir + os.sep):
-      raise ValueError('Relative package paths are not allowed. Given: {!r}'.format(package_path))
+      raise ValueError(f'Relative package paths are not allowed. Given: {package_path!r}')
     if os.path.isabs(package_path):
-      raise ValueError('Absolute package paths are not allowed. Given: {!r}'.format(package_path))
+      raise ValueError(f'Absolute package paths are not allowed. Given: {package_path!r}')
     return '' if not package_path or package_path == os.curdir else package_path.lstrip('/')
 
   @property
diff --git a/contrib/go/src/python/pants/contrib/go/tasks/go_buildgen.py b/contrib/go/src/python/pants/contrib/go/tasks/go_buildgen.py
index 8c6b20866f8..99409687a68 100644
--- a/contrib/go/src/python/pants/contrib/go/tasks/go_buildgen.py
+++ b/contrib/go/src/python/pants/contrib/go/tasks/go_buildgen.py
@@ -82,7 +82,7 @@ def _generate_missing(self, gopath, local_address, import_listing, visited):
             except AddressLookupError:
               if not self._generate_remotes:
                 raise self.NewRemoteEncounteredButRemotesNotAllowedError(
-                  'Cannot generate dependency for remote import path {}'.format(import_path))
+                  f'Cannot generate dependency for remote import path {import_path}')
               self._build_graph.inject_synthetic_target(address=address,
                                                         target_type=GoRemoteLibrary,
                                                         pkg=remote_pkg_path)
@@ -219,7 +219,7 @@ def log(self, logger):
       :type logger: A :class:`logging.Logger` compatible object.
       """
       log = logger.info if self.local or self.rev else logger.warn
-      log('\t{}'.format(self))
+      log(f'\t{self}')
 
     @property
     def failed(self):
@@ -231,9 +231,8 @@ def failed(self):
 
     def __str__(self):
       import_paths = ' '.join(sorted(self.import_paths))
-      rev = '' if self.local else ' {}'.format(self.rev or 'FLOATING')
-      return ('{build_file_path} ({import_paths}){rev}'
-              .format(build_file_path=self.build_file_path, import_paths=import_paths, rev=rev))
+      rev = '' if self.local else f" {self.rev or 'FLOATING'}"
+      return (f'{self.build_file_path} ({import_paths}){rev}')
 
   class FloatingRemoteError(TaskError):
     """Indicates Go remote libraries exist or were generated that don't specify a `rev`."""
diff --git a/contrib/go/src/python/pants/contrib/go/tasks/go_compile.py b/contrib/go/src/python/pants/contrib/go/tasks/go_compile.py
index aea0fa33b6b..ee061bb5e54 100644
--- a/contrib/go/src/python/pants/contrib/go/tasks/go_compile.py
+++ b/contrib/go/src/python/pants/contrib/go/tasks/go_compile.py
@@ -99,10 +99,10 @@ def _go_install(self, target, gopath, build_flags):
     result, go_cmd = self.go_dist.execute_go_cmd(
       'install', gopath=gopath, args=args,
       workunit_factory=self.context.new_workunit,
-      workunit_name='install {}'.format(target.import_path),
+      workunit_name=f'install {target.import_path}',
       workunit_labels=[WorkUnitLabel.COMPILER])
     if result != 0:
-      raise TaskError('{} failed with exit code {}'.format(go_cmd, result))
+      raise TaskError(f'{go_cmd} failed with exit code {result}')
 
   def _sync_binary_dep_links(self, target, gopath, lib_binary_map):
     """Syncs symlinks under gopath to the library binaries of target's transitive dependencies.
@@ -149,8 +149,8 @@ def _get_cross_compiling_subdir_and_extension(self, gopath):
     host_arch = self.go_dist.create_go_cmd('env', gopath=gopath, args=["GOARCH"]).check_output().decode().strip()
     target_arch = self.go_dist.create_go_cmd('env', gopath=gopath, args=["GOHOSTARCH"]).check_output().decode().strip()
 
-    host_pair = "{}_{}".format(host_goos, host_arch)
-    target_pair = "{}_{}".format(target_goos, target_arch)
+    host_pair = f"{host_goos}_{host_arch}"
+    target_pair = f"{target_goos}_{target_arch}"
 
     ext = ".exe" if target_goos == "windows" else ""
 
diff --git a/contrib/go/src/python/pants/contrib/go/tasks/go_fetch.py b/contrib/go/src/python/pants/contrib/go/tasks/go_fetch.py
index 5b16208937c..d15a22dcb79 100644
--- a/contrib/go/src/python/pants/contrib/go/tasks/go_fetch.py
+++ b/contrib/go/src/python/pants/contrib/go/tasks/go_fetch.py
@@ -73,7 +73,7 @@ def _fetch_pkg(self, gopath, pkg, rev):
     # Only fetch each remote root once.
     if not os.path.exists(root_dir):
       with temporary_dir() as tmp_fetch_root:
-        with self.context.new_workunit('fetch {}'.format(pkg)):
+        with self.context.new_workunit(f'fetch {pkg}'):
           fetcher.fetch(dest=tmp_fetch_root, rev=rev)
           safe_mkdir(root_dir)
           for path in os.listdir(tmp_fetch_root):
@@ -108,7 +108,7 @@ def _map_fetched_remote_source(self, go_remote_lib, gopath, all_known_remote_lib
       with safe_concurrent_creation(remote_import_paths_cache) as safe_path:
         with open(safe_path, 'w') as fp:
           for path in remote_import_paths:
-            fp.write('{}\n'.format(path))
+            fp.write(f'{path}\n')
 
     for remote_import_path in remote_import_paths:
       remote_root = import_root_map.get(remote_import_path)
@@ -277,4 +277,4 @@ def _write_import_root_map_file(path, import_root_map):
     with safe_concurrent_creation(path) as safe_path:
       with open(safe_path, 'w') as fp:
         for import_path, root in sorted(import_root_map.items()):
-          fp.write('{}\t{}\n'.format(import_path, root))
+          fp.write(f'{import_path}\t{root}\n')
diff --git a/contrib/go/src/python/pants/contrib/go/tasks/go_fmt_task_base.py b/contrib/go/src/python/pants/contrib/go/tasks/go_fmt_task_base.py
index 588c2cedaa8..642db39814f 100644
--- a/contrib/go/src/python/pants/contrib/go/tasks/go_fmt_task_base.py
+++ b/contrib/go/src/python/pants/contrib/go/tasks/go_fmt_task_base.py
@@ -37,7 +37,7 @@ def go_fmt_invalid_targets(self, flags):
         try:
           output = subprocess.check_output(args).decode()
         except subprocess.CalledProcessError as e:
-          raise TaskError('{} failed with exit code {}'.format(' '.join(args), e.returncode),
+          raise TaskError(f"{' '.join(args)} failed with exit code {e.returncode}",
                           exit_code=e.returncode)
         yield output
       else:
diff --git a/contrib/go/src/python/pants/contrib/go/tasks/go_go.py b/contrib/go/src/python/pants/contrib/go/tasks/go_go.py
index e796db05ab6..29846c6df35 100644
--- a/contrib/go/src/python/pants/contrib/go/tasks/go_go.py
+++ b/contrib/go/src/python/pants/contrib/go/tasks/go_go.py
@@ -66,7 +66,7 @@ def execute_with_go_env(self, go_path, import_paths, args, **kwargs):
     process = subprocess.Popen(cmd, shell=True, env=env, **kwargs)
     result = process.wait()
     if result != 0:
-      raise TaskError('{} failed with exit code {}'.format(cmd, result), exit_code=result)
+      raise TaskError(f'{cmd} failed with exit code {result}', exit_code=result)
 
 
 class GoGo(GoInteropTask):
@@ -78,4 +78,4 @@ def execute_with_go_env(self, go_path, import_paths, args, **kwargs):
     go_cmd = self.go_dist.create_go_cmd(gopath=go_path, cmd=cmd, args=args)
     result = go_cmd.spawn(**kwargs).wait()
     if result != 0:
-      raise TaskError('{} failed with exit code {}'.format(go_cmd, result), exit_code=result)
+      raise TaskError(f'{go_cmd} failed with exit code {result}', exit_code=result)
diff --git a/contrib/go/src/python/pants/contrib/go/tasks/go_protobuf_gen.py b/contrib/go/src/python/pants/contrib/go/tasks/go_protobuf_gen.py
index cd899fd323e..2a921311774 100644
--- a/contrib/go/src/python/pants/contrib/go/tasks/go_protobuf_gen.py
+++ b/contrib/go/src/python/pants/contrib/go/tasks/go_protobuf_gen.py
@@ -69,16 +69,16 @@ def execute_codegen(self, target, target_workdir):
 
     bases = OrderedSet(tgt.target_base for tgt in target.closure() if self.is_gentarget(tgt))
     for base in bases:
-      target_cmd.append('-I={}'.format(os.path.join(get_buildroot(), base)))
+      target_cmd.append(f'-I={os.path.join(get_buildroot(), base)}')
 
     outdir = os.path.join(target_workdir, 'src', 'go')
     safe_mkdir(outdir)
     protoc_plugins = self.get_options().protoc_plugins + list(target.protoc_plugins)
     if protoc_plugins:
-      go_out = 'plugins={}:{}'.format('+'.join(protoc_plugins), outdir)
+      go_out = f"plugins={'+'.join(protoc_plugins)}:{outdir}"
     else:
       go_out = outdir
-    target_cmd.append('--go_out={}'.format(go_out))
+    target_cmd.append(f'--go_out={go_out}')
 
     all_sources = list(target.sources_relative_to_buildroot())
     for source in all_sources:
@@ -92,7 +92,7 @@ def execute_codegen(self, target, target_workdir):
                                  stdout=workunit.output('stdout'),
                                  stderr=workunit.output('stderr'))
         if result != 0:
-          raise TaskError('{} ... exited non-zero ({})'.format(self._protoc, result))
+          raise TaskError(f'{self._protoc} ... exited non-zero ({result})')
 
   @property
   def _copy_target_attributes(self):
diff --git a/contrib/go/src/python/pants/contrib/go/tasks/go_run.py b/contrib/go/src/python/pants/contrib/go/tasks/go_run.py
index c7968ac2ec0..d689d03bdcb 100644
--- a/contrib/go/src/python/pants/contrib/go/tasks/go_run.py
+++ b/contrib/go/src/python/pants/contrib/go/tasks/go_run.py
@@ -28,5 +28,4 @@ def execute(self):
       # TODO(cgibb): Wrap with workunit and stdout/stderr plumbing.
       res = Xargs.subprocess([binary_path]).execute(self.get_passthru_args())
       if res != 0:
-        raise TaskError('{bin} exited non-zero ({res})'
-                        .format(bin=os.path.basename(binary_path), res=res))
+        raise TaskError(f'{os.path.basename(binary_path)} exited non-zero ({res})')
diff --git a/contrib/go/src/python/pants/contrib/go/tasks/go_task.py b/contrib/go/src/python/pants/contrib/go/tasks/go_task.py
index d8b0919ee42..5feff172027 100644
--- a/contrib/go/src/python/pants/contrib/go/tasks/go_task.py
+++ b/contrib/go/src/python/pants/contrib/go/tasks/go_task.py
@@ -69,8 +69,7 @@ def goos_goarch(self):
 
     :rtype: string
     """
-    return '{goos}_{goarch}'.format(goos=self._lookup_go_env_var('GOOS'),
-                                    goarch=self._lookup_go_env_var('GOARCH'))
+    return f"{self._lookup_go_env_var('GOOS')}_{self._lookup_go_env_var('GOARCH')}"
 
   def _lookup_go_env_var(self, var):
     return self.go_dist.create_go_cmd('env', args=[var]).check_output().decode().strip()
@@ -143,7 +142,7 @@ def list_imports(self, pkg, gopath=None):
              of `pkg`.
     """
     go_cmd = self._go_dist.create_go_cmd('list', args=['-json', pkg], gopath=gopath)
-    with self._workunit_factory('list {}'.format(pkg), cmd=str(go_cmd),
+    with self._workunit_factory(f'list {pkg}', cmd=str(go_cmd),
                                 labels=[WorkUnitLabel.TOOL]) as workunit:
       # TODO(John Sirois): It would be nice to be able to tee the stdout to the workunit to we have
       # a capture of the json available for inspection in the server console.
diff --git a/contrib/go/src/python/pants/contrib/go/tasks/go_test.py b/contrib/go/src/python/pants/contrib/go/tasks/go_test.py
index 699e6ae4049..2b96e1113cb 100644
--- a/contrib/go/src/python/pants/contrib/go/tasks/go_test.py
+++ b/contrib/go/src/python/pants/contrib/go/tasks/go_test.py
@@ -100,7 +100,7 @@ def _maybe_workdir(self):
     return get_buildroot()
 
   def run_tests(self, fail_fast, test_targets, args_by_target):
-    self.context.log.debug('test_targets: {}'.format(test_targets))
+    self.context.log.debug(f'test_targets: {test_targets}')
 
     with self.chroot(test_targets, self._maybe_workdir) as chroot:
       cmdline_args = self._build_and_test_flags + [
@@ -111,7 +111,7 @@ def run_tests(self, fail_fast, test_targets, args_by_target):
       )
       go_cmd = self.go_dist.create_go_cmd('test', gopath=gopath, args=cmdline_args)
 
-      self.context.log.debug('go_cmd: {}'.format(go_cmd))
+      self.context.log.debug(f'go_cmd: {go_cmd}')
 
       workunit_labels = [WorkUnitLabel.TOOL, WorkUnitLabel.TEST]
       with self.context.new_workunit(
diff --git a/contrib/go/src/python/pants/contrib/go/tasks/go_thrift_gen.py b/contrib/go/src/python/pants/contrib/go/tasks/go_thrift_gen.py
index 811c1937077..6c2f920114a 100644
--- a/contrib/go/src/python/pants/contrib/go/tasks/go_thrift_gen.py
+++ b/contrib/go/src/python/pants/contrib/go/tasks/go_thrift_gen.py
@@ -111,15 +111,15 @@ def _validate_supports_more_than_one_source(self):
   @memoized_property
   def _thrift_cmd(self):
     cmd = [self._thrift_binary]
-    thrift_import = 'thrift_import={}'.format(self.get_options().thrift_import)
+    thrift_import = f'thrift_import={self.get_options().thrift_import}'
     if thrift_import is None:
-      raise TaskError('Option thrift_import in scope {} must be set.'.format(self.options_scope))
+      raise TaskError(f'Option thrift_import in scope {self.options_scope} must be set.')
     gen_options = self.get_options().gen_options
     if gen_options:
       gen_options += ',' + thrift_import
     else:
       gen_options = thrift_import
-    cmd.extend(('--gen', 'go:{}'.format(gen_options)))
+    cmd.extend(('--gen', f'go:{gen_options}'))
 
     if self.get_options().strict:
       cmd.append('-strict')
@@ -149,7 +149,7 @@ def _generate_thrift(self, target, target_workdir):
                                  stdout=workunit.output('stdout'),
                                  stderr=workunit.output('stderr'))
         if result != 0:
-          raise TaskError('{} ... exited non-zero ({})'.format(self._thrift_binary, result))
+          raise TaskError(f'{self._thrift_binary} ... exited non-zero ({result})')
 
     gen_dir = os.path.join(target_workdir, 'gen-go')
     src_dir = os.path.join(target_workdir, 'src')
diff --git a/contrib/go/tests/python/pants_test/contrib/go/targets/go_local_source_test_base.py b/contrib/go/tests/python/pants_test/contrib/go/targets/go_local_source_test_base.py
index 959b2f055ab..e2a64cf9533 100644
--- a/contrib/go/tests/python/pants_test/contrib/go/targets/go_local_source_test_base.py
+++ b/contrib/go/tests/python/pants_test/contrib/go/targets/go_local_source_test_base.py
@@ -87,7 +87,7 @@ def test_globs_cgo(self):
     self.create_file('src/go/src/foo/jake.hh')
     self.create_file('src/go/src/foo/jake.hpp')
     self.create_file('src/go/src/foo/jake.hxx')
-    self.add_to_build_file('src/go/src/foo', '{}()\n'.format(self.target_type.alias()))
+    self.add_to_build_file('src/go/src/foo', f'{self.target_type.alias()}()\n')
     target = self.target('src/go/src/foo')
 
     self.assertEqual(sorted(['foo/jake.go',
@@ -111,7 +111,7 @@ def test_globs_resources(self):
     # We should grab all of these though.
     self.create_file('src/go/src/foo/jake.go')
     self.create_file('src/go/src/foo/jake.png')
-    self.add_to_build_file('src/go/src/foo', '{}()'.format(self.target_type.alias()))
+    self.add_to_build_file('src/go/src/foo', f'{self.target_type.alias()}()')
     target = self.target('src/go/src/foo')
 
     self.assertEqual(sorted(['foo/jake.go',
diff --git a/contrib/go/tests/python/pants_test/contrib/go/tasks/test_go_binary_create.py b/contrib/go/tests/python/pants_test/contrib/go/tasks/test_go_binary_create.py
index cdbac09d937..9b06cbd36f2 100644
--- a/contrib/go/tests/python/pants_test/contrib/go/tasks/test_go_binary_create.py
+++ b/contrib/go/tests/python/pants_test/contrib/go/tasks/test_go_binary_create.py
@@ -32,7 +32,7 @@ def test_execute(self):
     with temporary_dir() as bin_source_dir:
       def create_binary(name):
         target = self.make_target(name, GoBinary)
-        executable = os.path.join(bin_source_dir, '{}.exe'.format(name))
+        executable = os.path.join(bin_source_dir, f'{name}.exe')
         touch(executable)
         return target, executable
 
diff --git a/contrib/go/tests/python/pants_test/contrib/go/tasks/test_go_fetch.py b/contrib/go/tests/python/pants_test/contrib/go/tasks/test_go_fetch.py
index e5e531263ef..5647cf5d5cb 100644
--- a/contrib/go/tests/python/pants_test/contrib/go/tasks/test_go_fetch.py
+++ b/contrib/go/tests/python/pants_test/contrib/go/tasks/test_go_fetch.py
@@ -72,7 +72,7 @@ def test_resolve_and_inject_implicit_already_exists(self):
 
   def _create_package(self, dirpath, name, deps):
     """Creates a Go package inside dirpath named 'name' importing deps."""
-    imports = ['import "localzip/{}"'.format(d) for d in deps]
+    imports = [f'import "localzip/{d}"' for d in deps]
     f = os.path.join(dirpath, '{name}/{name}.go'.format(name=name))
     self.create_file(f, contents=
       """package {name}
@@ -84,7 +84,7 @@ def _create_zip(self, src, dest, name):
     shutil.make_archive(os.path.join(dest, name), 'zip', root_dir=src)
 
   def _create_remote_lib(self, name):
-    self.make_target(spec='3rdparty/go/localzip/{name}'.format(name=name),
+    self.make_target(spec=f'3rdparty/go/localzip/{name}',
                      target_type=GoRemoteLibrary,
                      pkg=name)
 
@@ -113,7 +113,7 @@ def _assert_dependency_graph(self, root_target, dep_map):
     if root_target.name not in dep_map:
       return
 
-    expected_spec_paths = {'3rdparty/go/localzip/{}'.format(name)
+    expected_spec_paths = {f'3rdparty/go/localzip/{name}'
                            for name in dep_map[root_target.name]}
     actual_spec_paths = {dep.address.spec_path for dep in root_target.dependencies}
     self.assertEqual(actual_spec_paths, expected_spec_paths)
diff --git a/contrib/node/src/python/pants/contrib/node/subsystems/command.py b/contrib/node/src/python/pants/contrib/node/subsystems/command.py
index 7738f649866..91c4c007a35 100644
--- a/contrib/node/src/python/pants/contrib/node/subsystems/command.py
+++ b/contrib/node/src/python/pants/contrib/node/subsystems/command.py
@@ -48,7 +48,7 @@ def run(self, **kwargs):
     :rtype: :class:`subprocess.Popen`
     """
     env, kwargs = self._prepare_env(kwargs)
-    logger.debug('Running command {}'.format(self.cmd))
+    logger.debug(f'Running command {self.cmd}')
     return subprocess.Popen(self.cmd, env=env, **kwargs)
 
   def check_output(self, **kwargs):
diff --git a/contrib/node/src/python/pants/contrib/node/subsystems/package_managers.py b/contrib/node/src/python/pants/contrib/node/subsystems/package_managers.py
index 3ca83b70ee3..a2818235eea 100644
--- a/contrib/node/src/python/pants/contrib/node/subsystems/package_managers.py
+++ b/contrib/node/src/python/pants/contrib/node/subsystems/package_managers.py
@@ -176,7 +176,7 @@ def _get_add_package_args(self, package, type_option, version_option):
       PackageInstallationTypeOption.NO_SAVE: None,
     }.get(type_option)
     if package_type_option is None:
-      LOG.warning('{} does not support {} packages, ignored.'.format(self.name, type_option))
+      LOG.warning(f'{self.name} does not support {type_option} packages, ignored.')
     elif package_type_option:  # Skip over '' entries
       return_args.append(package_type_option)
     package_version_option = {
@@ -185,7 +185,7 @@ def _get_add_package_args(self, package, type_option, version_option):
     }.get(version_option)
     if package_version_option is None:
       LOG.warning(
-        '{} does not support install with {} version, ignored'.format(self.name, version_option))
+        f'{self.name} does not support install with {version_option} version, ignored')
     elif package_version_option: # Skip over '' entries
       return_args.append(package_version_option)
     return return_args
@@ -208,7 +208,7 @@ def _get_installation_args(self, install_optional, production_only, force, froze
     if force:
       return_args.append('--force')
     if frozen_lockfile:
-      LOG.warning('{} does not support frozen lockfile option. Ignored.'.format(self.name))
+      LOG.warning(f'{self.name} does not support frozen lockfile option. Ignored.')
     return return_args
 
   def _get_add_package_args(self, package, type_option, version_option):
@@ -222,7 +222,7 @@ def _get_add_package_args(self, package, type_option, version_option):
       PackageInstallationTypeOption.NO_SAVE: '--no-save',
     }.get(type_option)
     if package_type_option is None:
-      LOG.warning('{} does not support {} packages, ignored.'.format(self.name, type_option))
+      LOG.warning(f'{self.name} does not support {type_option} packages, ignored.')
     elif package_type_option:  # Skip over '' entries
       return_args.append(package_type_option)
     package_version_option = {
@@ -231,7 +231,7 @@ def _get_add_package_args(self, package, type_option, version_option):
     }.get(version_option)
     if package_version_option is None:
       LOG.warning(
-        '{} does not support install with {} version, ignored.'.format(self.name, version_option))
+        f'{self.name} does not support install with {version_option} version, ignored.')
     elif package_version_option:  # Skip over '' entries
       return_args.append(package_version_option)
     return return_args
diff --git a/contrib/node/src/python/pants/contrib/node/subsystems/resolvers/npm_resolver.py b/contrib/node/src/python/pants/contrib/node/subsystems/resolvers/npm_resolver.py
index f7d71986189..d4e80a26449 100644
--- a/contrib/node/src/python/pants/contrib/node/subsystems/resolvers/npm_resolver.py
+++ b/contrib/node/src/python/pants/contrib/node/subsystems/resolvers/npm_resolver.py
@@ -163,12 +163,12 @@ def _scoped_package_name(node_task, package_name, node_scope):
     scoped_package_name = package_name
     chunk = package_name.split('/', 1)
     if len(chunk) > 1 and chunk[0].startswith('@'):
-      scoped_package_name = os.path.join('@{}'.format(node_scope), chunk[1:])
+      scoped_package_name = os.path.join(f'@{node_scope}', chunk[1:])
     else:
-      scoped_package_name = os.path.join('@{}'.format(node_scope), package_name)
+      scoped_package_name = os.path.join(f'@{node_scope}', package_name)
 
     node_task.context.log.debug(
-      'Node package "{}" will be resolved with scope "{}".'.format(package_name, scoped_package_name))
+      f'Node package "{package_name}" will be resolved with scope "{scoped_package_name}".')
     return scoped_package_name
 
   @staticmethod
@@ -205,12 +205,12 @@ def _emit_package_descriptor(node_task, target, results_dir, node_paths):
       'dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'
     ]
     node_task.context.log.debug(
-      'Removing {} from package.json for {}'.format(dependencies_to_remove, package['name']))
+      f"Removing {dependencies_to_remove} from package.json for {package['name']}")
     for dependencyType in dependencies_to_remove:
       package.pop(dependencyType, None)
 
     node_task.context.log.debug(
-      'Adding {} to package.json for {}'.format(dependencies, package['name']))
+      f"Adding {dependencies} to package.json for {package['name']}")
     package['dependencies'] = dependencies
 
     with open(package_json_path, 'w') as fp:
diff --git a/contrib/node/src/python/pants/contrib/node/tasks/javascript_style.py b/contrib/node/src/python/pants/contrib/node/tasks/javascript_style.py
index 3a538f46350..e3c565aaf8d 100644
--- a/contrib/node/src/python/pants/contrib/node/tasks/javascript_style.py
+++ b/contrib/node/src/python/pants/contrib/node/tasks/javascript_style.py
@@ -57,7 +57,7 @@ def _is_javascriptstyle_dir_valid(javascriptstyle_dir):
     dir_exists = os.path.isdir(javascriptstyle_dir)
     if not dir_exists:
       raise TaskError(
-        'javascriptstyle package does not exist: {}.'.format(javascriptstyle_dir))
+        f'javascriptstyle package does not exist: {javascriptstyle_dir}.')
     else:
       lock_file = os.path.join(javascriptstyle_dir, 'yarn.lock')
       package_json = os.path.join(javascriptstyle_dir, 'package.json')
@@ -72,8 +72,8 @@ def _is_javascriptstyle_dir_valid(javascriptstyle_dir):
   def _bootstrap_eslinter(self, bootstrap_dir):
     with pushd(bootstrap_dir):
       eslint_version = self.node_distribution.eslint_version
-      eslint = 'eslint@{}'.format(eslint_version)
-      self.context.log.debug('Installing {}...'.format(eslint))
+      eslint = f'eslint@{eslint_version}'
+      self.context.log.debug(f'Installing {eslint}...')
       result, add_command = self.add_package(
         package=eslint,
         package_manager=self.node_distribution.get_package_manager(package_manager=PACKAGE_MANAGER_YARNPKG),
@@ -100,7 +100,7 @@ def _install_eslint(self, bootstrap_dir):
         raise TaskError('Failed to install ESLint\n'
                         '\t{} failed with exit code {}'.format(install_command, result))
 
-    self.context.log.debug('Successfully installed ESLint to {}'.format(bootstrap_dir))
+    self.context.log.debug(f'Successfully installed ESLint to {bootstrap_dir}')
     return bootstrap_dir
 
   def _get_target_ignore_patterns(self, target):
@@ -128,7 +128,7 @@ def _run_javascriptstyle(self, target, bootstrap_dir, files, config=None, ignore
     if ignore_patterns:
       # Wrap ignore-patterns in quotes to avoid conflict with shell glob pattern
       args.extend([arg for ignore_args in ignore_patterns
-                   for arg in ['--ignore-pattern', '{}'.format(ignore_args)]])
+                   for arg in ['--ignore-pattern', f'{ignore_args}']])
     if other_args:
       args.extend(other_args)
     args.extend(files)
diff --git a/contrib/node/src/python/pants/contrib/node/tasks/node_bundle.py b/contrib/node/src/python/pants/contrib/node/tasks/node_bundle.py
index abc82acce2f..a38dcccb08e 100644
--- a/contrib/node/src/python/pants/contrib/node/tasks/node_bundle.py
+++ b/contrib/node/src/python/pants/contrib/node/tasks/node_bundle.py
@@ -39,7 +39,7 @@ def execute(self):
             # build_dir is a symlink.  Since dereference option for tar is set to False, we need to
             # dereference manually to archive the linked build dir.
             build_dir = os.path.realpath(abs_path)
-            self.context.log.debug('archiving {}'.format(build_dir))
+            self.context.log.debug(f'archiving {build_dir}')
             archivepath = archiver.create(
               build_dir,
               self._outdir,
@@ -50,4 +50,4 @@ def execute(self):
             bundle_archive_product.add(
               target, os.path.dirname(archivepath)).append(os.path.basename(archivepath))
             self.context.log.info(
-              'created {}'.format(os.path.relpath(archivepath, get_buildroot())))
+              f'created {os.path.relpath(archivepath, get_buildroot())}')
diff --git a/contrib/node/src/python/pants/contrib/node/tasks/node_test.py b/contrib/node/src/python/pants/contrib/node/tasks/node_test.py
index 0e48b9ed05b..4b8ac8579e9 100644
--- a/contrib/node/src/python/pants/contrib/node/tasks/node_test.py
+++ b/contrib/node/src/python/pants/contrib/node/tasks/node_test.py
@@ -52,7 +52,7 @@ def _execute(self, all_targets):
     for target in targets:
       node_module = target.dependencies[0]
       self.context.log.debug(
-        'Testing node module (first dependency): {}'.format(node_module))
+        f'Testing node module (first dependency): {node_module}')
       with pushd(node_paths.node_path(node_module)):
         self._currently_executing_test_targets = [target]
         result, test_command = self.run_script(
diff --git a/contrib/node/tests/python/pants_test/contrib/node/tasks/test_node_bundle.py b/contrib/node/tests/python/pants_test/contrib/node/tasks/test_node_bundle.py
index 389d9b9ba73..a8de06c3929 100644
--- a/contrib/node/tests/python/pants_test/contrib/node/tasks/test_node_bundle.py
+++ b/contrib/node/tests/python/pants_test/contrib/node/tasks/test_node_bundle.py
@@ -55,7 +55,7 @@ def test_node_deployable_bundle(self):
       product_data = product.get(target)
       self.assertIsNotNone(product_data)
       product_basedir = list(product_data.keys())[0]
-      self.assertEqual(product_data[product_basedir], ['{}.tar.gz'.format(self.target_name)])
+      self.assertEqual(product_data[product_basedir], [f'{self.target_name}.tar.gz'])
 
   def test_no_dependencies_for_node_bundle(self):
     with temporary_dir() as tmp_dir:
diff --git a/contrib/node/tests/python/pants_test/contrib/node/tasks/test_node_resolve_src_deps.py b/contrib/node/tests/python/pants_test/contrib/node/tasks/test_node_resolve_src_deps.py
index 47f772fa6d3..0c4951b9d67 100644
--- a/contrib/node/tests/python/pants_test/contrib/node/tasks/test_node_resolve_src_deps.py
+++ b/contrib/node/tests/python/pants_test/contrib/node/tasks/test_node_resolve_src_deps.py
@@ -81,7 +81,7 @@ def _create_dep(self, trans_dep=None, provide_bin=None, use_bin_dict=None, src_r
     if trans_dep:
       require_dep = 'trans_dep'
       if node_scope:
-        require_dep = os.path.join('@{}'.format(node_scope), require_dep)
+        require_dep = os.path.join(f'@{node_scope}', require_dep)
       self.create_file(os.path.join(src_root, 'dep/index.js'), contents=dedent("""
         const trans_dep = require('{require_dep}');
         const addOne = (num) => {{
@@ -160,7 +160,7 @@ def _create_app(self, dep, dep_not_found=None, package_manager=None, src_root=No
 
     require_dep = 'dep'
     if node_scope:
-      require_dep = os.path.join('@{}'.format(node_scope), require_dep)
+      require_dep = os.path.join(f'@{node_scope}', require_dep)
     self.create_file(os.path.join(src_root, 'app/index.js'), contents=dedent("""
       const dep = require('{require_dep}');
       console.log(dep.addOne(1));
diff --git a/contrib/node/tests/python/pants_test/contrib/node/tasks/test_node_task.py b/contrib/node/tests/python/pants_test/contrib/node/tasks/test_node_task.py
index 1c3158f023b..8e468a9af97 100644
--- a/contrib/node/tests/python/pants_test/contrib/node/tasks/test_node_task.py
+++ b/contrib/node/tests/python/pants_test/contrib/node/tasks/test_node_task.py
@@ -105,7 +105,7 @@ def test_execute_npm(self):
         'name': 'pantsbuild.pants.test',
         'version': '0.0.0',
         'scripts': {
-          'proof': 'echo "42" > {}'.format(proof)
+          'proof': f'echo "42" > {proof}'
         }
       }
       with open(os.path.join(chroot, 'package.json'), 'w') as fp:
@@ -130,7 +130,7 @@ def test_execute_yarnpkg(self):
         'name': 'pantsbuild.pants.test',
         'version': '0.0.0',
         'scripts': {
-          'proof': 'echo "42" > {}'.format(proof)
+          'proof': f'echo "42" > {proof}'
         }
       }
       with open(os.path.join(chroot, 'package.json'), 'w') as fp: