Browse Source

Bump ruff

Jelmer Vernooij 3 months ago
parent
commit
f46269ced5

+ 1 - 1
dulwich/bundle.py

@@ -116,7 +116,7 @@ def write_bundle(f, bundle) -> None:
     elif version == 3:
         f.write(b"# v3 git bundle\n")
     else:
-        raise AssertionError("unknown version %d" % version)
+        raise AssertionError(f"unknown version {version}")
     if version == 3:
         for key, value in bundle.capabilities.items():
             f.write(b"@" + key.encode("utf-8"))

+ 2 - 2
dulwich/cli.py

@@ -217,7 +217,7 @@ class cmd_dump_pack(Command):
         print(f"Object names checksum: {x.name()}")
         print(f"Checksum: {sha_to_hex(x.get_stored_checksum())}")
         x.check()
-        print("Length: %d" % len(x))
+        print(f"Length: {len(x)}")
         for name in x:
             try:
                 print(f"\t{x[name]}")
@@ -729,7 +729,7 @@ class cmd_stash_list(Command):
         parser = optparse.OptionParser()
         options, args = parser.parse_args(args)
         for i, entry in porcelain.stash_list("."):
-            print("stash@{%d}: %s" % (i, entry.message.rstrip("\n")))
+            print(f"stash@{{{i}}}: {entry.message.rstrip('\n')}")
 
 
 class cmd_stash_push(Command):

+ 17 - 23
dulwich/client.py

@@ -706,7 +706,7 @@ def _handle_upload_pack_tail(
             elif chan == SIDE_BAND_CHANNEL_PROGRESS:
                 progress(data)
             else:
-                raise AssertionError("Invalid sideband channel %d" % chan)
+                raise AssertionError(f"Invalid sideband channel {chan}")
     else:
         while True:
             data = proto.read(rbufsize)
@@ -1099,7 +1099,7 @@ class GitClient:
                 elif chan == SIDE_BAND_CHANNEL_PROGRESS:
                     progress(data)
                 else:
-                    raise AssertionError("Invalid sideband channel %d" % chan)
+                    raise AssertionError(f"Invalid sideband channel {chan}")
         else:
             if CAPABILITY_REPORT_STATUS in capabilities:
                 assert self._report_status_parser
@@ -1351,17 +1351,16 @@ class TraditionalGitClient(GitClient):
             protocol_version is not None
             and protocol_version not in GIT_PROTOCOL_VERSIONS
         ):
-            raise ValueError("unknown Git protocol version %d" % protocol_version)
+            raise ValueError(f"unknown Git protocol version {protocol_version}")
         proto, can_read, stderr = self._connect(b"upload-pack", path, protocol_version)
         server_protocol_version = negotiate_protocol_version(proto)
         if server_protocol_version not in GIT_PROTOCOL_VERSIONS:
             raise ValueError(
-                "unknown Git protocol version %d used by server"
-                % server_protocol_version
+                f"unknown Git protocol version {server_protocol_version} used by server"
             )
         if protocol_version and server_protocol_version > protocol_version:
             raise ValueError(
-                "bad Git protocol version %d used by server" % server_protocol_version
+                f"bad Git protocol version {server_protocol_version} used by server"
             )
         self.protocol_version = server_protocol_version
         with proto:
@@ -1462,17 +1461,16 @@ class TraditionalGitClient(GitClient):
             protocol_version is not None
             and protocol_version not in GIT_PROTOCOL_VERSIONS
         ):
-            raise ValueError("unknown Git protocol version %d" % protocol_version)
+            raise ValueError(f"unknown Git protocol version {protocol_version}")
         proto, _, stderr = self._connect(b"upload-pack", path, protocol_version)
         server_protocol_version = negotiate_protocol_version(proto)
         if server_protocol_version not in GIT_PROTOCOL_VERSIONS:
             raise ValueError(
-                "unknown Git protocol version %d used by server"
-                % server_protocol_version
+                f"unknown Git protocol version {server_protocol_version} used by server"
             )
         if protocol_version and server_protocol_version > protocol_version:
             raise ValueError(
-                "bad Git protocol version %d used by server" % server_protocol_version
+                f"bad Git protocol version {server_protocol_version} used by server"
             )
         self.protocol_version = server_protocol_version
         if self.protocol_version == 2:
@@ -1552,7 +1550,7 @@ class TraditionalGitClient(GitClient):
                 elif chan == SIDE_BAND_CHANNEL_FATAL:
                     write_error(data)
                 else:
