diff --git a/color.py b/color.py index e3e2a5f..7751715 100644 --- a/color.py +++ b/color.py @@ -194,7 +194,7 @@ class Coloring: if not opt: return _Color(fg, bg, attr) - v = self._config.GetString("%s.%s" % (self._section, opt)) + v = self._config.GetString(f"{self._section}.{opt}") if v is None: return _Color(fg, bg, attr) diff --git a/editor.py b/editor.py index 10ff158..359cff9 100644 --- a/editor.py +++ b/editor.py @@ -104,9 +104,7 @@ least one of these before using this command.""", # noqa: E501 try: rc = subprocess.Popen(args, shell=shell).wait() except OSError as e: - raise EditorError( - "editor failed, %s: %s %s" % (str(e), editor, path) - ) + raise EditorError(f"editor failed, {str(e)}: {editor} {path}") if rc != 0: raise EditorError( "editor failed with exit status %d: %s %s" diff --git a/git_command.py b/git_command.py index 0e25639..3c3869a 100644 --- a/git_command.py +++ b/git_command.py @@ -196,12 +196,10 @@ class UserAgent: def git(self): """The UA when running git.""" if self._git_ua is None: - self._git_ua = "git/%s (%s) git-repo/%s" % ( - git.version_tuple().full, - self.os, - RepoSourceVersion(), + self._git_ua = ( + f"git/{git.version_tuple().full} ({self.os}) " + f"git-repo/{RepoSourceVersion()}" ) - return self._git_ua @@ -216,7 +214,7 @@ def git_require(min_version, fail=False, msg=""): need = ".".join(map(str, min_version)) if msg: msg = " for " + msg - error_msg = "fatal: git %s or later required%s" % (need, msg) + error_msg = f"fatal: git {need} or later required{msg}" logger.error(error_msg) raise GitRequireError(error_msg) return False @@ -243,7 +241,7 @@ def _build_env( env["GIT_SSH"] = ssh_proxy.proxy env["GIT_SSH_VARIANT"] = "ssh" if "http_proxy" in env and "darwin" == sys.platform: - s = "'http.proxy=%s'" % (env["http_proxy"],) + s = f"'http.proxy={env['http_proxy']}'" p = env.get("GIT_CONFIG_PARAMETERS") if p is not None: s = p + " " + s @@ -468,7 +466,7 @@ class GitCommand: ) except Exception as e: raise GitPopenCommandError( - message="%s: %s" % (command[1], e), + message=f"{command[1]}: {e}", project=self.project.name if self.project else None, command_args=self.cmdv, ) diff --git a/git_config.py b/git_config.py index 6aa8d85..68016ff 100644 --- a/git_config.py +++ b/git_config.py @@ -418,7 +418,7 @@ class GitConfig: if p.Wait() == 0: return p.stdout else: - raise GitError("git config %s: %s" % (str(args), p.stderr)) + raise GitError(f"git config {str(args)}: {p.stderr}") class RepoConfig(GitConfig): @@ -651,13 +651,11 @@ class Remote: userEmail, host, port ) except urllib.error.HTTPError as e: - raise UploadError("%s: %s" % (self.review, str(e))) + raise UploadError(f"{self.review}: {str(e)}") except urllib.error.URLError as e: - raise UploadError("%s: %s" % (self.review, str(e))) + raise UploadError(f"{self.review}: {str(e)}") except http.client.HTTPException as e: - raise UploadError( - "%s: %s" % (self.review, e.__class__.__name__) - ) + raise UploadError(f"{self.review}: {e.__class__.__name__}") REVIEW_CACHE[u] = self._review_url return self._review_url + self.projectname @@ -666,7 +664,7 @@ class Remote: username = self._config.GetString("review.%s.username" % self.review) if username is None: username = userEmail.split("@")[0] - return "ssh://%s@%s:%s/" % (username, host, port) + return f"ssh://{username}@{host}:{port}/" def ToLocal(self, rev): """Convert a remote revision string to something we have locally.""" @@ -715,11 +713,11 @@ class Remote: self._Set("fetch", list(map(str, self.fetch))) def _Set(self, key, value): - key = "remote.%s.%s" % (self.name, key) + key = f"remote.{self.name}.{key}" return self._config.SetString(key, value) def _Get(self, key, all_keys=False): - key = "remote.%s.%s" % (self.name, key) + key = f"remote.{self.name}.{key}" return self._config.GetString(key, all_keys=all_keys) @@ -762,11 +760,11 @@ class Branch: fd.write("\tmerge = %s\n" % self.merge) def _Set(self, key, value): - key = "branch.%s.%s" % (self.name, key) + key = f"branch.{self.name}.{key}" return self._config.SetString(key, value) def _Get(self, key, all_keys=False): - key = "branch.%s.%s" % (self.name, key) + key = f"branch.{self.name}.{key}" return self._config.GetString(key, all_keys=all_keys) diff --git a/git_trace2_event_log_base.py b/git_trace2_event_log_base.py index 7b51b75..f542424 100644 --- a/git_trace2_event_log_base.py +++ b/git_trace2_event_log_base.py @@ -76,9 +76,8 @@ class BaseEventLog: # Save both our sid component and the complete sid. # We use our sid component (self._sid) as the unique filename prefix and # the full sid (self._full_sid) in the log itself. - self._sid = "repo-%s-P%08x" % ( - self.start.strftime("%Y%m%dT%H%M%SZ"), - os.getpid(), + self._sid = ( + f"repo-{self.start.strftime('%Y%m%dT%H%M%SZ')}-P{os.getpid():08x}" ) if add_init_count: diff --git a/hooks.py b/hooks.py index 6ded08b..82bf7e3 100644 --- a/hooks.py +++ b/hooks.py @@ -180,7 +180,7 @@ class RepoHook: abort_if_user_denies was passed to the consturctor. """ hooks_config = self._hooks_project.config - git_approval_key = "repo.hooks.%s.%s" % (self._hook_type, subkey) + git_approval_key = f"repo.hooks.{self._hook_type}.{subkey}" # Get the last value that the user approved for this hook; may be None. old_val = hooks_config.GetString(git_approval_key) @@ -193,7 +193,7 @@ class RepoHook: else: # Give the user a reason why we're prompting, since they last # told us to "never ask again". - prompt = "WARNING: %s\n\n" % (changed_prompt,) + prompt = f"WARNING: {changed_prompt}\n\n" else: prompt = "" @@ -241,9 +241,8 @@ class RepoHook: return self._CheckForHookApprovalHelper( "approvedmanifest", self._manifest_url, - "Run hook scripts from %s" % (self._manifest_url,), - "Manifest URL has changed since %s was allowed." - % (self._hook_type,), + f"Run hook scripts from {self._manifest_url}", + f"Manifest URL has changed since {self._hook_type} was allowed.", ) def _CheckForHookApprovalHash(self): @@ -262,7 +261,7 @@ class RepoHook: "approvedhash", self._GetHash(), prompt % (self._GetMustVerb(), self._script_fullpath), - "Scripts have changed since %s was allowed." % (self._hook_type,), + f"Scripts have changed since {self._hook_type} was allowed.", ) @staticmethod diff --git a/main.py b/main.py index bd8d513..604de76 100755 --- a/main.py +++ b/main.py @@ -198,9 +198,8 @@ class _Repo: if short: commands = " ".join(sorted(self.commands)) wrapped_commands = textwrap.wrap(commands, width=77) - print( - "Available commands:\n %s" % ("\n ".join(wrapped_commands),) - ) + help_commands = "".join(f"\n {x}" for x in wrapped_commands) + print(f"Available commands:{help_commands}") print("\nRun `repo help ` for command-specific details.") print("Bug reports:", Wrapper().BUG_URL) else: @@ -236,7 +235,7 @@ class _Repo: if name in self.commands: return name, [] - key = "alias.%s" % (name,) + key = f"alias.{name}" alias = RepoConfig.ForRepository(self.repodir).GetString(key) if alias is None: alias = RepoConfig.ForUser().GetString(key) diff --git a/manifest_xml.py b/manifest_xml.py index 97baed5..61b130c 100644 --- a/manifest_xml.py +++ b/manifest_xml.py @@ -114,9 +114,7 @@ def XmlInt(node, attr, default=None): try: return int(value) except ValueError: - raise ManifestParseError( - 'manifest: invalid %s="%s" integer' % (attr, value) - ) + raise ManifestParseError(f'manifest: invalid {attr}="{value}" integer') class _Default: @@ -810,7 +808,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md ret.setdefault(child.nodeName, []).append(element) else: raise ManifestParseError( - 'Unhandled element "%s"' % (child.nodeName,) + f'Unhandled element "{child.nodeName}"' ) append_children(element, child) @@ -1258,12 +1256,10 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md try: root = xml.dom.minidom.parse(path) except (OSError, xml.parsers.expat.ExpatError) as e: - raise ManifestParseError( - "error parsing manifest %s: %s" % (path, e) - ) + raise ManifestParseError(f"error parsing manifest {path}: {e}") if not root or not root.childNodes: - raise ManifestParseError("no root node in %s" % (path,)) + raise ManifestParseError(f"no root node in {path}") for manifest in root.childNodes: if ( @@ -1272,7 +1268,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md ): break else: - raise ManifestParseError("no in %s" % (path,)) + raise ManifestParseError(f"no in {path}") nodes = [] for node in manifest.childNodes: @@ -1282,7 +1278,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md msg = self._CheckLocalPath(name) if msg: raise ManifestInvalidPathError( - ' invalid "name": %s: %s' % (name, msg) + f' invalid "name": {name}: {msg}' ) include_groups = "" if parent_groups: @@ -1314,7 +1310,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md raise except Exception as e: raise ManifestParseError( - "failed parsing included manifest %s: %s" % (name, e) + f"failed parsing included manifest {name}: {e}" ) else: if parent_groups and node.nodeName == "project": @@ -1765,13 +1761,13 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md msg = self._CheckLocalPath(name) if msg: raise ManifestInvalidPathError( - ' invalid "name": %s: %s' % (name, msg) + f' invalid "name": {name}: {msg}' ) else: msg = self._CheckLocalPath(path) if msg: raise ManifestInvalidPathError( - ' invalid "path": %s: %s' % (path, msg) + f' invalid "path": {path}: {msg}' ) submanifest = _XmlSubmanifest( @@ -1806,7 +1802,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md msg = self._CheckLocalPath(name, dir_ok=True) if msg: raise ManifestInvalidPathError( - ' invalid "name": %s: %s' % (name, msg) + f' invalid "name": {name}: {msg}' ) if parent: name = self._JoinName(parent.name, name) @@ -1816,7 +1812,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md remote = self._default.remote if remote is None: raise ManifestParseError( - "no remote for project %s within %s" % (name, self.manifestFile) + f"no remote for project {name} within {self.manifestFile}" ) revisionExpr = node.getAttribute("revision") or remote.revision @@ -1837,7 +1833,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md msg = self._CheckLocalPath(path, dir_ok=True, cwd_dot_ok=True) if msg: raise ManifestInvalidPathError( - ' invalid "path": %s: %s' % (path, msg) + f' invalid "path": {path}: {msg}' ) rebase = XmlBool(node, "rebase", True) @@ -2094,7 +2090,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md if not cwd_dot_ok or parts != ["."]: for part in set(parts): if part in {".", "..", ".git"} or part.startswith(".repo"): - return "bad component: %s" % (part,) + return f"bad component: {part}" if not dir_ok and resep.match(path[-1]): return "dirs not allowed" @@ -2130,7 +2126,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md msg = cls._CheckLocalPath(dest) if msg: raise ManifestInvalidPathError( - '<%s> invalid "dest": %s: %s' % (element, dest, msg) + f'<{element}> invalid "dest": {dest}: {msg}' ) # |src| is the file we read from or path we point to for symlinks. @@ -2141,7 +2137,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md ) if msg: raise ManifestInvalidPathError( - '<%s> invalid "src": %s: %s' % (element, src, msg) + f'<{element}> invalid "src": {src}: {msg}' ) def _ParseCopyFile(self, project, node): @@ -2185,7 +2181,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md v = self._remotes.get(name) if not v: raise ManifestParseError( - "remote %s not defined in %s" % (name, self.manifestFile) + f"remote {name} not defined in {self.manifestFile}" ) return v diff --git a/platform_utils.py b/platform_utils.py index d720a07..4cf994b 100644 --- a/platform_utils.py +++ b/platform_utils.py @@ -57,8 +57,8 @@ def _validate_winpath(path): if _winpath_is_valid(path): return path raise ValueError( - 'Path "{}" must be a relative path or an absolute ' - "path starting with a drive letter".format(path) + f'Path "{path}" must be a relative path or an absolute ' + "path starting with a drive letter" ) diff --git a/platform_utils_win32.py b/platform_utils_win32.py index 80a5263..f10d9d0 100644 --- a/platform_utils_win32.py +++ b/platform_utils_win32.py @@ -186,9 +186,7 @@ def _create_symlink(source, link_name, dwFlags): error_desc = FormatError(code).strip() if code == ERROR_PRIVILEGE_NOT_HELD: raise OSError(errno.EPERM, error_desc, link_name) - _raise_winerror( - code, 'Error creating symbolic link "{}"'.format(link_name) - ) + _raise_winerror(code, f'Error creating symbolic link "{link_name}"') def islink(path): @@ -210,7 +208,7 @@ def readlink(path): ) if reparse_point_handle == INVALID_HANDLE_VALUE: _raise_winerror( - get_last_error(), 'Error opening symbolic link "{}"'.format(path) + get_last_error(), f'Error opening symbolic link "{path}"' ) target_buffer = c_buffer(MAXIMUM_REPARSE_DATA_BUFFER_SIZE) n_bytes_returned = DWORD() @@ -227,7 +225,7 @@ def readlink(path): CloseHandle(reparse_point_handle) if not io_result: _raise_winerror( - get_last_error(), 'Error reading symbolic link "{}"'.format(path) + get_last_error(), f'Error reading symbolic link "{path}"' ) rdb = REPARSE_DATA_BUFFER.from_buffer(target_buffer) if rdb.ReparseTag == IO_REPARSE_TAG_SYMLINK: @@ -236,11 +234,11 @@ def readlink(path): return rdb.MountPointReparseBuffer.PrintName # Unsupported reparse point type. _raise_winerror( - ERROR_NOT_SUPPORTED, 'Error reading symbolic link "{}"'.format(path) + ERROR_NOT_SUPPORTED, f'Error reading symbolic link "{path}"' ) def _raise_winerror(code, error_desc): win_error_desc = FormatError(code).strip() - error_desc = "{0}: {1}".format(error_desc, win_error_desc) + error_desc = f"{error_desc}: {win_error_desc}" raise WinError(code, error_desc) diff --git a/progress.py b/progress.py index 54eb8f9..290265c 100644 --- a/progress.py +++ b/progress.py @@ -52,11 +52,11 @@ def duration_str(total): uses microsecond resolution. This makes for noisy output. """ hours, mins, secs = convert_to_hms(total) - ret = "%.3fs" % (secs,) + ret = f"{secs:.3f}s" if mins: - ret = "%im%s" % (mins, ret) + ret = f"{mins}m{ret}" if hours: - ret = "%ih%s" % (hours, ret) + ret = f"{hours}h{ret}" return ret diff --git a/project.py b/project.py index 7b78427..069cc71 100644 --- a/project.py +++ b/project.py @@ -365,19 +365,19 @@ def _SafeExpandPath(base, subpath, skipfinal=False): for part in components: if part in {".", ".."}: raise ManifestInvalidPathError( - '%s: "%s" not allowed in paths' % (subpath, part) + f'{subpath}: "{part}" not allowed in paths' ) path = os.path.join(path, part) if platform_utils.islink(path): raise ManifestInvalidPathError( - "%s: traversing symlinks not allow" % (path,) + f"{path}: traversing symlinks not allow" ) if os.path.exists(path): if not os.path.isfile(path) and not platform_utils.isdir(path): raise ManifestInvalidPathError( - "%s: only regular files & directories allowed" % (path,) + f"{path}: only regular files & directories allowed" ) if skipfinal: @@ -409,11 +409,11 @@ class _CopyFile: if platform_utils.isdir(src): raise ManifestInvalidPathError( - "%s: copying from directory not supported" % (self.src,) + f"{self.src}: copying from directory not supported" ) if platform_utils.isdir(dest): raise ManifestInvalidPathError( - "%s: copying to directory not allowed" % (self.dest,) + f"{self.dest}: copying to directory not allowed" ) # Copy file if it does not exist or is out of date. @@ -957,15 +957,11 @@ class Project: f_status = "-" if i and i.src_path: - line = " %s%s\t%s => %s (%s%%)" % ( - i_status, - f_status, - i.src_path, - p, - i.level, + line = ( + f" {i_status}{f_status}\t{i.src_path} => {p} ({i.level}%)" ) else: - line = " %s%s\t%s" % (i_status, f_status, p) + line = f" {i_status}{f_status}\t{p}" if i and not f: out.added("%s", line) @@ -1157,7 +1153,7 @@ class Project: if dest_branch.startswith(R_HEADS): dest_branch = dest_branch[len(R_HEADS) :] - ref_spec = "%s:refs/for/%s" % (R_HEADS + branch.name, dest_branch) + ref_spec = f"{R_HEADS + branch.name}:refs/for/{dest_branch}" opts = [] if auto_topic: opts += ["topic=" + branch.name] @@ -1182,7 +1178,7 @@ class Project: GitCommand(self, cmd, bare=True, verify_command=True).Wait() if not dryrun: - msg = "posted to %s for %s" % (branch.remote.review, dest_branch) + msg = f"posted to {branch.remote.review} for {dest_branch}" self.bare_git.UpdateRef( R_PUB + branch.name, R_HEADS + branch.name, message=msg ) @@ -1444,7 +1440,7 @@ class Project: return self.bare_git.rev_list(self.revisionExpr, "-1")[0] except GitError: raise ManifestInvalidRevisionError( - "revision %s in %s not found" % (self.revisionExpr, self.name) + f"revision {self.revisionExpr} in {self.name} not found" ) def GetRevisionId(self, all_refs=None): @@ -1461,7 +1457,7 @@ class Project: return self.bare_git.rev_parse("--verify", "%s^0" % rev) except GitError: raise ManifestInvalidRevisionError( - "revision %s in %s not found" % (self.revisionExpr, self.name) + f"revision {self.revisionExpr} in {self.name} not found" ) def SetRevisionId(self, revisionId): @@ -1773,9 +1769,7 @@ class Project: raise DeleteDirtyWorktreeError(msg, project=self) if not quiet: - print( - "%s: Deleting obsolete checkout." % (self.RelPath(local=False),) - ) + print(f"{self.RelPath(local=False)}: Deleting obsolete checkout.") # Unlock and delink from the main worktree. We don't use git's worktree # remove because it will recursively delete projects -- we handle that @@ -1968,7 +1962,7 @@ class Project: # target branch, but otherwise take no other action. _lwrite( self.work_git.GetDotgitPath(subpath=HEAD), - "ref: %s%s\n" % (R_HEADS, name), + f"ref: {R_HEADS}{name}\n", ) return True @@ -2277,7 +2271,7 @@ class Project: self.config.SetString("core.repositoryFormatVersion", str(version)) # Enable the extension! - self.config.SetString("extensions.%s" % (key,), value) + self.config.SetString(f"extensions.{key}", value) def ResolveRemoteHead(self, name=None): """Find out what the default branch (HEAD) points to. @@ -2447,7 +2441,7 @@ class Project: old_packed_lines = [] for r in sorted(all_refs): - line = "%s %s\n" % (all_refs[r], r) + line = f"{all_refs[r]} {r}\n" tmp_packed_lines.append(line) if r not in tmp: old_packed_lines.append(line) @@ -2617,7 +2611,7 @@ class Project: # one. if not verbose and gitcmd.stdout: print( - "\n%s:\n%s" % (self.name, gitcmd.stdout), + f"\n{self.name}:\n{gitcmd.stdout}", end="", file=output_redir, ) @@ -2752,7 +2746,7 @@ class Project: proc = None with Trace("Fetching bundle: %s", " ".join(cmd)): if verbose: - print("%s: Downloading bundle: %s" % (self.name, srcUrl)) + print(f"{self.name}: Downloading bundle: {srcUrl}") stdout = None if verbose else subprocess.PIPE stderr = None if verbose else subprocess.STDOUT try: @@ -2810,7 +2804,7 @@ class Project: if GitCommand(self, cmd).Wait() != 0: if self._allrefs: raise GitError( - "%s checkout %s " % (self.name, rev), project=self.name + f"{self.name} checkout {rev} ", project=self.name ) def _CherryPick(self, rev, ffonly=False, record_origin=False): @@ -2824,7 +2818,7 @@ class Project: if GitCommand(self, cmd).Wait() != 0: if self._allrefs: raise GitError( - "%s cherry-pick %s " % (self.name, rev), project=self.name + f"{self.name} cherry-pick {rev} ", project=self.name ) def _LsRemote(self, refs): @@ -2841,9 +2835,7 @@ class Project: cmd.append("--") if GitCommand(self, cmd).Wait() != 0: if self._allrefs: - raise GitError( - "%s revert %s " % (self.name, rev), project=self.name - ) + raise GitError(f"{self.name} revert {rev} ", project=self.name) def _ResetHard(self, rev, quiet=True): cmd = ["reset", "--hard"] @@ -2852,7 +2844,7 @@ class Project: cmd.append(rev) if GitCommand(self, cmd).Wait() != 0: raise GitError( - "%s reset --hard %s " % (self.name, rev), project=self.name + f"{self.name} reset --hard {rev} ", project=self.name ) def _SyncSubmodules(self, quiet=True): @@ -2871,18 +2863,14 @@ class Project: cmd.extend(["--onto", onto]) cmd.append(upstream) if GitCommand(self, cmd).Wait() != 0: - raise GitError( - "%s rebase %s " % (self.name, upstream), project=self.name - ) + raise GitError(f"{self.name} rebase {upstream} ", project=self.name) def _FastForward(self, head, ffonly=False): cmd = ["merge", "--no-stat", head] if ffonly: cmd.append("--ff-only") if GitCommand(self, cmd).Wait() != 0: - raise GitError( - "%s merge %s " % (self.name, head), project=self.name - ) + raise GitError(f"{self.name} merge {head} ", project=self.name) def _InitGitDir(self, mirror_git=None, force_sync=False, quiet=False): init_git_dir = not os.path.exists(self.gitdir) @@ -3171,8 +3159,9 @@ class Project: "--force-sync not enabled; cannot overwrite a local " "work tree. If you're comfortable with the " "possibility of losing the work tree's git metadata," - " use `repo sync --force-sync {0}` to " - "proceed.".format(self.RelPath(local=False)), + " use " + f"`repo sync --force-sync {self.RelPath(local=False)}` " + "to proceed.", project=self.name, ) @@ -3686,12 +3675,12 @@ class Project: config = kwargs.pop("config", None) for k in kwargs: raise TypeError( - "%s() got an unexpected keyword argument %r" % (name, k) + f"{name}() got an unexpected keyword argument {k!r}" ) if config is not None: for k, v in config.items(): cmdv.append("-c") - cmdv.append("%s=%s" % (k, v)) + cmdv.append(f"{k}={v}") cmdv.append(name) cmdv.extend(args) p = GitCommand( diff --git a/repo b/repo index a9ae4fa..2738142 100755 --- a/repo +++ b/repo @@ -33,7 +33,7 @@ import sys # bit more flexible with older systems. See that file for more details on the # versions we select. MIN_PYTHON_VERSION_SOFT = (3, 6) -MIN_PYTHON_VERSION_HARD = (3, 5) +MIN_PYTHON_VERSION_HARD = (3, 6) # Keep basic logic in sync with repo_trace.py. @@ -96,7 +96,7 @@ def check_python_version(): # bridge the gap. This is the fallback anyways so perf isn't critical. min_major, min_minor = MIN_PYTHON_VERSION_SOFT for inc in range(0, 10): - reexec("python{}.{}".format(min_major, min_minor + inc)) + reexec(f"python{min_major}.{min_minor + inc}") # Fallback to older versions if possible. for inc in range( @@ -105,7 +105,7 @@ def check_python_version(): # Don't downgrade, and don't reexec ourselves (which would infinite loop). if (min_major, min_minor - inc) <= (major, minor): break - reexec("python{}.{}".format(min_major, min_minor - inc)) + reexec(f"python{min_major}.{min_minor - inc}") # Try the generic Python 3 wrapper, but only if it's new enough. If it # isn't, we want to just give up below and make the user resolve things. @@ -566,8 +566,7 @@ def run_command(cmd, **kwargs): return output.decode("utf-8") except UnicodeError: print( - "repo: warning: Invalid UTF-8 output:\ncmd: %r\n%r" - % (cmd, output), + f"repo: warning: Invalid UTF-8 output:\ncmd: {cmd!r}\n{output}", file=sys.stderr, ) return output.decode("utf-8", "backslashreplace") @@ -590,20 +589,17 @@ def run_command(cmd, **kwargs): # If things failed, print useful debugging output. if check and ret.returncode: print( - 'repo: error: "%s" failed with exit status %s' - % (cmd[0], ret.returncode), - file=sys.stderr, - ) - print( - " cwd: %s\n cmd: %r" % (kwargs.get("cwd", os.getcwd()), cmd), + f'repo: error: "{cmd[0]}" failed with exit status {ret.returncode}', file=sys.stderr, ) + cwd = kwargs.get("cwd", os.getcwd()) + print(f" cwd: {cwd}\n cmd: {cmd!r}", file=sys.stderr) def _print_output(name, output): if output: print( - " %s:\n >> %s" - % (name, "\n >> ".join(output.splitlines())), + f" {name}:" + + "".join(f"\n >> {x}" for x in output.splitlines()), file=sys.stderr, ) @@ -719,7 +715,7 @@ def _Init(args, gitc_init=False): except OSError as e: if e.errno != errno.EEXIST: print( - "fatal: cannot make %s directory: %s" % (repodir, e.strerror), + f"fatal: cannot make {repodir} directory: {e.strerror}", file=sys.stderr, ) # Don't raise CloneFailure; that would delete the @@ -817,7 +813,7 @@ def _CheckGitVersion(): if ver_act < MIN_GIT_VERSION: need = ".".join(map(str, MIN_GIT_VERSION)) print( - "fatal: git %s or later required; found %s" % (need, ver_act.full), + f"fatal: git {need} or later required; found {ver_act.full}", file=sys.stderr, ) raise CloneFailure() @@ -836,7 +832,8 @@ def SetGitTrace2ParentSid(env=None): KEY = "GIT_TRACE2_PARENT_SID" now = datetime.datetime.now(datetime.timezone.utc) - value = "repo-%s-P%08x" % (now.strftime("%Y%m%dT%H%M%SZ"), os.getpid()) + timestamp = now.strftime("%Y%m%dT%H%M%SZ") + value = f"repo-{timestamp}-P{os.getpid():08x}" # If it's already set, then append ourselves. if KEY in env: @@ -880,8 +877,7 @@ def SetupGnuPG(quiet): except OSError as e: if e.errno != errno.EEXIST: print( - "fatal: cannot make %s directory: %s" - % (home_dot_repo, e.strerror), + f"fatal: cannot make {home_dot_repo} directory: {e.strerror}", file=sys.stderr, ) sys.exit(1) @@ -891,15 +887,15 @@ def SetupGnuPG(quiet): except OSError as e: if e.errno != errno.EEXIST: print( - "fatal: cannot make %s directory: %s" % (gpg_dir, e.strerror), + f"fatal: cannot make {gpg_dir} directory: {e.strerror}", file=sys.stderr, ) sys.exit(1) if not quiet: print( - "repo: Updating release signing keys to keyset ver %s" - % (".".join(str(x) for x in KEYRING_VERSION),) + "repo: Updating release signing keys to keyset ver " + + ".".join(str(x) for x in KEYRING_VERSION), ) # NB: We use --homedir (and cwd below) because some environments (Windows) do # not correctly handle full native paths. We avoid the issue by changing to @@ -951,7 +947,7 @@ def _GetRepoConfig(name): return None else: print( - "repo: error: git %s failed:\n%s" % (" ".join(cmd), ret.stderr), + f"repo: error: git {' '.join(cmd)} failed:\n{ret.stderr}", file=sys.stderr, ) raise RunError() @@ -1064,7 +1060,7 @@ def _Clone(url, cwd, clone_bundle, quiet, verbose): os.mkdir(cwd) except OSError as e: print( - "fatal: cannot make %s directory: %s" % (cwd, e.strerror), + f"fatal: cannot make {cwd} directory: {e.strerror}", file=sys.stderr, ) raise CloneFailure() @@ -1104,7 +1100,7 @@ def resolve_repo_rev(cwd, committish): ret = run_git( "rev-parse", "--verify", - "%s^{commit}" % (committish,), + f"{committish}^{{commit}}", cwd=cwd, check=False, ) @@ -1117,7 +1113,7 @@ def resolve_repo_rev(cwd, committish): rev = resolve("refs/remotes/origin/%s" % committish) if rev is None: print( - 'repo: error: unknown branch "%s"' % (committish,), + f'repo: error: unknown branch "{committish}"', file=sys.stderr, ) raise CloneFailure() @@ -1130,7 +1126,8 @@ def resolve_repo_rev(cwd, committish): rev = resolve(remote_ref) if rev is None: print( - 'repo: error: unknown tag "%s"' % (committish,), file=sys.stderr + f'repo: error: unknown tag "{committish}"', + file=sys.stderr, ) raise CloneFailure() return (remote_ref, rev) @@ -1138,12 +1135,12 @@ def resolve_repo_rev(cwd, committish): # See if it's a short branch name. rev = resolve("refs/remotes/origin/%s" % committish) if rev: - return ("refs/heads/%s" % (committish,), rev) + return (f"refs/heads/{committish}", rev) # See if it's a tag. - rev = resolve("refs/tags/%s" % committish) + rev = resolve(f"refs/tags/{committish}") if rev: - return ("refs/tags/%s" % (committish,), rev) + return (f"refs/tags/{committish}", rev) # See if it's a commit. rev = resolve(committish) @@ -1152,7 +1149,8 @@ def resolve_repo_rev(cwd, committish): # Give up! print( - 'repo: error: unable to resolve "%s"' % (committish,), file=sys.stderr + f'repo: error: unable to resolve "{committish}"', + file=sys.stderr, ) raise CloneFailure() @@ -1168,8 +1166,8 @@ def verify_rev(cwd, remote_ref, rev, quiet): if not quiet: print(file=sys.stderr) print( - "warning: '%s' is not signed; falling back to signed release '%s'" - % (remote_ref, cur), + f"warning: '{remote_ref}' is not signed; " + f"falling back to signed release '{cur}'", file=sys.stderr, ) print(file=sys.stderr) @@ -1222,7 +1220,7 @@ def _ExpandAlias(name): if name in {"gitc-init", "help", "init"}: return name, [] - alias = _GetRepoConfig("alias.%s" % (name,)) + alias = _GetRepoConfig(f"alias.{name}") if alias is None: return name, [] @@ -1318,18 +1316,20 @@ class Requirements: hard_ver = tuple(self._get_hard_ver(pkg)) if curr_ver < hard_ver: print( - 'repo: error: Your version of "%s" (%s) is unsupported; ' - "Please upgrade to at least version %s to continue." - % (pkg, self._format_ver(curr_ver), self._format_ver(soft_ver)), + f'repo: error: Your version of "{pkg}" ' + f"({self._format_ver(curr_ver)}) is unsupported; " + "Please upgrade to at least version " + f"{self._format_ver(soft_ver)} to continue.", file=sys.stderr, ) sys.exit(1) if curr_ver < soft_ver: print( - 'repo: warning: Your version of "%s" (%s) is no longer supported; ' - "Please upgrade to at least version %s to avoid breakage." - % (pkg, self._format_ver(curr_ver), self._format_ver(soft_ver)), + f'repo: error: Your version of "{pkg}" ' + f"({self._format_ver(curr_ver)}) is no longer supported; " + "Please upgrade to at least version " + f"{self._format_ver(soft_ver)} to continue.", file=sys.stderr, ) @@ -1390,20 +1390,18 @@ def _Help(args): def _Version(): """Show version information.""" print("") - print("repo launcher version %s" % (".".join(str(x) for x in VERSION),)) - print(" (from %s)" % (__file__,)) - print("git %s" % (ParseGitVersion().full,)) - print("Python %s" % sys.version) + print(f"repo launcher version {'.'.join(str(x) for x in VERSION)}") + print(f" (from {__file__})") + print(f"git {ParseGitVersion().full}") + print(f"Python {sys.version}") uname = platform.uname() if sys.version_info.major < 3: # Python 3 returns a named tuple, but Python 2 is simpler. print(uname) else: - print("OS %s %s (%s)" % (uname.system, uname.release, uname.version)) - print( - "CPU %s (%s)" - % (uname.machine, uname.processor if uname.processor else "unknown") - ) + print(f"OS {uname.system} {uname.release} ({uname.version})") + processor = uname.processor if uname.processor else "unknown" + print(f"CPU {uname.machine} ({processor})") print("Bug reports:", BUG_URL) sys.exit(0) diff --git a/ssh.py b/ssh.py index bb89fa1..a824279 100644 --- a/ssh.py +++ b/ssh.py @@ -165,7 +165,7 @@ class ProxyManager: # Check to see whether we already think that the master is running; if # we think it's already running, return right away. if port is not None: - key = "%s:%s" % (host, port) + key = f"{host}:{port}" else: key = host diff --git a/subcmds/__init__.py b/subcmds/__init__.py index 965ad0b..83ec847 100644 --- a/subcmds/__init__.py +++ b/subcmds/__init__.py @@ -37,9 +37,7 @@ for py in os.listdir(my_dir): try: cmd = getattr(mod, clsn) except AttributeError: - raise SyntaxError( - "%s/%s does not define class %s" % (__name__, py, clsn) - ) + raise SyntaxError(f"{__name__}/{py} does not define class {clsn}") name = name.replace("_", "-") cmd.NAME = name diff --git a/subcmds/abandon.py b/subcmds/abandon.py index f6c0c66..e280d69 100644 --- a/subcmds/abandon.py +++ b/subcmds/abandon.py @@ -117,7 +117,7 @@ It is equivalent to "git branch -D ". all_projects, callback=_ProcessResults, output=Progress( - "Abandon %s" % (nb,), len(all_projects), quiet=opt.quiet + f"Abandon {nb}", len(all_projects), quiet=opt.quiet ), ) @@ -152,4 +152,4 @@ It is equivalent to "git branch -D ". _RelPath(p) for p in success[br] ) ) - print("%s%s| %s\n" % (br, " " * (width - len(br)), result)) + print(f"{br}{' ' * (width - len(br))}| {result}\n") diff --git a/subcmds/branches.py b/subcmds/branches.py index d9a190b..59b5cb2 100644 --- a/subcmds/branches.py +++ b/subcmds/branches.py @@ -174,7 +174,7 @@ is shown, then the branch appears in all projects. if _RelPath(p) not in have: paths.append(_RelPath(p)) - s = " %s %s" % (in_type, ", ".join(paths)) + s = f" {in_type} {', '.join(paths)}" if not i.IsSplitCurrent and (width + 7 + len(s) < 80): fmt = out.current if i.IsCurrent else fmt fmt(s) diff --git a/subcmds/checkout.py b/subcmds/checkout.py index ea48263..379bfa1 100644 --- a/subcmds/checkout.py +++ b/subcmds/checkout.py @@ -96,7 +96,7 @@ The command is equivalent to: all_projects, callback=_ProcessResults, output=Progress( - "Checkout %s" % (nb,), len(all_projects), quiet=opt.quiet + f"Checkout {nb}", len(all_projects), quiet=opt.quiet ), ) diff --git a/subcmds/diffmanifests.py b/subcmds/diffmanifests.py index b446dbd..88b697b 100644 --- a/subcmds/diffmanifests.py +++ b/subcmds/diffmanifests.py @@ -87,25 +87,17 @@ synced and their revisions won't be found. def _printRawDiff(self, diff, pretty_format=None, local=False): _RelPath = lambda p: p.RelPath(local=local) for project in diff["added"]: - self.printText( - "A %s %s" % (_RelPath(project), project.revisionExpr) - ) + self.printText(f"A {_RelPath(project)} {project.revisionExpr}") self.out.nl() for project in diff["removed"]: - self.printText( - "R %s %s" % (_RelPath(project), project.revisionExpr) - ) + self.printText(f"R {_RelPath(project)} {project.revisionExpr}") self.out.nl() for project, otherProject in diff["changed"]: self.printText( - "C %s %s %s" - % ( - _RelPath(project), - project.revisionExpr, - otherProject.revisionExpr, - ) + f"C {_RelPath(project)} {project.revisionExpr} " + f"{otherProject.revisionExpr}" ) self.out.nl() self._printLogs( @@ -118,12 +110,8 @@ synced and their revisions won't be found. for project, otherProject in diff["unreachable"]: self.printText( - "U %s %s %s" - % ( - _RelPath(project), - project.revisionExpr, - otherProject.revisionExpr, - ) + f"U {_RelPath(project)} {project.revisionExpr} " + f"{otherProject.revisionExpr}" ) self.out.nl() diff --git a/subcmds/help.py b/subcmds/help.py index a839131..8004071 100644 --- a/subcmds/help.py +++ b/subcmds/help.py @@ -150,7 +150,7 @@ Displays detailed usage information about a command. def _PrintAllCommandHelp(self): for name in sorted(all_commands): cmd = all_commands[name](manifest=self.manifest) - self._PrintCommandHelp(cmd, header_prefix="[%s] " % (name,)) + self._PrintCommandHelp(cmd, header_prefix=f"[{name}] ") def _Options(self, p): p.add_option( diff --git a/subcmds/info.py b/subcmds/info.py index c24682c..f637600 100644 --- a/subcmds/info.py +++ b/subcmds/info.py @@ -248,7 +248,7 @@ class Info(PagedCommand): for commit in commits: split = commit.split() - self.text("{0:38}{1} ".format("", "-")) + self.text(f"{'':38}{'-'} ") self.sha(split[0] + " ") self.text(" ".join(split[1:])) self.out.nl() diff --git a/subcmds/init.py b/subcmds/init.py index 9ac42d8..4451787 100644 --- a/subcmds/init.py +++ b/subcmds/init.py @@ -215,7 +215,7 @@ to update the working directory files. if not opt.quiet: print() - print("Your identity is: %s <%s>" % (name, email)) + print(f"Your identity is: {name} <{email}>") print("is this correct [y/N]? ", end="", flush=True) a = sys.stdin.readline().strip().lower() if a in ("yes", "y", "t", "true"): diff --git a/subcmds/list.py b/subcmds/list.py index fba6a4d..4338e1c 100644 --- a/subcmds/list.py +++ b/subcmds/list.py @@ -131,7 +131,7 @@ This is similar to running: repo forall -c 'echo "$REPO_PATH : $REPO_PROJECT"'. elif opt.path_only and not opt.name_only: lines.append("%s" % (_getpath(project))) else: - lines.append("%s : %s" % (_getpath(project), project.name)) + lines.append(f"{_getpath(project)} : {project.name}") if lines: lines.sort() diff --git a/subcmds/prune.py b/subcmds/prune.py index f18471f..f99082a 100644 --- a/subcmds/prune.py +++ b/subcmds/prune.py @@ -83,9 +83,7 @@ class Prune(PagedCommand): ) if not branch.base_exists: - print( - "(ignoring: tracking branch is gone: %s)" % (branch.base,) - ) + print(f"(ignoring: tracking branch is gone: {branch.base})") else: commits = branch.commits date = branch.date diff --git a/subcmds/start.py b/subcmds/start.py index fd177f9..56008f4 100644 --- a/subcmds/start.py +++ b/subcmds/start.py @@ -130,7 +130,7 @@ revision specified in the manifest. all_projects, callback=_ProcessResults, output=Progress( - "Starting %s" % (nb,), len(all_projects), quiet=opt.quiet + f"Starting {nb}", len(all_projects), quiet=opt.quiet ), ) diff --git a/subcmds/sync.py b/subcmds/sync.py index a0a0be9..02c1d3a 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py @@ -1394,7 +1394,7 @@ later is required to fix a server side protocol bug. if username and password: manifest_server = manifest_server.replace( - "://", "://%s:%s@" % (username, password), 1 + "://", f"://{username}:{password}@", 1 ) transport = PersistentTransport(manifest_server) diff --git a/subcmds/version.py b/subcmds/version.py index 71a0360..5c817f1 100644 --- a/subcmds/version.py +++ b/subcmds/version.py @@ -42,35 +42,28 @@ class Version(Command, MirrorSafeCommand): # These might not be the same. Report them both. src_ver = RepoSourceVersion() rp_ver = rp.bare_git.describe(HEAD) - print("repo version %s" % rp_ver) - print(" (from %s)" % rem.url) - print(" (tracking %s)" % branch.merge) - print(" (%s)" % rp.bare_git.log("-1", "--format=%cD", HEAD)) + print(f"repo version {rp_ver}") + print(f" (from {rem.url})") + print(f" (tracking {branch.merge})") + print(f" ({rp.bare_git.log('-1', '--format=%cD', HEAD)})") if self.wrapper_path is not None: - print("repo launcher version %s" % self.wrapper_version) - print(" (from %s)" % self.wrapper_path) + print(f"repo launcher version {self.wrapper_version}") + print(f" (from {self.wrapper_path})") if src_ver != rp_ver: - print(" (currently at %s)" % src_ver) + print(f" (currently at {src_ver})") - print("repo User-Agent %s" % user_agent.repo) - print("git %s" % git.version_tuple().full) - print("git User-Agent %s" % user_agent.git) - print("Python %s" % sys.version) + print(f"repo User-Agent {user_agent.repo}") + print(f"git {git.version_tuple().full}") + print(f"git User-Agent {user_agent.git}") + print(f"Python {sys.version}") uname = platform.uname() if sys.version_info.major < 3: # Python 3 returns a named tuple, but Python 2 is simpler. print(uname) else: - print( - "OS %s %s (%s)" % (uname.system, uname.release, uname.version) - ) - print( - "CPU %s (%s)" - % ( - uname.machine, - uname.processor if uname.processor else "unknown", - ) - ) + print(f"OS {uname.system} {uname.release} ({uname.version})") + processor = uname.processor if uname.processor else "unknown" + print(f"CPU {uname.machine} ({processor})") print("Bug reports:", Wrapper().BUG_URL) diff --git a/tests/test_git_command.py b/tests/test_git_command.py index 7c108cc..ffee023 100644 --- a/tests/test_git_command.py +++ b/tests/test_git_command.py @@ -19,12 +19,7 @@ import os import re import subprocess import unittest - - -try: - from unittest import mock -except ImportError: - import mock +from unittest import mock import git_command import wrapper diff --git a/tests/test_git_config.py b/tests/test_git_config.py index a44dca0..cf6e779 100644 --- a/tests/test_git_config.py +++ b/tests/test_git_config.py @@ -100,7 +100,7 @@ class GitConfigReadOnlyTests(unittest.TestCase): ("intg", 10737418240), ) for key, value in TESTS: - self.assertEqual(value, self.config.GetInt("section.%s" % (key,))) + self.assertEqual(value, self.config.GetInt(f"section.{key}")) class GitConfigReadWriteTests(unittest.TestCase): diff --git a/tests/test_git_superproject.py b/tests/test_git_superproject.py index 478ebca..4e66521 100644 --- a/tests/test_git_superproject.py +++ b/tests/test_git_superproject.py @@ -34,7 +34,7 @@ class SuperprojectTestCase(unittest.TestCase): PARENT_SID_KEY = "GIT_TRACE2_PARENT_SID" PARENT_SID_VALUE = "parent_sid" SELF_SID_REGEX = r"repo-\d+T\d+Z-.*" - FULL_SID_REGEX = r"^%s/%s" % (PARENT_SID_VALUE, SELF_SID_REGEX) + FULL_SID_REGEX = rf"^{PARENT_SID_VALUE}/{SELF_SID_REGEX}" def setUp(self): """Set up superproject every time.""" diff --git a/tests/test_git_trace2_event_log.py b/tests/test_git_trace2_event_log.py index d8e963d..4658a79 100644 --- a/tests/test_git_trace2_event_log.py +++ b/tests/test_git_trace2_event_log.py @@ -61,7 +61,7 @@ class EventLogTestCase(unittest.TestCase): PARENT_SID_KEY = "GIT_TRACE2_PARENT_SID" PARENT_SID_VALUE = "parent_sid" SELF_SID_REGEX = r"repo-\d+T\d+Z-.*" - FULL_SID_REGEX = r"^%s/%s" % (PARENT_SID_VALUE, SELF_SID_REGEX) + FULL_SID_REGEX = rf"^{PARENT_SID_VALUE}/{SELF_SID_REGEX}" def setUp(self): """Load the event_log module every time.""" diff --git a/tests/test_manifest_xml.py b/tests/test_manifest_xml.py index bd255dc..3fcf09f 100644 --- a/tests/test_manifest_xml.py +++ b/tests/test_manifest_xml.py @@ -198,13 +198,13 @@ class ValueTests(unittest.TestCase): def test_bool_true(self): """Check XmlBool true values.""" for value in ("yes", "true", "1"): - node = self._get_node('' % (value,)) + node = self._get_node(f'') self.assertTrue(manifest_xml.XmlBool(node, "a")) def test_bool_false(self): """Check XmlBool false values.""" for value in ("no", "false", "0"): - node = self._get_node('' % (value,)) + node = self._get_node(f'') self.assertFalse(manifest_xml.XmlBool(node, "a")) def test_int_default(self): @@ -220,7 +220,7 @@ class ValueTests(unittest.TestCase): def test_int_good(self): """Check XmlInt numeric handling.""" for value in (-1, 0, 1, 50000): - node = self._get_node('' % (value,)) + node = self._get_node(f'') self.assertEqual(value, manifest_xml.XmlInt(node, "a")) def test_int_invalid(self): diff --git a/tests/test_project.py b/tests/test_project.py index 83cfe0a..6dc071b 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -151,7 +151,7 @@ class CopyLinkTestCase(unittest.TestCase): # "". break result = os.path.exists(path) - msg.append("\tos.path.exists(%s): %s" % (path, result)) + msg.append(f"\tos.path.exists({path}): {result}") if result: msg.append("\tcontents: %r" % os.listdir(path)) break