-                    raise AssertionError("Invalid sideband channel %d" % chan)
+                    raise AssertionError(f"Invalid sideband channel {chan}")
 
 
 class TCPGitClient(TraditionalGitClient):
@@ -1572,7 +1570,7 @@ class TCPGitClient(TraditionalGitClient):
     def get_url(self, path):
         netloc = self._host
         if self._port is not None and self._port != TCP_GIT_PORT:
-            netloc += ":%d" % self._port
+            netloc += f":{self._port}"
         return urlunsplit(("git", netloc, path, "", ""))
 
     def _connect(
@@ -2142,7 +2140,7 @@ class SSHGitClient(TraditionalGitClient):
     def get_url(self, path):
         netloc = self.host
         if self.port is not None:
-            netloc += ":%d" % self.port
+            netloc += f":{self.port}"
 
         if self.username is not None:
             netloc = urlquote(self.username, "@/:") + "@" + netloc
@@ -2414,7 +2412,7 @@ class AbstractHttpGitClient(GitClient):
             protocol_version is not None
             and protocol_version not in GIT_PROTOCOL_VERSIONS
         ):
-            raise ValueError("unknown Git protocol version %d" % protocol_version)
+            raise ValueError(f"unknown Git protocol version {protocol_version}")
         assert base_url[-1] == "/"
         tail = "info/refs"
         headers = {"Accept": "*/*"}
@@ -2478,13 +2476,11 @@ class AbstractHttpGitClient(GitClient):
                 server_protocol_version = negotiate_protocol_version(proto)
                 if server_protocol_version not in GIT_PROTOCOL_VERSIONS:
                     raise ValueError(
-                        "unknown Git protocol version %d used by server"
-                        % server_protocol_version
+                        f"unknown Git protocol version {server_protocol_version} used by server"
                     )
                 if protocol_version and server_protocol_version > protocol_version:
                     raise ValueError(
-                        "bad Git protocol version %d used by server"
-                        % server_protocol_version
+                        f"bad Git protocol version {server_protocol_version} used by server"
                     )
                 self.protocol_version = server_protocol_version
                 if self.protocol_version == 2:
@@ -2508,13 +2504,11 @@ class AbstractHttpGitClient(GitClient):
                     server_protocol_version = negotiate_protocol_version(proto)
                     if server_protocol_version not in GIT_PROTOCOL_VERSIONS:
                         raise ValueError(
-                            "unknown Git protocol version %d used by server"
-                            % server_protocol_version
+                            f"unknown Git protocol version {server_protocol_version} used by server"
                         )
                     if protocol_version and server_protocol_version > protocol_version:
                         raise ValueError(
-                            "bad Git protocol version %d used by server"
-                            % server_protocol_version
+                            f"bad Git protocol version {server_protocol_version} used by server"
                         )
                     self.protocol_version = server_protocol_version
                     if self.protocol_version == 2:
@@ -2853,7 +2847,7 @@ class Urllib3HttpGitClient(AbstractHttpGitClient):
             raise HTTPProxyUnauthorized(resp.headers.get("Proxy-Authenticate"), url)
         if resp.status != 200:
             raise GitProtocolError(
-                "unexpected http resp %d for %s" % (resp.status, url)
+                f"unexpected http resp {resp.status} for {url}"
             )
 
         resp.content_type = resp.headers.get("Content-Type")

+ 2 - 3
dulwich/config.py

@@ -393,12 +393,11 @@ def _parse_string(value: bytes) -> bytes:
                 v = _ESCAPE_TABLE[value[i]]
             except IndexError as exc:
                 raise ValueError(
-                    "escape character in %r at %d before end of string" % (value, i)
+                    f"escape character in {value!r} at {i} before end of string"
                 ) from exc
             except KeyError as exc:
                 raise ValueError(
-                    "escape character followed by unknown character "
-                    "%s at %d in %r" % (value[i], i, value)
+                    f"escape character followed by unknown character {value[i]!r} at {i} in {value!r}"
                 ) from exc
             if whitespace:
                 ret.extend(whitespace)

+ 1 - 1
dulwich/contrib/requests_vendor.py

@@ -81,7 +81,7 @@ class RequestsHttpGitClient(AbstractHttpGitClient):
             raise HTTPProxyUnauthorized(resp.headers.get("Proxy-Authenticate"), url)
         if resp.status_code != 200:
             raise GitProtocolError(
-                "unexpected http resp %d for %s" % (resp.status_code, url)
+                f"unexpected http resp {resp.status_code} for {url}"
             )
 
         # Add required fields as stated in AbstractHttpGitClient._http_request

+ 1 - 1
dulwich/contrib/swift.py

@@ -112,7 +112,7 @@ class PackInfoMissingObjectFinder(GreenThreadsMissingObjectFinder):
             if sha in self._tagged:
                 self.add_todo([(self._tagged[sha], None, True)])
         self.sha_done.add(sha)
-        self.progress("counting objects: %d\r" % len(self.sha_done))
+        self.progress(f"counting objects: {len(self.sha_done)}\r")
         return (sha, name)
 
 

+ 5 - 5
dulwich/diff_tree.py

@@ -139,8 +139,8 @@ def walk_trees(store, tree1_id, tree2_id, prune_identical=False):
     """
     # This could be fairly easily generalized to >2 trees if we find a use
     # case.
-    mode1 = tree1_id and stat.S_IFDIR or None
-    mode2 = tree2_id and stat.S_IFDIR or None
+    mode1 = (tree1_id and stat.S_IFDIR) or None
+    mode2 = (tree2_id and stat.S_IFDIR) or None
     todo = [(TreeEntry(b"", mode1, tree1_id), TreeEntry(b"", mode2, tree2_id))]
     while todo:
         entry1, entry2 = todo.pop()
@@ -149,8 +149,8 @@ def walk_trees(store, tree1_id, tree2_id, prune_identical=False):
         if prune_identical and is_tree1 and is_tree2 and entry1 == entry2:
             continue
 
-        tree1 = is_tree1 and store[entry1.sha] or None
-        tree2 = is_tree2 and store[entry2.sha] or None
+        tree1 = (is_tree1 and store[entry1.sha]) or None
+        tree2 = (is_tree2 and store[entry2.sha]) or None
         path = entry1.path or entry2.path
         todo.extend(reversed(_merge_entries(path, tree1, tree2)))
         yield entry1, entry2
@@ -520,7 +520,7 @@ class RenameDetector:
                 if is_delete:
                     delete_paths.add(old.path)
                 add_paths.add(new.path)
-                new_type = is_delete and CHANGE_RENAME or CHANGE_COPY
+                new_type = (is_delete and CHANGE_RENAME) or CHANGE_COPY
                 self._changes.append(TreeChange(new_type, old, new))
 
             num_extra_adds = len(sha_adds) - len(sha_deletes)

+ 1 - 1
dulwich/fastexport.py

@@ -51,7 +51,7 @@ class GitFastExporter:
 
     def _allocate_marker(self):
         self._marker_idx += 1
-        return ("%d" % (self._marker_idx,)).encode("ascii")
+        return str(self._marker_idx).encode("ascii")
 
     def _export_blob(self, blob):
         marker = self._allocate_marker()

+ 1 - 1
dulwich/greenthreads.py

@@ -117,4 +117,4 @@ class GreenThreadsMissingObjectFinder(MissingObjectFinder):
             self.progress = lambda x: None
         else:
             self.progress = progress
-        self._tagged = get_tagged and get_tagged() or {}
+        self._tagged = (get_tagged and get_tagged()) or {}

+ 2 - 4
dulwich/hooks.py

@@ -89,9 +89,7 @@ class ShellHook(Hook):
         """Execute the hook with given args."""
         if len(args) != self.numparam:
             raise HookError(
-                "Hook %s executed with wrong number of args. \
-                            Expected %d. Saw %d. args: %s"
-                % (self.name, self.numparam, len(args), args)
+                f"Hook {self.name} executed with wrong number of args. Expected {self.numparam}. Saw {len(args)}. args: {args}"
             )
 
         if self.pre_exec_callback is not None:
@@ -105,7 +103,7 @@ class ShellHook(Hook):
                 if self.post_exec_callback is not None:
                     self.post_exec_callback(0, *args)
                 raise HookError(
-                    "Hook %s exited with non-zero status %d" % (self.name, ret)
+                    f"Hook {self.name} exited with non-zero status {ret}"
                 )
             if self.post_exec_callback is not None:
                 return self.post_exec_callback(1, *args)

+ 1 - 1
dulwich/lru_cache.py

@@ -35,7 +35,7 @@ V = TypeVar("V")
 class _LRUNode(Generic[K, V]):
     """This maintains the linked-list which is the lru internals."""
 
-    __slots__ = ("prev", "next_key", "key", "value", "cleanup", "size")
+    __slots__ = ("cleanup", "key", "next_key", "prev", "size", "value")
 
     prev: Optional["_LRUNode[K, V]"]
     next_key: K

+ 4 - 4
dulwich/object_store.py

@@ -898,7 +898,7 @@ class DiskObjectStore(PackBasedObjectStore):
         for i, entry in enumerate(indexer):
             if progress is not None:
                 progress(
-                    ("generating index: %d/%d\r" % (i, num_objects)).encode("ascii")
+                    f"generating index: {i}/{num_objects}\r".encode("ascii")
                 )
             entries.append(entry)
 
@@ -1366,7 +1366,7 @@ class MissingObjectFinder:
             self.progress = lambda x: None
         else:
             self.progress = progress
-        self._tagged = get_tagged and get_tagged() or {}
+        self._tagged = (get_tagged and get_tagged()) or {}
 
     def get_remote_has(self):
         return self.remote_has
@@ -1380,7 +1380,7 @@ class MissingObjectFinder:
         while True:
             if not self.objects_to_send:
                 self.progress(
-                    ("counting objects: %d, done.\n" % len(self.sha_done)).encode(
+                    f"counting objects: {len(self.sha_done)}, done.\n".encode(
                         "ascii"
                     )
                 )
@@ -1412,7 +1412,7 @@ class MissingObjectFinder:
         self.sha_done.add(sha)
         if len(self.sha_done) % 1000 == 0:
             self.progress(
-                ("counting objects: %d\r" % len(self.sha_done)).encode("ascii")
+                f"counting objects: {len(self.sha_done)}\r".encode("ascii")
             )
         if type_num is None:
             pack_hint = None

+ 22 - 22
dulwich/objects.py

@@ -162,7 +162,7 @@ def object_header(num_type: int, length: int) -> bytes:
     """Return an object header for the given numeric type and text length."""
     cls = object_class(num_type)
     if cls is None:
-        raise AssertionError("unsupported class type num: %d" % num_type)
+        raise AssertionError(f"unsupported class type num: {num_type}")
     return cls.type_name + b" " + str(length).encode("ascii") + b"\0"
 
 
@@ -273,7 +273,7 @@ class FixedSha:
 class ShaFile:
     """A git SHA file."""
 
-    __slots__ = ("_chunked_text", "_sha", "_needs_serialization")
+    __slots__ = ("_chunked_text", "_needs_serialization", "_sha")
 
     _needs_serialization: bool
     type_name: bytes
@@ -387,7 +387,7 @@ class ShaFile:
         num_type = (ord(magic[0:1]) >> 4) & 7
         obj_class = object_class(num_type)
         if not obj_class:
-            raise ObjectFormatException("Not a known type %d" % num_type)
+            raise ObjectFormatException(f"Not a known type {num_type}")
         return obj_class()
 
     def _parse_object(self, map) -> None:
@@ -464,7 +464,7 @@ class ShaFile:
         """
         cls = object_class(type_num)
         if cls is None:
-            raise AssertionError("unsupported class type num: %d" % type_num)
+            raise AssertionError(f"unsupported class type num: {type_num}")
         obj = cls()
         obj.set_raw_string(string, sha)
         return obj
@@ -482,7 +482,7 @@ class ShaFile:
         """
         cls = object_class(type_num)
         if cls is None:
-            raise AssertionError("unsupported class type num: %d" % type_num)
+            raise AssertionError(f"unsupported class type num: {type_num}")
         obj = cls()
         obj.set_raw_chunks(chunks, sha)
         return obj
@@ -551,7 +551,7 @@ class ShaFile:
         """Create a new copy of this SHA1 object from its raw string."""
         obj_class = object_class(self.type_num)
         if obj_class is None:
-            raise AssertionError("invalid type num %d" % self.type_num)
+            raise AssertionError(f"invalid type num {self.type_num}")
         return obj_class.from_raw_string(self.type_num, self.as_raw_string(), self.id)
 
     @property
@@ -743,15 +743,15 @@ class Tag(ShaFile):
     type_num = 4
 
     __slots__ = (
-        "_tag_timezone_neg_utc",
+        "_message",
         "_name",
-        "_object_sha",
         "_object_class",
+        "_object_sha",
+        "_signature",
         "_tag_time",
         "_tag_timezone",
+        "_tag_timezone_neg_utc",
         "_tagger",
-        "_message",
-        "_signature",
     )
 
     _tagger: Optional[bytes]
@@ -1260,7 +1260,7 @@ def parse_timezone(text):
     if sign == b"-":
         offset = -offset
     unnecessary_negative_timezone = offset >= 0 and sign == b"-"
-    signum = (offset < 0) and -1 or 1
+    signum = ((offset < 0) and -1) or 1
     offset = abs(offset)
     hours = int(offset / 100)
     minutes = offset % 100
@@ -1285,7 +1285,7 @@ def format_timezone(offset, unnecessary_negative_timezone=False):
         offset = -offset
     else:
         sign = "+"
-    return ("%c%02d%02d" % (sign, offset / 3600, (offset / 60) % 60)).encode("ascii")
+    return ("%c%02d%02d" % (sign, offset / 3600, (offset / 60) % 60)).encode("ascii")  # noqa: UP031
 
 
 def parse_time_entry(value):
@@ -1380,21 +1380,21 @@ class Commit(ShaFile):
     type_num = 1
 
     __slots__ = (
-        "_parents",
-        "_encoding",
-        "_extra",
-        "_author_timezone_neg_utc",
-        "_commit_timezone_neg_utc",
-        "_commit_time",
+        "_author",
         "_author_time",
         "_author_timezone",
+        "_author_timezone_neg_utc",
+        "_commit_time",
         "_commit_timezone",
-        "_author",
+        "_commit_timezone_neg_utc",
         "_committer",
-        "_tree",
-        "_message",
-        "_mergetag",
+        "_encoding",
+        "_extra",
         "_gpgsig",
+        "_mergetag",
+        "_message",
+        "_parents",
+        "_tree",
     )
 
     def __init__(self) -> None:

+ 21 - 29
dulwich/pack.py

@@ -190,16 +190,16 @@ class UnpackedObject:
     """
 
     __slots__ = [
-        "offset",  # Offset in its pack.
         "_sha",  # Cached binary SHA.
-        "obj_type_num",  # Type of this object.
-        "obj_chunks",  # Decompressed and delta-resolved chunks.
-        "pack_type_num",  # Type of this object in the pack (may be a delta).
-        "delta_base",  # Delta base offset or SHA.
         "comp_chunks",  # Compressed object chunks.
+        "crc32",  # CRC32.
         "decomp_chunks",  # Decompressed object chunks.
         "decomp_len",  # Decompressed length of this object.
-        "crc32",  # CRC32.
+        "delta_base",  # Delta base offset or SHA.
+        "obj_chunks",  # Decompressed and delta-resolved chunks.
+        "obj_type_num",  # Type of this object.
+        "offset",  # Offset in its pack.
+        "pack_type_num",  # Type of this object in the pack (may be a delta).
     ]
 
     obj_type_num: Optional[int]
@@ -409,7 +409,7 @@ def load_pack_index_file(path, f):
         if version == 2:
             return PackIndex2(path, file=f, contents=contents, size=size)
         else:
-            raise KeyError("Unknown pack index format %d" % version)
+            raise KeyError(f"Unknown pack index format {version}")
     else:
         return PackIndex1(path, file=f, contents=contents, size=size)
 
@@ -797,7 +797,7 @@ class PackIndex2(FilePackIndex):
             raise AssertionError("Not a v2 pack index file")
         (self.version,) = unpack_from(b">L", self._contents, 4)
         if self.version != 2:
-            raise AssertionError("Version was %d" % self.version)
+            raise AssertionError(f"Version was {self.version}")
         self._fan_out_table = self._read_fan_out_table(8)
         self._name_table_offset = 8 + 0x100 * 4
         self._crc32_table_offset = self._name_table_offset + 20 * len(self)
@@ -844,7 +844,7 @@ def read_pack_header(read) -> tuple[int, int]:
         raise AssertionError(f"Invalid pack header {header!r}")
     (version,) = unpack_from(b">L", header, 4)
     if version not in (2, 3):
-        raise AssertionError("Version was %d" % version)
+        raise AssertionError(f"Version was {version}")
     (num_objects,) = unpack_from(b">L", header, 8)
     return (version, num_objects)
 
@@ -1122,10 +1122,10 @@ class PackStreamCopier(PackStreamReader):
                 self._delta_iter.record(unpacked)
             if progress is not None:
                 progress(
-                    ("copying pack entries: %d/%d\r" % (i, len(self))).encode("ascii")
+                    f"copying pack entries: {i}/{len(self)}\r".encode("ascii")
                 )
         if progress is not None:
-            progress(("copied %d pack entries\n" % i).encode("ascii"))
+            progress(f"copied {i} pack entries\n".encode("ascii"))
 
 
 def obj_sha(type, chunks):
@@ -1156,8 +1156,7 @@ def compute_file_sha(f, start_ofs=0, end_ofs=0, buffer_size=1 << 16):
     length = f.tell()
     if (end_ofs < 0 and length + end_ofs < start_ofs) or end_ofs > length:
         raise AssertionError(
-            "Attempt to read beyond file length. "
-            "start_ofs: %d, end_ofs: %d, file length: %d" % (start_ofs, end_ofs, length)
+            f"Attempt to read beyond file length. start_ofs: {start_ofs}, end_ofs: {end_ofs}, file length: {length}"
         )
     todo = length + end_ofs - start_ofs
     f.seek(start_ofs)
@@ -1251,11 +1250,7 @@ class PackData:
             return self._size
         self._size = os.path.getsize(self._filename)
         if self._size < self._header_size:
-            errmsg = "%s is too small for a packfile (%d < %d)" % (
-                self._filename,
-                self._size,
-                self._header_size,
-            )
+            errmsg = f"{self._filename} is too small for a packfile ({self._size} < {self._header_size})"
             raise AssertionError(errmsg)
         return self._size
 
@@ -1364,7 +1359,7 @@ class PackData:
                 filename, progress, resolve_ext_ref=resolve_ext_ref
             )
         else:
-            raise ValueError("unknown index format %d" % version)
+            raise ValueError(f"unknown index format {version}")
 
     def get_stored_checksum(self):
         """Return the expected checksum stored in this pack."""
@@ -1797,9 +1792,7 @@ def find_reusable_deltas(
     ):
         if progress is not None and i % 1000 == 0:
             progress(
-                ("checking for reusable deltas: %d/%d\r" % (i, len(object_ids))).encode(
-                    "utf-8"
-                )
+                f"checking for reusable deltas: {i}/{len(object_ids)}\r".encode()
             )
         if unpacked.pack_type_num == REF_DELTA:
             hexsha = sha_to_hex(unpacked.delta_base)
@@ -1807,7 +1800,7 @@ def find_reusable_deltas(
                 yield unpacked
                 reused += 1
     if progress is not None:
-        progress(("found %d deltas to reuse\n" % (reused,)).encode("utf-8"))
+        progress((f"found {reused} deltas to reuse\n").encode())
 
 
 def deltify_pack_objects(
@@ -1870,7 +1863,7 @@ def deltas_from_sorted_objects(
     possible_bases: deque[tuple[bytes, int, list[bytes]]] = deque()
     for i, o in enumerate(objects):
         if progress is not None and i % 1000 == 0:
-            progress(("generating deltas: %d\r" % (i,)).encode("utf-8"))
+            progress((f"generating deltas: {i}\r").encode())
         raw = o.as_raw_chunks()
         winner = raw
         winner_len = sum(map(len, winner))
@@ -2118,7 +2111,7 @@ class PackChunkGenerator:
             type_num = unpacked.pack_type_num
             if progress is not None and i % 1000 == 0:
                 progress(
-                    ("writing pack data: %d/%d\r" % (i, num_records)).encode("ascii")
+                    (f"writing pack data: {i}/{num_records}\r").encode("ascii")
                 )
             raw: Union[list[bytes], tuple[int, list[bytes]], tuple[bytes, list[bytes]]]
             if unpacked.delta_base is not None:
@@ -2151,8 +2144,7 @@ class PackChunkGenerator:
             offset += object_size
         if actual_num_records != num_records:
             raise AssertionError(
-                "actual records written differs: %d != %d"
-                % (actual_num_records, num_records)
+                f"actual records written differs: {actual_num_records} != {num_records}"
             )
 
         yield self.cs.digest()
@@ -2320,7 +2312,7 @@ def apply_delta(src_buf, delta):
 
     src_size, index = get_delta_header_size(delta, index)
     dest_size, index = get_delta_header_size(delta, index)
-    assert src_size == len(src_buf), "%d vs %d" % (src_size, len(src_buf))
+    assert src_size == len(src_buf), f"{src_size} vs {len(src_buf)}"
     while index < delta_length:
         cmd = ord(delta[index : index + 1])
         index += 1
@@ -2771,7 +2763,7 @@ def extend_pack(
     for i, object_id in enumerate(object_ids):
         if progress is not None:
             progress(
-                ("writing extra base objects: %d/%d\r" % (i, len(object_ids))).encode(
+                (f"writing extra base objects: {i}/{len(object_ids)}\r").encode(
                     "ascii"
                 )
             )

+ 1 - 1
dulwich/patch.py

@@ -64,7 +64,7 @@ def write_commit_patch(
         b"Date: " + time.strftime("%a, %d %b %Y %H:%M:%S %Z").encode(encoding) + b"\n"
     )
     f.write(
-        ("Subject: [PATCH %d/%d] " % (num, total)).encode(encoding)
+        (f"Subject: [PATCH {num}/{total}] ").encode(encoding)
         + commit.message
         + b"\n"
     )

+ 1 - 1
dulwich/porcelain.py

@@ -877,7 +877,7 @@ def print_name_status(changes):
                 kind = "R"
             elif change.type == CHANGE_COPY:
                 kind = "C"
-        yield "%-8s%-20s%-20s" % (kind, path1, path2)
+        yield "%-8s%-20s%-20s" % (kind, path1, path2)  # noqa: UP031
 
 
 def log(

+ 1 - 1
dulwich/protocol.py

@@ -441,7 +441,7 @@ class ReceivableProtocol(Protocol):
                 buf.write(data)
                 del data  # explicit free
                 break
-            assert n <= left, "_recv(%d) returned %d bytes" % (left, n)
+            assert n <= left, f"_recv({left}) returned {n} bytes"
             buf.write(data)
             buf_len += n
             del data  # explicit free

+ 1 - 1
dulwich/reflog.py

@@ -101,7 +101,7 @@ def drop_reflog_entry(f, index, rewrite=False) -> None:
             old SHA to the new SHA of the entry that now precedes it
     """
     if index < 0:
-        raise ValueError("Invalid reflog index %d" % index)
+        raise ValueError(f"Invalid reflog index {index}")
 
     log = []
     offset = f.tell()

+ 1 - 1
dulwich/server.py

@@ -408,7 +408,7 @@ class UploadPackHandler(PackHandler):
 
         self._start_pack_send_phase()
         self.progress(
-            ("counting objects: %d, done.\n" % len(object_ids)).encode("ascii")
+            (f"counting objects: {len(object_ids)}, done.\n").encode("ascii")
         )
 
         write_pack_from_container(

+ 2 - 2
dulwich/tests/utils.py

@@ -319,7 +319,7 @@ def build_commit_graph(object_store, commit_spec, trees=None, attrs=None):
             parent_ids = [nums[pn] for pn in commit[1:]]
         except KeyError as exc:
             (missing_parent,) = exc.args
-            raise ValueError("Unknown parent %i" % missing_parent) from exc
+            raise ValueError(f"Unknown parent {missing_parent}") from exc
 
         blobs = []
         for entry in trees.get(commit_num, []):
@@ -332,7 +332,7 @@ def build_commit_graph(object_store, commit_spec, trees=None, attrs=None):
         tree_id = commit_tree(object_store, blobs)
 
         commit_attrs = {
-            "message": ("Commit %i" % commit_num).encode("ascii"),
+            "message": (f"Commit {commit_num}").encode("ascii"),
             "parents": parent_ids,
             "tree": tree_id,
             "commit_time": commit_time,

+ 1 - 1
dulwich/walk.py

@@ -287,7 +287,7 @@ class Walker:
         self.order = order
         self.reverse = reverse
         self.max_entries = max_entries
-        self.paths = paths and set(paths) or None
+        self.paths = (paths and set(paths)) or None
         if follow and not rename_detector:
             rename_detector = RenameDetector(store)
         self.rename_detector = rename_detector

+ 1 - 1
dulwich/web.py

@@ -102,7 +102,7 @@ def date_time_string(timestamp: Optional[float] = None) -> str:
     if timestamp is None:
         timestamp = time.time()
     year, month, day, hh, mm, ss, wd = time.gmtime(timestamp)[:7]
-    return "%s, %02d %3s %4d %02d:%02d:%02d GMD" % (
+    return "%s, %02d %3s %4d %02d:%02d:%02d GMD" % (  # noqa: UP031
         weekdays[wd],
         day,
         months[month],

+ 0 - 2
pyproject.toml

@@ -85,8 +85,6 @@ ignore = [
     "ANN001",
     "ANN002",
     "ANN003",
-    "ANN101",  # missing-type-self
-    "ANN102",
     "ANN201",
     "ANN202",
     "ANN204",

+ 2 - 2
tests/__init__.py

@@ -22,11 +22,11 @@
 """Tests for Dulwich."""
 
 __all__ = [
+    "BlackboxTestCase",
     "SkipTest",
     "TestCase",
-    "BlackboxTestCase",
-    "skipIf",
     "expectedFailure",
+    "skipIf",
 ]
 
 import doctest

+ 3 - 3
tests/compat/test_pack.py

@@ -90,7 +90,7 @@ class TestPack(PackTests):
         self.assertEqual(
             3,
             got_non_delta,
-            "Expected 3 non-delta objects, got %d" % got_non_delta,
+            f"Expected 3 non-delta objects, got {got_non_delta}",
         )
 
     def test_delta_medium_object(self) -> None:
@@ -121,7 +121,7 @@ class TestPack(PackTests):
         self.assertEqual(
             3,
             got_non_delta,
-            "Expected 3 non-delta objects, got %d" % got_non_delta,
+            f"Expected 3 non-delta objects, got {got_non_delta}",
         )
         # We expect one object to have a delta chain length of two
         # (new_blob_2), so let's verify that actually happens:
@@ -161,5 +161,5 @@ class TestPack(PackTests):
         self.assertEqual(
             4,
             got_non_delta,
-            "Expected 4 non-delta objects, got %d" % got_non_delta,
+            f"Expected 4 non-delta objects, got {got_non_delta}",
         )

+ 2 - 4
tests/compat/utils.py

@@ -93,8 +93,7 @@ def require_git_version(required_version, git_path=_DEFAULT_GIT) -> None:
 
     if len(required_version) > _VERSION_LEN:
         raise ValueError(
-            "Invalid version tuple %s, expected %i parts"
-            % (required_version, _VERSION_LEN)
+            f"Invalid version tuple {required_version}, expected {_VERSION_LEN} parts"
         )
 
     required_version = list(required_version)
@@ -170,8 +169,7 @@ def run_git_or_fail(args, git_path=_DEFAULT_GIT, input=None, **popen_kwargs):
     )
     if returncode != 0:
         raise AssertionError(
-            "git with args %r failed with %d: stdout=%r stderr=%r"
-            % (args, returncode, stdout, stderr)
+            f"git with args {args!r} failed with {returncode}: stdout={stdout!r} stderr={stderr!r}"
         )
     return stdout
 

+ 1 - 1
tests/test_client.py

@@ -103,7 +103,7 @@ class GitClientTests(TestCase):
         self.client = DummyClient(lambda x: True, self.rin.read, self.rout.write)
 
     def test_caps(self) -> None:
-        agent_cap = ("agent=dulwich/%d.%d.%d" % dulwich.__version__).encode("ascii")
+        agent_cap = "agent=dulwich/{}.{}.{}".format(*dulwich.__version__).encode("ascii")
         self.assertEqual(
             {
                 b"multi_ack",

+ 1 - 1
tests/test_greenthreads.py

@@ -58,7 +58,7 @@ def create_commit(marker=None):
 def init_store(store, count=1):
     ret = []
     for i in range(count):
-        objs = create_commit(marker=("%d" % i).encode("ascii"))
+        objs = create_commit(marker=str(i).encode("ascii"))
         for obj in objs:
             ret.append(obj)
             store.add_object(obj)

+ 3 - 3
tests/test_pack.py

@@ -1002,7 +1002,7 @@ class TestPackIterator(DeltaChainIterator):
 
     def _resolve_object(self, offset, pack_type_num, base_chunks):
         assert offset not in self._unpacked_offsets, (
-            "Attempted to re-inflate offset %i" % offset
+            f"Attempted to re-inflate offset {offset}"
         )
         self._unpacked_offsets.add(offset)
         return super()._resolve_object(offset, pack_type_num, base_chunks)
@@ -1034,14 +1034,14 @@ class DeltaChainIteratorTests(TestCase):
     def make_pack_iter(self, f, thin=None):
         if thin is None:
             thin = bool(list(self.store))
-        resolve_ext_ref = thin and self.get_raw_no_repeat or None
+        resolve_ext_ref = (thin and self.get_raw_no_repeat) or None
         data = PackData("test.pack", file=f)
         return TestPackIterator.for_pack_data(data, resolve_ext_ref=resolve_ext_ref)
 
     def make_pack_iter_subset(self, f, subset, thin=None):
         if thin is None:
             thin = bool(list(self.store))
-        resolve_ext_ref = thin and self.get_raw_no_repeat or None
+        resolve_ext_ref = (thin and self.get_raw_no_repeat) or None
         data = PackData("test.pack", file=f)
         assert data
         index = MemoryPackIndex.for_pack(data)